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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5771501/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 03:54:38  来源:igfitidea点击:

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

iphonexcodeuiimagepixelcgimage

提问by EliteTUM

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

我有以下问题,但只能部分解决。我正在使用 XCode 3.2.5,为 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:

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

Header-File: myClassViewController.h

头文件: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

主文件 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.

A. 在 Button-Click 上,我调用 drawQRImage 方法,该方法将返回一个 UIImage。B. 在 drawQRImage 中,我打开了一个 PNG 文件,直到现在它的大小为 210x210,只有白色背景。没有其他的。然后我操纵它上面的一些像素并“将它们涂成黑色”。当前代码应设置像素 nr。11 黑色。完成后,我返回新创建的图像。C. buttonClicked 方法将在 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);

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

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

    //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.

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

Every bit of help is appreciated!

每一点帮助表示赞赏!

采纳答案by 5hoom

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

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

as for the blank image question: Drawing into CGImageRef

至于空白图像问题: Drawing into CGImageRef

回答by roberto.buratti

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

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

回答by Darshit Shah

Mansion size and scale to create image

大厦大小和规模创造形象

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