Skip to content

Instantly share code, notes, and snippets.

@SheffieldKevin
Last active July 1, 2022 06:43
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SheffieldKevin/9873485 to your computer and use it in GitHub Desktop.
Save SheffieldKevin/9873485 to your computer and use it in GitHub Desktop.
Code to demonstrate that the backside image option for the CIPageCurlTransition filter doesn't work.
// main.m
// pagecurlbacksidetest
//
// Created by Kevin Meaney on 30/03/2014.
@import Foundation;
@import QuartzCore;
size_t const kWidth = 600;
size_t const kHeight = 400;
size_t const kBitsPerComponent = 8;
size_t const kBytesPerPixel = 4;
CGRect kBoundsRect = { 0.0, 0.0, kWidth, kHeight };
CGRect innerRect = { kWidth / 4.0, kHeight / 4.0, kWidth / 2.0, kHeight / 2.0 };
CGPoint trianglePoint1 = { 100, 350 };
CGPoint trianglePoint2 = { 300, 50 };
CGPoint trianglePoint3 = { 500, 350 };
CGBitmapInfo const bitmapInfo = (CGBitmapInfo)kCGImageAlphaPremultipliedFirst;
CGContextRef CreateMyContext()
{
CGColorSpaceRef colorSpace;
colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
CGContextRef context = CGBitmapContextCreate(NULL, kWidth, kHeight,
kBitsPerComponent,
kWidth * kBytesPerPixel,
colorSpace,
bitmapInfo);
CGColorSpaceRelease(colorSpace);
return context;
}
CGImageRef DrawFillOvalAndCreateImage(CGContextRef context)
{
// Draw red oval on a blue background.
CGColorRef redColor = CGColorCreateGenericRGB(1.0, 0.0, 0.0, 1.0);
CGColorRef blueColor = CGColorCreateGenericRGB(0.0, 0.0, 1.0, 1.0);
CGContextSetFillColorWithColor(context, blueColor);
CGContextFillRect(context, kBoundsRect);
CGContextSetFillColorWithColor(context, redColor);
CGContextFillEllipseInRect(context, innerRect);
CGColorRelease(redColor);
CGColorRelease(blueColor);
CGImageRef image = CGBitmapContextCreateImage(context);
return image;
}
CGImageRef DrawFillRectAndCreateImage(CGContextRef context)
{
// Draw green oval on a red background.
CGColorRef redColor = CGColorCreateGenericRGB(1.0, 0.0, 0.0, 1.0);
CGColorRef greenColor = CGColorCreateGenericRGB(0.0, 1.0, 0.0, 1.0);
CGContextSetFillColorWithColor(context, redColor);
CGContextFillRect(context, kBoundsRect);
CGContextSetFillColorWithColor(context, greenColor);
CGContextFillRect(context, innerRect);
CGColorRelease(redColor);
CGColorRelease(greenColor);
CGImageRef image = CGBitmapContextCreateImage(context);
return image;
}
CGImageRef DrawFillTriangleAndCreateImage(CGContextRef context)
{
// Draw blue triangle on a green bacgkround.
CGColorRef blueColor = CGColorCreateGenericRGB(1.0, 0.0, 0.0, 1.0);
CGColorRef greenColor = CGColorCreateGenericRGB(0.0, 1.0, 0.0, 1.0);
CGContextSetFillColorWithColor(context, greenColor);
CGContextFillRect(context, kBoundsRect);
CGContextSetFillColorWithColor(context, blueColor);
CGContextBeginPath(context);
CGContextMoveToPoint(context, trianglePoint1.x, trianglePoint1.y);
CGContextAddLineToPoint(context, trianglePoint2.x, trianglePoint2.y);
CGContextAddLineToPoint(context, trianglePoint3.x, trianglePoint3.y);
CGContextClosePath(context);
CGContextFillPath(context);
CGColorRelease(blueColor);
CGColorRelease(greenColor);
CGImageRef image = CGBitmapContextCreateImage(context);
return image;
}
void SaveCGImageToAPNGFile(CGImageRef theImage, NSString *path)
{
NSString *expandedPath = [path stringByExpandingTildeInPath];
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:expandedPath];
CGImageDestinationRef exporter = CGImageDestinationCreateWithURL(
(__bridge CFURLRef)fileURL,
kUTTypePNG, 1, NULL);
CGImageDestinationAddImage(exporter, theImage, nil);
CGImageDestinationFinalize(exporter);
CFRelease(exporter);
}
void SaveCGBitmapContextToAPNGFile(CGContextRef context, NSString *path)
{
CGImageRef image = CGBitmapContextCreateImage(context);
SaveCGImageToAPNGFile(image, path);
CGImageRelease(image);
}
int main(int argc, const char * argv[])
{
if (argc < 2)
{
printf("Please provide a path to where you want to save public.png image.");
return 1;
}
@autoreleasepool
{
// Create the context and the images.
CGContextRef myContext = CreateMyContext();
CGImageRef sourceImage = DrawFillOvalAndCreateImage(myContext);
CGImageRef destinationImage = DrawFillRectAndCreateImage(myContext);
CGImageRef backsideImage = DrawFillTriangleAndCreateImage(myContext);
// Set up the radial gradient and crop filters for the inputShadingImage
CGFloat diam = 300.0;
CGFloat radius = diam * 0.5;
CIFilter *radialGradientFilter = [CIFilter filterWithName:@"CIRadialGradient"];
[radialGradientFilter setDefaults];
CIVector *centerVector = [CIVector vectorWithX:radius Y:radius];
[radialGradientFilter setValue:centerVector forKey:@"inputCenter"];
// inner circle is 4% of the size of the outer one.
[radialGradientFilter setValue:@(radius * 0.04) forKey:@"inputRadius0"];
[radialGradientFilter setValue:@(radius) forKey:@"inputRadius1"];
CIColor *color0 = [CIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.3];
[radialGradientFilter setValue:color0 forKey:@"inputColor0"];
CIColor *color1 = [CIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.7];
[radialGradientFilter setValue:color1 forKey:@"inputColor1"];
CIFilter *cropFilter = [CIFilter filterWithName:@"CICrop"];
[cropFilter setDefaults];
CIVector *extentVector;
extentVector = [CIVector vectorWithX:0.0 Y:0.0 Z:diam W:diam];
[cropFilter setValue:extentVector forKey:@"inputRectangle"];
[cropFilter setValue:[radialGradientFilter valueForKeyPath:@"outputImage"]
forKey:@"inputImage"];
// OK, the radial gradient fill and crop filters have been setup so that
// we have generated a shading input image for the CIPageCurlTransition
// filter.
CIFilter *pageCurlFilter = [CIFilter filterWithName:@"CIPageCurlTransition"];
[pageCurlFilter setDefaults];
[pageCurlFilter setValue:@(0.5) forKey:@"inputTime"];
CIImage *inputImage = [CIImage imageWithCGImage:sourceImage];
[pageCurlFilter setValue:inputImage forKey:@"inputImage"];
CIImage *inputTargetImage = [CIImage imageWithCGImage:destinationImage];
[pageCurlFilter setValue:inputTargetImage forKey:@"inputTargetImage"];
CIImage *inputBacksideImage = [CIImage imageWithCGImage:backsideImage];
[pageCurlFilter setValue:inputBacksideImage forKey:@"inputBacksideImage"];
CIImage *inputShadingImage = [cropFilter valueForKeyPath:@"outputImage"];
[pageCurlFilter setValue:inputShadingImage forKey:@"inputShadingImage"];
// [pageCurlFilter setValue:inputShadingImage forKey:@"inputBacksideImage"];
CIVector *fullExtentVector;
fullExtentVector = [CIVector vectorWithX:0.0 Y:0.0 Z:kWidth W:kHeight];
[pageCurlFilter setValue:fullExtentVector forKey:@"inputExtent"];
[pageCurlFilter setValue:@(-2.7) forKey:@"inputAngle"];
[pageCurlFilter setValue:@(120) forKey:@"inputRadius"];
// So the page Filter has been setup. Now we want to create a CIContext
// and draw the output CIImage from the pageCurlFilter using the CIContext
// into myContext and CGContextRef context.
CIContext *ciContext = [CIContext contextWithCGContext:myContext options:nil];
[ciContext drawImage:[pageCurlFilter valueForKey:@"outputImage"]
inRect:kBoundsRect
fromRect:kBoundsRect];
// Now need to save the image to disk.
const char * filePath = argv[1];
SaveCGBitmapContextToAPNGFile(myContext, @(filePath));
CGContextRelease(myContext);
CGImageRelease(sourceImage);
CGImageRelease(destinationImage);
CGImageRelease(backsideImage);
}
return 0;
}
@SheffieldKevin
Copy link
Author

The problem is that the inputBacksideImage value option for the CIPageCurlTransition filter doesn't appear to work.

@gangster-puppy
Copy link

true

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment