Initializing a pixel array from a CGBitmapContext

Discussion in 'iOS Programming' started by KnightWRX, Jul 23, 2011.

  1. macrumors Pentium

    KnightWRX

    Joined:
    Jan 28, 2009
    Location:
    Quebec, Canada
    #1
    Hi!

    Ran into an issue with PNGs having transparent backgrounds and applying them into a pixel array using a CGBitmapContext. This was the "faulty" code :

    Code:
    -(id) initWithCGImage: (CGImageRef) image
    {
    	NSInteger bytes;
    	self = [super init];
    	
    	CGColorSpaceRef colorSpace;
    	
    	width = CGImageGetWidth(image);
    	height = CGImageGetHeight(image);
    	bytesPerChannel = 4; 
    	
    	colorSpace = CGColorSpaceCreateDeviceRGB();
    	bytes = width * height * sizeof(BRUnifiedPixelRGBA);
    	imagePixels = malloc(bytes);
    	//[self resetToSolidColor: 0x00000000];
    	CGContextRef context = CGBitmapContextCreate(imagePixels, 
    						   width,
    						   height,
    						   8,
    						   width * bytesPerChannel,
    						 colorSpace,
    			             		 kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
    	
            CGContextDrawImage(context,
    	   		   CGRectMake(0.0f, 0.0f, width, height),
    			   image);
    	CGContextRelease(context);
    	CGColorSpaceRelease(colorSpace);
    	
    	return self;
    }
    
    This ended up giving artifacts (from previously used and discarded memory regions in all probability) that basically looked like this :

    [​IMG]

    (Please save the laughter and comments about my graphical skills for yourselves. Consider it an honor to have seen a very, very early screenshot).

    Now, my question, short of resetting the entire pixel buffer memory after allocation (either with memcpy() or with a for loop, which [-(void) resetToSolidColor basically is), is there some parameters I can pass to CGBitmapContextCreate to tell it to not do alpha blending and just squash whatever is there ?

    Reading through CGImageAlphaInfo, I'm not quite sure I understand the Premultiplied vs well... not premultiplied bit. Is that what I'm looking for or really is there just no way to do this short of resetting memory myself ?

    (BTW, yes, I realise the BytesPerChannel variable is very poorly named. There is only 1 byte per channel, 4 channels per pixel... whatever, call it lazyness on my part, this code was written a very long time ago and I'm just now using it with transparent PNGs).
     
  2. macrumors 603

    Joined:
    Aug 9, 2009
    #2
    Call calloc() instead of malloc() and the memory will be returned zeroed. See the man page for calloc.

    Otherwise you'll have to zero it yourself. Assuming zeroing is the desired state for the pixel format.
     
  3. thread starter macrumors Pentium

    KnightWRX

    Joined:
    Jan 28, 2009
    Location:
    Quebec, Canada
    #3
    Yes 0 is fine since this is a transparent png the alpha channel needs to be set to 0 or otherwise it would mess up when I merge 2 images.

    Hum... calloc has a bit of a different calling convention than malloc, dunno if I want to mess with that. The resetToSolidColor function is actually quite useful in initializing flat color surfaces, which I use a lot. I think I'll just keep that and make the 0x0 value a constant like my other color constants and clean up the code a bit.

    But can someone still explain what the Alpha premultiplied vs not pre-multiplied means ? The documentation isn't quite clear there.
     
  4. macrumors 603

    Joined:
    Aug 9, 2009
    #4
    It's simple C. You'll have to read the man page, but it's not hard.

    No harm in that.

    Did google stop working?

    If I start typing "premult", the first suggestion is "premultiplied alpha".
    If I choose that, the first result is a Wikipedia article:
    http://en.wikipedia.org/wiki/Alpha_compositing

    If I find "premult" on the page, an explanation and example moves into view.
     
  5. macrumors 603

    Joined:
    Jul 29, 2003
    Location:
    Silicon Valley
    #5
    non-premultiplied means your 8-bit RGB values are full scaled to go from 0 to 255

    premultiplied means your 8-bit RGB values are scaled to go from 0 to Alpha,
    where Alpha can be less than 255.
     
  6. thread starter macrumors Pentium

    KnightWRX

    Joined:
    Jan 28, 2009
    Location:
    Quebec, Canada
    #6
    I'm sure it's not, but allocating a sized object and then a count of those means I need to sit down and read it, when basically, I already wrote the "zeroing" code which also serves another purpose on top of it.


    Sorry, I was stuck on Apple's documentation and didn't think this was a broader concept concerning Alpha blending. The wikipedia page was quite clear and it has nothing to do with what I wanted. I really guess calloc() or malloc() plus a full buffer initalization is the only way to not screw up the transparent background when copying the PNG using a CGBitmapContext. Anyway, the code works great now.
     
  7. macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #7
    If you want to fill your context with a color then you should fill your context with a color.

    Code:
    CGContextSetFillColorWithColor(context, backgroundColor);
    CGContextFillRect(context, bounds);
    
     
  8. thread starter macrumors Pentium

    KnightWRX

    Joined:
    Jan 28, 2009
    Location:
    Quebec, Canada
    #8
    That actually wouldn't work at all in my case. I'll leave you to think on why not. ;) Hint: It would result in the same broken behavior with artifacts.
     

Share This Page