Leopard: CGContextDrawShading crash a known problem?

  • Hi!

    I am seeing occasional crashes in CGContextDrawShading on Leopard. The
    very same code worked fin on Tiger.

    #0    0x939ef41b in x_list_length
    #1    0x939ef31b in fe_kernel_new_with_kernel
    #2    0x939fb6e7 in fe_kernel_concat
    #3    0x939fb365 in fe_tree_merge_apply
    #4    0x939fb1e7 in fe_tree_merge_kernels_1
    #5    0x939fae3f in fe_tree_merge_kernels_1
    #6    0x939fae3f in fe_tree_merge_kernels_1
    #7    0x939fad41 in fe_tree_merge_kernels
    #8    0x939f6166 in fe_tree_prepare_tree_
    #9    0x939f4a10 in fe_tree_render_image
    #10    0x939f42bc in fe_image_render_
    #11    0x93a4d0e9 in fe_image_render
    #12    0x93b0232e in renderImage
    #13    0x93a4b76f in -[CIOpenGLContextImpl
    renderWithBounds:matrix:function:info:]
    #14    0x93a4b696 in -[CIContextImpl render:]
    #15    0x16a4d769 in cgxcoreimage_instance_render
    #16    0x925d5df2 in CGXCoreImageInstanceRender
    #17    0x900e1e29 in ripc_AcquireCoreImage
    #18    0x900c6faf in ripc_DrawShading
    #19    0x925d5b53 in CGContextDrawShading
    #20    0x939f1ec7 in -[CICGContextImpl render:]
    #21    0x939f1948 in -[CIContext drawImage:inRect:fromRect:]
    #22    0x00020373 in -[CIImage(HSExtensions) cgImage] at CIImage
    +HSExtensions.m:148
    #23    0x000203c5 in -[CIImage(HSExtensions)
    writeToURL:ofType:metadata:error:] at CIImage+HSExtensions.m:161
    #24    0x0001f21e in +[NSImage(HSExtensions)
    scaleAndSaveAsJPEG:maxSize:quality:saveTo:] at NSImage+HSExtensions.m:
    308
    #25    0x00037bdc in -[GoogleEarthExport writeImages:] at
    GoogleEarthExport.m:940
    #26    0x0002e660 in -[SIWorkUnit performWork] at SIWorkUnit.m:45
    #27    0x0002e3cc in -[SIWorkThread workLoop:] at SIWorkThread.m:47
    #28    0x956da04d in -[NSThread main]
    #29    0x956d9bf4 in __NSThread__main__
    #30    0x938ba075 in _pthread_start
    #31    0x938b9f32 in thread_start

    - (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);
    NSMutableDictionary *options = [NSDictionary dictionary];

    #ifndef NSAppKitVersionNumber10_4
    #define NSAppKitVersionNumber10_4 824
    #endif

    if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_4)
    {
      [options setObject:[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;
    }

    Pierre
    ---
    Pierre Bernard
    http://www.bernard-web.com/pierre
    http://www.houdah.com
  • Hi!

    It appears that the crash I am seeing is related to multithreading. If
    I use Core Images concurrently on different threads, I seem to be
    begging for trouble. This worked just fine on Tiger.

    Pierre

    On Dec 5, 2007, at 2:09 PM, Pierre Bernard wrote:

    > Hi!
    >
    > I am seeing occasional crashes in CGContextDrawShading on Leopard.
    > The very same code worked fin on Tiger.
    >
    > #0    0x939ef41b in x_list_length
    > #1    0x939ef31b in fe_kernel_new_with_kernel
    > #2    0x939fb6e7 in fe_kernel_concat
    > #3    0x939fb365 in fe_tree_merge_apply
    > #4    0x939fb1e7 in fe_tree_merge_kernels_1
    > #5    0x939fae3f in fe_tree_merge_kernels_1
    > #6    0x939fae3f in fe_tree_merge_kernels_1
    > #7    0x939fad41 in fe_tree_merge_kernels
    > #8    0x939f6166 in fe_tree_prepare_tree_
    > #9    0x939f4a10 in fe_tree_render_image
    > #10    0x939f42bc in fe_image_render_
    > #11    0x93a4d0e9 in fe_image_render
    > #12    0x93b0232e in renderImage
    > #13    0x93a4b76f in -[CIOpenGLContextImpl
    > renderWithBounds:matrix:function:info:]
    > #14    0x93a4b696 in -[CIContextImpl render:]
    > #15    0x16a4d769 in cgxcoreimage_instance_render
    > #16    0x925d5df2 in CGXCoreImageInstanceRender
    > #17    0x900e1e29 in ripc_AcquireCoreImage
    > #18    0x900c6faf in ripc_DrawShading
    > #19    0x925d5b53 in CGContextDrawShading
    > #20    0x939f1ec7 in -[CICGContextImpl render:]
    > #21    0x939f1948 in -[CIContext drawImage:inRect:fromRect:]
    > #22    0x00020373 in -[CIImage(HSExtensions) cgImage] at CIImage
    > +HSExtensions.m:148
    > #23    0x000203c5 in -[CIImage(HSExtensions)
    > writeToURL:ofType:metadata:error:] at CIImage+HSExtensions.m:161
    > #24    0x0001f21e in +[NSImage(HSExtensions)
    > scaleAndSaveAsJPEG:maxSize:quality:saveTo:] at NSImage
    > +HSExtensions.m:308
    > #25    0x00037bdc in -[GoogleEarthExport writeImages:] at
    > GoogleEarthExport.m:940
    > #26    0x0002e660 in -[SIWorkUnit performWork] at SIWorkUnit.m:45
    > #27    0x0002e3cc in -[SIWorkThread workLoop:] at SIWorkThread.m:47
    > #28    0x956da04d in -[NSThread main]
    > #29    0x956d9bf4 in __NSThread__main__
    > #30    0x938ba075 in _pthread_start
    > #31    0x938b9f32 in thread_start
    >
    > - (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);
    > NSMutableDictionary *options = [NSDictionary dictionary];
    >
    > #ifndef NSAppKitVersionNumber10_4
    > #define NSAppKitVersionNumber10_4 824
    > #endif
    >
    > if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_4)
    > {
    > [options setObject:[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;
    > }
    >
    > Pierre
    > ---
    > Pierre Bernard
    > http://www.bernard-web.com/pierre
    > http://www.houdah.com

    ---
    Pierre Bernard
    http://www.bernard-web.com/pierre
    http://www.houdah.com
  • On Dec 6, 2007, at 9:48 AM, Pierre Bernard wrote:

    > It appears that the crash I am seeing is related to multithreading.
    > If I use Core Images concurrently on different threads, I seem to be
    > begging for trouble. This worked just fine on Tiger.
    >
    > On Dec 5, 2007, at 2:09 PM, Pierre Bernard wrote:
    >
    >> I am seeing occasional crashes in CGContextDrawShading on Leopard.
    >> The very same code worked fin on Tiger.

    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.
    --
    David Duncan
    Apple DTS Animation and Printing
    <david.duncan...>
  • 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
previous month december 2007 next month
MTWTFSS
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            
Go to today