Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sprout a Lens module #5

Closed
wants to merge 3 commits into from
Closed

Conversation

zspencer
Copy link
Member

@zspencer zspencer commented Sep 7, 2020

See: #4

As we learn how to Swift; we're stepping away from the SwiftUI/etc.
system and focusing more on building a library for doing the filtering.

We'll start with downloading a file from the Internet, saving it, then
running it through a LensStack, and saving a copy at each stage.

This way, we can start to diagnose if/how the filters are working
without futzing about with SwiftUI; which adds a confounding factor when
trying to figure things out.

TODO

  • Review the code and make suggestions about what to change for comprehensibility/safety (@theInternauts)
  • Figure out how to get a CGImage out of an NSImage
  • Save the original as name-original.png
  • Apply a "filter" that is a noop, and save the result as name-noop.png

See: #4

As we learn how to Swift; we're stepping away from the SwiftUI/etc.
system and focusing more on building a library for doing the filtering.

We'll start with downloading a file from the Internet, saving it, then
running it through a LensStack, and saving a copy at each stage.

This way, we can start to diagnose if/how the filters are working
without futzing about with SwiftUI; which adds a confounding factor when
trying to figure things out.
Copy link
Contributor

@theInternauts theInternauts left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: Some of the built in iOS Filters have multiple input params--some of which are images and/or objects not just strings and floats.

@theInternauts theInternauts marked this pull request as draft September 20, 2020 15:25
Copy link
Contributor

@theInternauts theInternauts left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Annnnnd it look like the fine folks at Apple already thought of 90% of this little sub-project: Recipes for Custom Effects

You can create custom effects by using the output of one image filter as the input of another, chaining as many filters together as you’d like. When you create an effect this way that you want to use multiple times, consider subclassing CIFilter to encapsulate the effect as a filter.

@zspencer
Copy link
Member Author

@theInternauts That's cool! I think a Swift Wrapper may still make sense for that functionality. However, it's up to you to decide what path you want to take!

…ilters and added a test filter to the driver code--currently unable to save filtered image
Copy link
Member Author

@zspencer zspencer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking really great! Nice work! I think we're really close to getting something that we can start wiring into the UI!


func apply(image: CIImage) -> CIImage {
let localFilter = CIFilter(name: filter.filterName, parameters: filter.filterData)
localFilter?.setValue(image, forKey: kCIInputImageKey)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great! It feels a little bit like feature envy for the Lens to be pulling this data out of the filter. I wonder if we can apply "Tell, Don't Ask" here and refactor in such a way that the Lens method takes responsibility for handling the failure case for Filters (i.e. the filter raises, returns nil, etc.).

guard let output = filter?.apply(image, fingerprint) else {
  return image
}
return output

This way each filter can encapsulate how it leverages the fingerprint to generate the filter parameters.

For example, a MotionBlur filter looks like it wants two numbers between ??? and 20?, so the MotionBlur filter class would use the Fingerprint to generate two random values. On the other hand, the SepiFilter class would only need to generate a single float value; so it would use the fingerprint to do that. Her'es some pseudocode for those two filters:

class SepiaFilter  {
  func apply(image, fingerprint) {
    intensity = fingerprint.randBetween(0.8,1.0)
    let localFilter = CIFilter(name: "CISepiaTone", parameters: [kCIInputIntensityKey: intensity])
    localFilter?.setValue(image, forKey: kCIInputImageKey)
    return localFilter.?outputImage
  }
}

Once we have 2~3 classes, we may find a way to DRY it up a bit.

let image = CIImage(data: data)!

// found a way to get to CIImage from web resource -- can use this in a refactor later
// let webImage = CIImage(contentsOf: URL(string: aang)!)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lol, of course.

@zspencer zspencer closed this Dec 14, 2020
@theInternauts theInternauts deleted the 4/sprout-lens-namespace branch April 5, 2021 17:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants