2011-11-04 4 views
1

나는 내가 할 수있는 그러한 PNG 파일을 읽을 수 :조작 원시 PNG 데이터

A) 전치 승산없는 색 공간 조정 또는 알파와 파일의 원시 비트 맵 데이터를 액세스 할 수 있습니다.

b) 비트 맵을 기반으로하여 이미지를 비트 맵으로 표시합니다 (이미지 전체에 걸쳐 비트, 전체 이미지에서 하나의 비트로만 표시). 비트 맵을 가지고 있다면 적절한 비트를 찾을 수 있지만 화면에 표시하기 위해 무엇을 넣을 수 있습니까?

c) 비트 플래 인 수정 후 수정없이 새로운 PNG 파일을 다시 작성하십시오.

이것은 특정 이미지에만 적용됩니다. PNG는 단순히 RGBA-32 이외의 데이터를 가질 것으로 예상되지 않습니다.

몇 가지 유사한 질문을 여기에서 읽으면서 NSBitmapImageRep 파일의 읽기/쓰기 및 NSView에서 화면상의 부분을 그리는 것으로 의심됩니다. 이 말이 맞습니까?

답변

1

1.) NSBitmapImageRep의 -bitmapData를 사용하여 원시 픽셀 데이터를 얻을 수 있습니다. 불행히도 CG (NSBitmapImageRep의 백엔드)는 기본 unpremultiplication을 지원하지 않으므로 자신을 unpremultiply해야합니다. 이 색상 공간은 파일에있는 것과 동일합니다. 다음은 이미지 데이터를 unpremultiply하는 방법입니다 :

NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:data]; 
    NSInteger width = [imageRep pixelsWide]; 
    NSInteger height = [imageRep pixelsHigh]; 

    unsigned char *bytes = [imageRep bitmapData]; 
    for (NSUInteger y = 0; y < width * height * 4; y += 4) { // bgra little endian + alpha first 
     uint8_t a, r, g, b; 

     if (imageRep.bitmapFormat & NSAlphaFirstBitmapFormat) { 
      a = bytes[y]; 
      r = bytes[y+1]; 
      g = bytes[y+2]; 
      b = bytes[y+3]; 
     } else { 
      r = bytes[y+0]; 
      g = bytes[y+1]; 
      b = bytes[y+2]; 
      a = bytes[y+3]; 
     } 

     // unpremultiply alpha if there is any 
     if (a > 0) { 
      if (!(imageRep.bitmapFormat & NSAlphaNonpremultipliedBitmapFormat)) { 
       float factor = 255.0f/a; 
       b *= factor; 
       g *= factor; 
       r *= factor; 
      } 
     } else { 
      b = 0; 
      g = 0; 
      r = 0; 
     } 
     bytes[y]=a; // for argb 
     bytes[y+1]=r; 
     bytes[y+2]=g; 
     bytes[y+3]=b; 
    } 

2.)이 작업을 수행하는 간단한 방법을 생각할 수 없었습니다. 원시 이미지 데이터를 반복하고 값을 기반으로 새 이미지를 생성하는 고유 한 이미지 그리기 방법을 만들 수 있습니다. 그것을 시작하는 방법을 보려면 위에서 참조하십시오.

3.) 여기에 CG가 불편하게하는 경우 (당신이

static CGImageRef cgImageFrom(NSData *data, uint16_t width, uint16_t height) { 
CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)data); 
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
CGBitmapInfo bitmapInfo = kCGImageAlphaFirst; 

CGImageRef cgImage = CGImageCreate(width, height, 8, 32, 4 * width, colorSpace, bitmapInfo, provider, NULL, NO, kCGRenderingIntentDefault); 
CGDataProviderRelease(provider); 
CGColorSpaceRelease(colorSpace); 
return cgImage; 
} 

) 기본 CG 기능을 사용하여 파일에 PNG를 작성하거나 NSBitmapImageRep로 변환 할 수 있습니다 원시 데이터 장소에서의 CGImage를 얻을 수있는 방법이다 +dataWithBytes:length:

+1

아야. 사전 곱셈을 제거하면 특히 알파가 작은 경우 심각한 반올림 오류가 발생합니다. 그러면 비트 맵에 액세스 할 때 문제가 발생합니다. 미리로드되지 않은 파일에 ** 정확한 ** 비트 맵 값을로드하고 저장해야합니다. CGImageCreateWithPNGDataProvider는 CGImage에 미리 곱하기 여부를 지정하는 접근자를 가지고 있으므로이 기능을 지원하는 것처럼 보입니다. CGImageDestinationCreateWithURL은 PNG를 쓰는 것처럼 들립니다. –

+0

예, 데이터가 원본 이미지에 미리 unprimultiplied되어 있다면 CGImage/NSBitmapImageRep은 그 이미지를 그대로 취급 할 것입니다. 컨텍스트에 그려지고 메모리에 새 이미지로 초기화 된 이미지는 지원되지 않으므로 unpremultiplied되지 않습니다. 또한, unpremultiplication 동안 lossiness 불가피합니다. –

+0

사실 ** PNG 파일의 ** 원래 ** 데이터는 ** 미리 곱셈되지 않았습니다. 로드, 수정 및 저장하려는 데이터입니다. 하지만 내가 바로 참조를 읽고 있다면 NSBitmapImageRep (비트 맵에 액세스하는 방법을 볼 수있는 유일한 클래스)은 파일의 데이터로 초기화 될 때 미리 곱해집니다. 파이썬의 PyPNG 모듈이 최선의 방법이라고 생각합니다. 데이터를 얻기 위해 Cocoa에서 쉬운 방법을 찾지 못했습니다. –

0

나는이 분야에서 일한 적이 없지만 Image IO을 사용할 수 있습니다.

+0

이미지 입출력은 파일과 CGImageRef 사이의 이미지 전송을 처리합니다. 분명히 미리 곱하기가 없으므로 # 1과 # 3을 덮어 씁니다.모든 종류의 필터에 CGImage를 공급하거나 화면으로 보낼 수는 있지만 비트 맵 데이터에 액세스 할 방법은 없습니다. :( –