如何创建空/空白 UIImage 或 CGImage 并操作其上的像素(Xcode)?

发布于 2024-11-03 16:12:57 字数 4475 浏览 10 评论 0原文

我有以下问题,但只能部分解决。我正在使用 XCode 3.2.5,为 iOS 4+ 进行开发。

我只是尝试创建一个预定义大小的图像,操作其上的像素,然后在 UIImageView 中显示该图像。我的视图由连接到的简单按钮和名为“buttonClicked”的 IBAction 以及名为“qrImage”并设置为“IBOutlet”的 UIImageView 组成。我使用以下代码:

头文件:myClassViewController.h

#import <UIKit/UIKit.h>

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

@property (nonatomic, retain) UIImageView   *qrImage;

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

@end

主文件 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;
}

我希望代码是不言自明的,如果不是这里简短的描述:

A.在按钮单击时,我调用方法drawQRImage,它将返回一个UIImage。 B.在drawQRImage中我打开一个PNG文件,到目前为止它的大小为210x210并且只有白色背景。没有别的了。然后我操纵它上面的一些像素并将它们“漆成黑色”。当前代码应设置像素编号。 11 黑色。完成后,我返回新创建的图像。 C. 然后,buttonClicked 方法将在 UIImageView 中显示此图像。

总而言之其实很简单。它也(几乎)完美地工作。但现在我想做一些修改,但直到现在才可以让它们工作:

  1. 我必须返回的图像并不总是 210x210 像素,所以我必须能够更改大小。加载“空白”PNG 文件并操作它的像素是迄今为止我设法开始工作的唯一解决方法。一种更优雅的方法是创建一个具有所需大小的白色 BG 的空白图像,我可以在当前的方法中使用。不幸的是我还没有找到关于这个主题的任何内容。仅在操作所有现有图像上的像素时。这就是我想出当前解决方法的方法。我已经尝试了从以下链接调整大小的剪裁: 以正确的方式调整 UIImage 的大小

  2. 按钮可以单击多次,绘制的像素也会发生变化。我现在的问题是,我似乎有内存泄漏,因为我注释掉了该行

    //CGImageRelease(imageRef);

但如果我确实释放了 UIImageRef“imageRef”,那么再次单击该按钮时我将收到 EXC_BAD_ACCESS-Error 。所以我知道这意味着我尝试访问一个已经释放的对象。但我该如何解决这个问题,我不确定我是否一切都正确。我认为 imageRef 将在方法“drawQRImage”的开头重新创建,因此当我再次调用该方法时释放它应该不是问题。但看来我好像错了。

感谢您的每一点帮助!

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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

醉南桥 2024-11-10 16:12:57

以下讨论涉及 CGImage 对象的内存管理:
释放 CGImage (CGImageRef)

至于空白图像问题:
绘制到 CGImageRef

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

as for the blank image question:
Drawing into CGImageRef

带上头具痛哭 2024-11-10 16:12:57

为什么不用这个简单的技巧呢?这对我有用。
(假设 self.imageViewSymbol 是一个 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();

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();
⒈起吃苦の倖褔 2024-11-10 16:12:57

豪宅尺寸和规模打造形象

UIGraphicsBeginImageContextWithOptions(*defineSize*, NO, *Scale*);
UIImage *imgClearBG = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

Mansion size and scale to create image

UIGraphicsBeginImageContextWithOptions(*defineSize*, NO, *Scale*);
UIImage *imgClearBG = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文