• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: [Leopard] CIContext thread safety [was: CGContextDrawShading crash a known problem?]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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


References: 
 >Leopard: CGContextDrawShading crash a known problem? (From: Pierre Bernard <email@hidden>)
 >[Leopard] CIContext thread safety [was: CGContextDrawShading crash a known problem?] (From: Pierre Bernard <email@hidden>)
 >Re: [Leopard] CIContext thread safety [was: CGContextDrawShading crash a known problem?] (From: David Duncan <email@hidden>)

  • Prev by Date: Re: [Leopard] CIContext thread safety [was: CGContextDrawShading crash a known problem?]
  • Next by Date: Question about NSView's -enterFullScreenMode:withOptions: method
  • Previous by thread: Re: [Leopard] CIContext thread safety [was: CGContextDrawShading crash a known problem?]
  • Next by thread: Preference panel appears one but not the second time?
  • Index(es):
    • Date
    • Thread