Re: [Leopard] CIContext thread safety [was: CGContextDrawShading crash a known problem?]
Re: [Leopard] CIContext thread safety [was: CGContextDrawShading crash a known problem?]
- Subject: Re: [Leopard] CIContext thread safety [was: CGContextDrawShading crash a known problem?]
- From: Pierre Bernard <email@hidden>
- Date: Thu, 6 Dec 2007 19:44:22 +0100
On Dec 6, 2007, at 7:30 PM, David Duncan wrote:
This somewhat begs the question of why your using Core Image to
render a gradient via the software renderer in the first place? If
you simply need to construct a gradient, then you can do so directly
via the Quartz API (look up the Quartz 2D Shadings sample code for
an example) instead of using Core Image which, in this case, just
turns around and calls the same functions.
Hi David!
I am trying to scale an image read from a file and save it back to a
file. At the time I wrote this I tried several options and chose the
fastest one.
I do not purposely call upon gradients.
I use the software renderer because I had trouble with the hardware
renderer. I got ugly artefacts in the image. Maybe this comes from
threading too?
I have never used CGImage nor CIImage for anything but this. My
understanding of the technologies is very limited. This code was
constructed with a lot of experimentation work and extensive Google-ing.
The full code is as follows:
+ (BOOL) scaleAndSaveAsJPEG:(NSString *)source
maxSize:(int)maxSize
quality:(float)quality
saveTo:(NSString *)dest
{
NSURL *url = [NSURL fileURLWithPath:source];
CIImage *image = nil;
NSDictionary *metadata = nil;
NSError *error = nil;
BOOL status = [CIImage readFromURL:url image:&image
metadata:&metadata error:&error];
if (!status) {
MLogString(@"%@", error);
return NO;
}
NSNumber* orientation = [(NSDictionary*)metadata objectForKey:
(id)kCGImagePropertyOrientation];
if (orientation != nil) {
int orientationValue = [orientation intValue];
NSNumber* xdpi = [metadata objectForKey:(id)kCGImagePropertyDPIWidth];
NSNumber* ydpi = [metadata objectForKey:
(id)kCGImagePropertyDPIHeight];
if ((orientationValue > 1) && (orientationValue <= 8)) {
image = [image uprightImageWithOrientation:orientationValue
xdpi:xdpi ydpi:ydpi];
}
}
if (maxSize > 0) {
image = [image scaledImageWithMaxSize:maxSize];
}
CFMutableDictionaryRef mSaveMetaAndOpts;
if (metadata != nil) {
mSaveMetaAndOpts = CFDictionaryCreateMutableCopy(nil, 0,
(CFDictionaryRef)metadata);
} else {
mSaveMetaAndOpts = CFDictionaryCreateMutable(nil, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
// save a dictionary of the image properties
CFDictionaryRef tiffProfs = CFDictionaryGetValue(mSaveMetaAndOpts,
kCGImagePropertyTIFFDictionary);
CFMutableDictionaryRef tiffProfsMut;
if (tiffProfs) {
tiffProfsMut = CFDictionaryCreateMutableCopy(nil, 0, tiffProfs);
} else {
tiffProfsMut = CFDictionaryCreateMutable(nil, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
CFDictionarySetValue(mSaveMetaAndOpts,
kCGImagePropertyTIFFDictionary, tiffProfsMut);
CFRelease(tiffProfsMut);
CFDictionarySetValue(mSaveMetaAndOpts,
kCGImageDestinationLossyCompressionQuality,
[NSNumber numberWithFloat:quality]);
CFDictionarySetValue(mSaveMetaAndOpts, kCGImagePropertyOrientation,
[NSNumber numberWithInt:1]);
CFDictionarySetValue(tiffProfsMut, kCGImagePropertyOrientation,
[NSNumber numberWithInt:1]);
NSURL *destUrl = [NSURL fileURLWithPath:dest];
NSError *writeError = nil;
status = [image writeToURL:destUrl ofType:@"public.jpeg" metadata:
(NSDictionary*)mSaveMetaAndOpts error:&writeError];
if (!status) {
MLogString(@"%@", error);
}
return status;
}
+ (BOOL) readFromURL:(NSURL *)absURL image:(CIImage **)outImage
metadata:(NSDictionary **)outMetadata error:(NSError **)outError
{
BOOL status = NO;
CGImageSourceRef source =
CGImageSourceCreateWithURL((CFURLRef)absURL, NULL);
if (source != nil) {
NSDictionary* options = [NSDictionary dictionaryWithObjectsAndKeys:
(id)kCFBooleanFalse, (id)kCGImageSourceShouldCache,
(id)kCFBooleanTrue, (id)kCGImageSourceShouldAllowFloat,
nil];
CGImageRef mImage = CGImageSourceCreateImageAtIndex(source, 0,
(CFDictionaryRef)options);
CFDictionaryRef mMetadata =
CGImageSourceCopyPropertiesAtIndex(source, 0, (CFDictionaryRef)options);
if (mImage != nil) {
status = YES;
*outImage = [CIImage imageWithCGImage:mImage];
*outMetadata = [(NSDictionary*) mMetadata autorelease];
CGImageRelease(mImage);
}
CFRelease(source);
}
if ((status == NO) && (outError)) {
*outError = [NSError errorWithDomain:NSCocoaErrorDomain
code:NSFileReadCorruptFileError userInfo:nil];
}
return status;
}
- (BOOL) writeToURL:(NSURL *)absURL ofType:(NSString *)typeName
metadata:(NSDictionary*)metadata error:(NSError **)outError
{
BOOL status = NO;
CGImageRef image = [self cgImage];
if (image != nil) {
// Create an image destination writing to absURL
CGImageDestinationRef dest =
CGImageDestinationCreateWithURL((CFURLRef)absURL,
(CFStringRef)typeName, 1, nil);
if (dest != nil) {
CGImageDestinationAddImage(dest, image, (CFDictionaryRef)metadata);
status = CGImageDestinationFinalize(dest);
CGImageRelease(image);
}
}
if ((status == NO) && outError) {
*outError = [NSError errorWithDomain:NSCocoaErrorDomain
code:NSFileWriteUnknownError userInfo:nil];
}
return status;
}
- (CGImageRef) cgImage
{
size_t height = [self extent].size.height;
size_t width = [self extent].size.width;
CGRect rect = {{0,0}, {width, height}};
size_t bitsPerComponent = 8;
size_t bytesPerRow = width*4;
CGImageAlphaInfo alphaInfo = kCGImageAlphaPremultipliedLast;
CGContextRef context = CGBitmapContextCreate(nil, width, height,
bitsPerComponent, bytesPerRow,
CGColorSpaceCreateDeviceRGB(), alphaInfo);
NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber
numberWithBool:YES] forKey:kCIContextUseSoftwareRenderer];
CIContext *ciContext = [CIContext contextWithCGContext:context
options:options];
CGColorSpaceRef graySpace = CGColorSpaceCreateDeviceGray();
const float whiteComps[2] = {1.0, 1.0};
CGColorRef whiteColor = CGColorCreate(graySpace, whiteComps);
CFRelease(graySpace);
CGContextSetFillColorWithColor(context, whiteColor);
CGContextFillRect(context, rect);
CFRelease(whiteColor);
CGRect extent = [self extent];
[ciContext drawImage:self inRect:rect fromRect:extent];
CGImageRef image = CGBitmapContextCreateImage(context);
CGContextRelease(context);
return image;
}
- (CIImage *) scaledImageWithMaxSize:(int)maxSize;
{
float width = [self extent].size.width;
float height = [self extent].size.height;
float widthScale = (1.0f + maxSize) / width;
float heightScale = (1.0f + maxSize) / height;
float scaleFactor = MIN(1.0, MIN(widthScale, heightScale));
CIFilter *scaleTransformFilter = [CIFilter
filterWithName:@"CILanczosScaleTransform"];
[scaleTransformFilter setDefaults];
[scaleTransformFilter setValue:[NSNumber numberWithFloat:scaleFactor]
forKey:@"inputScale"];
[scaleTransformFilter setValue:self forKey:@"inputImage"];
CIFilter *unsharpMaskFilter = [CIFilter
filterWithName:@"CIUnsharpMask"];
[unsharpMaskFilter setDefaults];
[unsharpMaskFilter setValue:[NSNumber numberWithFloat:0.3f]
forKey:@"inputIntensity"];
[unsharpMaskFilter setValue:[scaleTransformFilter
valueForKey:@"outputImage"] forKey:@"inputImage"];
return [unsharpMaskFilter valueForKey:@"outputImage"];
}
- (CIImage *) uprightImageWithOrientation:(int)orientation xdpi:
(NSNumber*)xdpi ydpi:(NSNumber*)ydpi
{
if ((orientation < 1) || (orientation > 8)) {
orientation = 1;
}
float xdpiValue = [xdpi floatValue];
if (xdpiValue == 0) {
xdpiValue = 72.0;
}
float ydpiValue = [ydpi floatValue];
if (ydpiValue == 0) {
ydpiValue = 72.0;
}
float width = [self extent].size.width;
float height = [self extent].size.height;
float x = (ydpiValue > xdpiValue) ? ydpiValue/xdpiValue : 1;
float y = (xdpiValue > ydpiValue) ? xdpiValue/ydpiValue : 1;
float w = x * width;
float h = y * height;
CGAffineTransform ctms[8] = {
{ x, 0, 0, y, 0, 0}, // 1 = row 0 top, col 0 lhs = normal
{-x, 0, 0, y, w, 0}, // 2 = row 0 top, col 0 rhs = flip
horizontal
{-x, 0, 0,-y, w, h}, // 3 = row 0 bot, col 0 rhs = rotate 180
{ x, 0, 0,-y, 0, h}, // 4 = row 0 bot, col 0 lhs = flip vertical
{ 0,-x,-y, 0, h, w}, // 5 = row 0 lhs, col 0 top = rot -90,
flip vert
{ 0,-x, y, 0, 0, w}, // 6 = row 0 rhs, col 0 top = rot 90
{ 0, x, y, 0, 0, 0}, // 7 = row 0 rhs, col 0 bot = rot 90, flip
vert
{ 0, x,-y, 0, h, 0} // 8 = row 0 lhs, col 0 bot = rotate -90
};
return [self imageByApplyingTransform:ctms[orientation - 1]];
}
Best,
Pierre
---
Pierre Bernard
http://www.bernard-web.com/pierre
http://www.houdah.com
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden