Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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!

like image 399
EliteTUM Avatar asked Apr 24 '11 15:04

EliteTUM


People also ask

What is UIImage in Xcode?

An object that manages image data in your app.

What is the difference between UIImage and UIImageView?

UIImage contains the data for an image. UIImageView is a custom view meant to display the UIImage . Save this answer.


3 Answers

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

as for the blank image question: Drawing into CGImageRef

like image 142
5hoom Avatar answered Oct 28 '22 10:10

5hoom


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();
like image 22
roberto.buratti Avatar answered Oct 28 '22 10:10

roberto.buratti


Mansion size and scale to create image

UIGraphicsBeginImageContextWithOptions(*defineSize*, NO, *Scale*);
UIImage *imgClearBG = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
like image 34
Darshit Shah Avatar answered Oct 28 '22 11:10

Darshit Shah