Как создать пустой / пустой UIImage или CGImage и манипулировать пикселями на нем (Xcode)? - PullRequest
11 голосов
/ 24 апреля 2011

У меня есть следующая проблема, и я смог решить ее только частично. Я работаю с XCode 3.2.5, разрабатываю для iOS 4+.

Я просто пытаюсь создать изображение заранее определенного размера, манипулировать пикселями на нем и затем отображать изображение в UIImageView. Мое представление состоит из простой кнопки, подключенной к IBAction и называемой «buttonClicked», и UIImageView с именем «qrImage» и устанавливаемого как «IBOutlet». Я использую следующий код:

Заголовочный файл: 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;
}

Надеюсь, код достаточно понятен, если не короткое описание:

A. При нажатии кнопки я вызываю метод drawQRImage, который возвращает UIImage. B. Внутри drawQRImage я открываю PNG-файл, до сих пор он имеет размер 210x210 и только белый фон. Ничего больше. Затем я манипулирую некоторыми пикселями на нем и «закрашиваю их в черный цвет». Текущий код должен установить номер пикселя. 11 черный. По окончании я возвращаю только что созданное изображение. C. Затем метод buttonClicked покажет это изображение внутри UIImageView.

В целом все очень просто. Это также работает (почти) отлично. Но сейчас я хочу внести некоторые изменения, но не могу заставить их работать до сих пор:

  1. Изображение, которое я должен вернуть, не всегда имеет размер 210x210 пикселей, поэтому я должен иметь возможность изменить размер. Загрузка «пустого» PNG-файла и манипулирование его пикселями была единственным выходом из положения, и теперь мне удалось начать работать. Более элегантным способом было бы создать пустое изображение с белым фоновым рисунком желаемого размера, которое я мог бы использовать в своем текущем методе. К сожалению, я еще ничего не нашел по этому вопросу. Только при работе с пикселями на уже существующих изображениях. Вот как я придумал текущий обходной путь. Я уже пробовал отсканировать для изменения размера по следующей ссылке: Изменение размера UIImage правильным способом

  2. Кнопка может быть нажата несколько раз, измененные пиксели также изменятся. Моя проблема сейчас в том, что у меня, похоже, утечка памяти, потому что я закомментировал строку

    // CGImageRelease (imageRef);

Но если я выпущу UIImageRef "imageRef", я получу ошибку EXC_BAD_ACCESS при повторном нажатии кнопки. Итак, я знаю, что это означает, что я пытаюсь получить доступ к объекту, который уже был освобожден. Но как я могу решить эту проблему, я не уверен, все ли у меня получилось. Я думал, что imageRef будет создан заново в начале метода "drawQRImage" и, следовательно, его освобождение не должно быть проблемой, когда я вызываю метод в другой раз. Но, похоже, я не прав.

Мы ценим любую помощь!

Ответы [ 3 ]

4 голосов
/ 26 августа 2011

В следующем обсуждении рассматривается управление памятью для объектов CGImage: Выпуск CGImage (CGImageRef)

что касается вопроса с пустым изображением: Рисование в CGImageRef

3 голосов
/ 12 мая 2012

Почему бы не этот простой трюк? Меня устраивает. (учитывая, что 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();
1 голос
/ 24 марта 2017

Размер и масштаб особняка для создания изображения

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