diff --git a/docs/_docs/image-modification-block.md b/docs/_docs/image-modification-block.md
index 3a4e1a44db..3ee1fd6747 100755
--- a/docs/_docs/image-modification-block.md
+++ b/docs/_docs/image-modification-block.md
@@ -16,9 +16,9 @@ By assigning an `imageModificationBlock` to your imageNode, you can define a set
_backgroundImageNode.imageModificationBlock = ^(UIImage *image) {
- UIImage *newImage = [image applyBlurWithRadius:30
- tintColor:[UIColor colorWithWhite:0.5 alpha:0.3]
- saturationDeltaFactor:1.8
+ UIImage *newImage = [image applyBlurWithRadius:30
+ tintColor:[UIColor colorWithWhite:0.5 alpha:0.3]
+ saturationDeltaFactor:1.8
maskImage:nil];
return newImage ? newImage : image;
};
@@ -30,8 +30,8 @@ _backgroundImageNode.image = someImage;
backgroundImageNode.imageModificationBlock = { image in
- let newImage = image.applyBlurWithRadius(30, tintColor: UIColor(white: 0.5, alpha: 0.3),
- saturationDeltaFactor: 1.8,
+ let newImage = image.applyBlurWithRadius(30, tintColor: UIColor(white: 0.5, alpha: 0.3),
+ saturationDeltaFactor: 1.8,
maskImage: nil)
return (newImage != nil) ? newImage : image
}
@@ -45,3 +45,102 @@ backgroundImageNode.image = someImage
The image named "someImage" will now be blurred asynchronously before being assigned to the imageNode to be displayed.
+### Adding image effects
+
+The most efficient way to add image effects is by leveraging the `imageModificationBlock` block. If a block is provided it can perform drawing operations on the image during the display phase. As display is happening on a background thread it will not block the main thread.
+
+In the following example we assume we have an avatar node that will be setup in `init` of a supernode and the image of the node should be rounded. We provide the `imageModificationBlock` and in there we call a convenience method that transforms the image passed in into a circular image and return it.
+
+
+
+- (instancetype)init
+{
+// ...
+ _userAvatarImageNode.imageModificationBlock = ^UIImage *(UIImage *image) {
+ CGSize profileImageSize = CGSizeMake(USER_IMAGE_HEIGHT, USER_IMAGE_HEIGHT);
+ return [image makeCircularImageWithSize:profileImageSize];
+ };
+ // ...
+}
+
+
+
+init() {
+ // ...
+ _userAvatarImageNode?.imageModificationBlock = { image in
+ return image.makeCircularImage(size: CGSize(width: USER_IMAGE_HEIGHT, height: USER_IMAGE_HEIGHT))
+ }
+
+
+
+
+The actual drawing code is nicely abstracted away in an UIImage category and looks like the following:
+
+
+
+
+@implementation UIImage (Additions)
+- (UIImage *)makeCircularImageWithSize:(CGSize)size
+{
+ // make a CGRect with the image's size
+ CGRect circleRect = (CGRect) {CGPointZero, size};
+
+ // begin the image context since we're not in a drawRect:
+ UIGraphicsBeginImageContextWithOptions(circleRect.size, NO, 0);
+
+ // create a UIBezierPath circle
+ UIBezierPath *circle = [UIBezierPath bezierPathWithRoundedRect:circleRect cornerRadius:circleRect.size.width/2];
+
+ // clip to the circle
+ [circle addClip];
+
+ // draw the image in the circleRect *AFTER* the context is clipped
+ [self drawInRect:circleRect];
+
+ // get an image from the image context
+ UIImage *roundedImage = UIGraphicsGetImageFromCurrentImageContext();
+
+ // end the image context since we're not in a drawRect:
+ UIGraphicsEndImageContext();
+
+ return roundedImage;
+}
+@end
+
+
+
+extension UIImage {
+
+ func makeCircularImage(size: CGSize) -> UIImage {
+ // make a CGRect with the image's size
+ let circleRect = CGRect(origin: .zero, size: size)
+
+ // begin the image context since we're not in a drawRect:
+ UIGraphicsBeginImageContextWithOptions(circleRect.size, false, 0)
+
+ // create a UIBezierPath circle
+ let circle = UIBezierPath(roundedRect: circleRect, cornerRadius: circleRect.size.width * 0.5)
+
+ // clip to the circle
+ circle.addClip()
+
+ UIColor.white.set()
+ circle.fill()
+
+ // draw the image in the circleRect *AFTER* the context is clipped
+ self.draw(in: circleRect)
+
+ // get an image from the image context
+ let roundedImage = UIGraphicsGetImageFromCurrentImageContext()
+
+ // end the image context since we're not in a drawRect:
+ UIGraphicsEndImageContext()
+
+ return roundedImage ?? self
+ }
+}
+
+
+
+
+The imageModificationBlock is very handy and can be used to add all kind of image effects, such as rounding, adding borders, or other pattern overlays, without extraneous display calls.
diff --git a/docs/_docs/image-node.md b/docs/_docs/image-node.md
index 872393b70c..d7b1057ed7 100755
--- a/docs/_docs/image-node.md
+++ b/docs/_docs/image-node.md
@@ -33,44 +33,13 @@ imageNode.contentMode = .scaleAspectFill
-### Image Modification Block
+### Image transformations and effects
-Many times, operations that would affect the appearance of an image you're displaying are big sources of main thread work. Naturally, you want to move these to a background thread. By assigning an `imageModificationBlock` to your `imageNode`, you can define a set of transformations that need to happen asynchronously to any image that gets set on the `imageNode`.
+Many times, operations that would affect the appearance of an image you're displaying are big sources of main thread work. Naturally, you want to move these to a background thread.
-
-
SwiftObjective-C
+By assigning an `imageModificationBlock` to your `imageNode`, you can define a set of transformations that need to happen asynchronously to any image that gets set on the `imageNode`, including image effects such as rounding, adding borders, or other pattern overlays, without extraneous display calls.
-
-
-_backgroundImageNode.imageModificationBlock = ^(UIImage *image) {
- UIImage *newImage = [image applyBlurWithRadius:30
- tintColor:[UIColor colorWithWhite:0.5 alpha:0.3]
- saturationDeltaFactor:1.8
- maskImage:nil];
- return newImage ? newImage : image;
-};
-
-//some time later...
-
-_backgroundImageNode.image = someImage;
-
-
-
-backgroundImageNode.imageModificationBlock = { image in
- let newImage = image.applyBlurWithRadius(30, tintColor: UIColor(white: 0.5, alpha: 0.3),
- saturationDeltaFactor: 1.8,
- maskImage: nil)
- return (newImage != nil) ? newImage : image
-}
-
-//some time later...
-
-backgroundImageNode.image = someImage
-
-
-
-
-The image named "someImage" will now be blurred asynchronously before being assigned to the `imageNode` to be displayed.
+You can read more about it at Image Modification Blocks.
### Image Cropping
@@ -82,7 +51,7 @@ By default, the expanded image will be centered within the bounds of the view. T
That's messed up. To fix it, you can set the `cropRect` property to move the image over. By default it is set to `CGRectMake(0.5, 0.5, 0.0, 0.0)`.
-The rectangle is specified as a "unit rectangle," using percentages of the source image's width and height. To show the image starting at the left side, you can set the `cropRect`'s `x` value to be `0.0`, meaning the image's origin should start at `{0, 0}` as opposed to the default.
+The rectangle is specified as a "unit rectangle," using percentages of the source image's width and height. To show the image starting at the left side, you can set the `cropRect`'s `x` value to be `0.0`, meaning the image's origin should start at `{0, 0}` as opposed to the default.