以前でっぱりだったトコ このページをアンテナに追加 RSSフィード

2008-10-08

UIImageからのピクセルデータの読み込み(つづき) 14:46

先のコードで何枚も画像を読んでるとCGDataProviderCopyDataのところで落ちる。CFRelease(ibuf);をコメントアウトすると動くけど、メモリリークの状況はInstrumentsで明確にモニターできる。で、

  // CFRelease(ibuf);
  NSData* ibuf2 = (NSData*)ibuf;
  [ibuf2 release];

しても同じ症状で落ちる。はて、と思って[ibuf2 release]を[ibuf2 autorelease]にしてみたらメモリも解放されるっぽくて、かつ落ちないみたい。

なにそれー。

いや、これでダメなら

  static CFDataRef ibuf = 0;
  if (ibuf) CFRelease(ibuf);
  ibuf = CGDataProviderCopyData(.....

とかやろうとしてて、そこまで変態的な事しなくて済んで良かったのかも。いや、でもこれはバッドノウハウなんでないの?

追記 15:12

autoreleaseでもstatic CFDataRefでも落ちます。うーん、困った。

メモリリークをわかっていながらリリースしないで放っておく?

また続き 17:17

メモリリークは起きてなさそう。画像をどんどん読み込んでも落ちなさそう。ただ、特定の画像を読もうとすると必ず落ちます。どっちがええんかな。色空間の変換もしてくれるし、API Referenceに記述されてる範囲で収まってる分だけ、こっちの方が筋が良さそうだけど… ちなみに落ちるのはCGContextDrawImageのトコです。

void SketchPainter::setUIImage(UIImage *img) {
  double ratio, ratio_w, ratio_h;
  uint16 *buf = this->buf();
  uint x, y, index, offset_x, offset_y, offset;
  
  CGImageRef cgimg = img.CGImage;
  uint imgw = CGImageGetWidth(cgimg);
  uint imgh = CGImageGetHeight(cgimg);

  ratio_w = (double)imgw / width;
  ratio_h = (double)imgh / height;
  ratio = (ratio_w < ratio_h) ? ratio_w : ratio_h;
  offset_x = max(0, (int)floor((imgw - width * ratio) / 2));
  offset_y = max(0, (int)floor((imgh - height * ratio) / 2));

  CGContextRef bitmap;
  NSMutableData *imgdata = [[NSMutableData alloc]
			     initWithLength:width * height * 4];
  UInt8 *imgbuf = (UInt8*)[imgdata mutableBytes];
  bitmap = CGBitmapContextCreate(imgbuf, imgw, imgh, 8, imgw * 4,
				 CGColorSpaceCreateDeviceRGB(),
				 kCGImageAlphaNoneSkipFirst);
  CGContextDrawImage(bitmap, CGRectMake(0, 0, imgw, imgh), cgimg);
  CGContextRelease(bitmap);

  PtColor col;
  offset = offset_y * imgw + offset_x;
  for (y = 0; y < height; y ++)
    for (x = 0; x < width; x ++) {
      index = (offset + 
	       (uint)floor(y * ratio) * imgw +
	       (uint)floor(x * ratio)) * 4;
      col.setRgb(imgbuf[index + 1],
		 imgbuf[index + 2],
		 imgbuf[index + 3]);
      buf[y * width +  x] = SketchPainter::pack_color(col);
    }
  [imgdata release];
}

追記 00:53

そりゃダメじゃん。「initWithLength:width * height * 4];」じゃなくて「initWithLength:imgw * imgh * 4];」にしなきゃ。これで落ちないかな?

今日の5の2 23:54

何これ、面白いじゃん。全然期待してなかったのに。

画像の読み書き 00:56

今日はウソをいっぱい書いてしまったようなので罪滅ぼしに現状の読み書きルーチンをそのまま上げときます。

#include "ptimageutil.h"
#include "sketchpainter.h"
#include "ptcolor.h"

UIImage* PtImageUtil::uint16toUIImage(unsigned short int* buf, int imgw,
			 int x0, int y0, int w, int h) {
  CGDataProviderRef providerref;
  providerref = 
    CGDataProviderCreateWithData(NULL, 
				 buf + y0 * imgw + x0, 
				 imgw * 2 * h, NULL);
  CGImageRef imgref = 
    CGImageCreate(w, h, 5, 16, imgw * 2, 
		  CGColorSpaceCreateDeviceRGB(),
		  kCGBitmapByteOrder16Host,
		  providerref, NULL, NO, kCGRenderingIntentDefault);
  CGDataProviderRelease(providerref);
  UIImage *img = [UIImage imageWithCGImage:imgref];
  CGImageRelease(imgref);
  
  return img;
}

uint16* PtImageUtil::UIImagetoUint16(UIImage *img, 
                                     int *imgw, int *imgh) {
  CGImageRef cgimg = img.CGImage;
  int w = CGImageGetWidth(cgimg);
  int h = CGImageGetHeight(cgimg);

  UInt8* sbuf = new UInt8[w * h * 4];
  uint16* dbuf = new uint16[w * h];
  CGContextRef cont;
  cont = CGBitmapContextCreate(sbuf, w, h, 8, w * 4,
                               CGColorSpaceCreateDeviceRGB(),
                               kCGImageAlphaNoneSkipFirst);
  CGContextDrawImage(cont, CGRectMake(0, 0, w, h), cgimg);
  CGContextRelease(cont);

  int x, y, index;
  PtColor col;
  for (y = 0; y < h; y ++) {
    index = y * w;
    for (x = 0; x < w; x ++, index ++) {
      col.setRgb(sbuf[index * 4 + 1],
                 sbuf[index * 4 + 2],
                 sbuf[index * 4 + 3]);
      dbuf[index] = SketchPainter::pack_color(col);
    }
  }
  delete[] sbuf;

  if (imgw) *imgw = w;
  if (imgh) *imgh = h;

  return dbuf;
}
Connection: close