How to create empty/blank UIImage or CGImage and manipulate pixels on it (Xcode)?
Asked Answered
L

3

12

I have following problem and only could solve it partially yet. I am working with XCode 3.2.5, developing for iOS 4+.

I simply try to create an Image of pre-defined size, manipulate pixels on it and then show the Image in an UIImageView. My view consists of simple Button connected to and IBAction called "buttonClicked" and an UIImageView called "qrImage" and being set as "IBOutlet". I use following Code:

Header-File: myClassViewController.h

#import <UIKit/UIKit.h>

@interface myClassViewController : UIViewController
{
    IBOutlet UIImageView *qrImage;
}

@property (nonatomic, retain) UIImageView   *qrImage;

- (IBAction) buttonClicked;
- (UIImage*) drawQRImage;

@end

Main-File myClassViewController.m

#import "myClassViewController.h"
#include <math.h>

@implementation myClassViewController
@synthesize qrImage;


-(UIImage*) drawQRImage
{
    // load Image
    //
    UIImage *image              = [UIImage imageNamed:@"blank.png"];    
    CGImageRef imageRef         = image.CGImage;
    NSData *data                = (NSData *) CGDataProviderCopyData(CGImageGetDataProvider(imageRef));
    char *pixels                = (char *)[data bytes];

    unsigned long int startPixel, pixelNr;


    // manipulate the individual pixels
    //
    size_t width                = CGImageGetWidth(imageRef);
    size_t height               = CGImageGetHeight(imageRef);

    //
    // [...] deleted some unimportant code here
    //

    pixelNr = 10;

    int red                 = pixelNr*3;
    int green               = pixelNr*3+1;
    int blue                = pixelNr*3+2;

    // Set Pixel-Color Black
    //
    pixels[red]         = 0;
    pixels[green]           = 0;
    pixels[blue]            = 0;

    //
    // [...] deleted some unimportant code here
    //

    // create a new image from the modified pixel data
    //
    size_t bitsPerComponent     = CGImageGetBitsPerComponent(imageRef);
    size_t bitsPerPixel         = CGImageGetBitsPerPixel(imageRef);
    size_t bytesPerRow          = CGImageGetBytesPerRow(imageRef);

    CGColorSpaceRef colorspace  = CGColorSpaceCreateDeviceRGB();
    CGBitmapInfo bitmapInfo     = CGImageGetBitmapInfo(imageRef);
    CGDataProviderRef provider  = CGDataProviderCreateWithData(NULL, pixels, [data length], NULL);

    CGImageRef newImageRef      = CGImageCreate (
                                                 width,
                                                 height,
                                                 bitsPerComponent,
                                                 bitsPerPixel,
                                                 bytesPerRow,
                                                 colorspace,
                                                 bitmapInfo,
                                                 provider,
                                                 NULL,
                                                 false,
                                                 kCGRenderingIntentDefault
                                                 );

    // the modified image
    //
    UIImage *newImage           = [UIImage imageWithCGImage:newImageRef];

    // cleanup
    //
    free(pixels);
    //CGImageRelease(imageRef); // DO NOT RELEASE OR ON NEXT RUN NSData GETS EXC_BAD_ACCESS
    CGColorSpaceRelease(colorspace);
    CGDataProviderRelease(provider);
    CGImageRelease(newImageRef);

    QRcode_free(qrCode);
    QRinput_free(input);

    [image release];

    // return created Image
    //
    return newImage;
}


-(IBAction) buttonClicked
{
    UIImage *createdUIImg = [self drawQRImage]; 
    qrImage.image = createdUIImg;
}

I hope the code is quite self explanatory, if not here a short Description:

A. On Button-Click I call the method drawQRImage, which will return a UIImage. B. Inside drawQRImage I open a PNG-File, until now it has the size 210x210 and only a white background. Nothing else. I then manipulate some of the pixels on it and "paint them black". The current Code should set pixel nr. 11 black. When finished I return the newly created image. C. The method buttonClicked will then show this Image inside the UIImageView.

All in all actually very simple. It also works (nearly) perfectly. But now I want to make some modifications, but can not get them working until now:

  1. The image I have to return is not always 210x210 pixels, so I have to be able to change the size. Loading a "blank" PNG-File and manipulating it's pixels was the only workaround until now I managed to get working. A more elegant way would be creating a blank Image with white BG of desired size I could use in my current method. Unfortunately I didn't find anything on that subject yet. Only on manipulating pixels on allready existing Images. That's how I came up with the current workaround. I allready tried the snipped for resizing from the following Link: Resizing a UIImage the right way

  2. The button can be clicked several times, the painted pixels will also change. My problem now is, that I seem to have a memory leak because I commented out the line

    //CGImageRelease(imageRef);

But if I do release the UIImageRef "imageRef", I will get a EXC_BAD_ACCESS-Error when clicking the button again. So I know this means that I try accessing an object that allready has been released. But how can I solve this problem, I am not sure if I got everything right here. I thought the imageRef will be created newly at the beginning of method "drawQRImage" and hence releasing it should not be a problem when I call the method another time. But looks like I seem to be wrong.

Every bit of help is appreciated!

Luminal answered 24/4, 2011 at 15:46 Comment(1)
I found a not perfect but more or less acceptable workaround for problem #1. I will post the Code as soon as I have tested and finished it. Still, I would be glad if anyone could give me a tip on how to create a blank image instead of having to open a blank/white png (the way I do it right now). Concerning problem #2: I guess following links answers my question to my EXC_BAD_ACCESS-Error, right? #1428602Luminal
M
4

The following discussion addresses memory management for CGImage objects: Releasing CGImage (CGImageRef)

as for the blank image question: Drawing into CGImageRef

Mareah answered 26/8, 2011 at 8:53 Comment(1)
some time ago I asked the question, but thanks anyway. I guess that will do it! Both links look promising. Had to pause the project unfortunately, but will keep on working on it maybe around december.Luminal
D
3

Why not this simple trick? It works for me. (given that self.imageViewSymbol is an UIImageView*)

self.imageViewSymbol.image = nil;
self.imageView.frame = CGRect(...as you like...);
UIGraphicsBeginImageContext(self.imageViewSymbol.bounds.size);
[self.imageViewSymbol.image drawInRect:self.imageViewSymbol.bounds];
self.imageViewSymbol.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Dogmatism answered 12/5, 2012 at 16:51 Comment(0)
E
2

Mansion size and scale to create image

UIGraphicsBeginImageContextWithOptions(*defineSize*, NO, *Scale*);
UIImage *imgClearBG = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Eleaseeleatic answered 24/3, 2017 at 11:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.