views:

21

answers:

1

How do I read the image color information for each pixel of PVRTC image?

Here is my code extracting the integer arrays

    NSData *data = [[NSData alloc] initWithContentsOfFile:path];

 NSMutableArray *_imageData = [[NSMutableArray alloc] initWithCapacity:10];

 BOOL success = FALSE;
 PVRTexHeader *header = NULL;
 uint32_t flags, pvrTag;
 uint32_t dataLength = 0, dataOffset = 0, dataSize = 0;
 uint32_t blockSize = 0, widthBlocks = 0, heightBlocks = 0;
 uint32_t width = 0, height = 0, bpp = 4;
 uint8_t *bytes = NULL;
 uint32_t formatFlags;

 header = (PVRTexHeader *)[data bytes];

 pvrTag = CFSwapInt32LittleToHost(header->pvrTag);

 if (gPVRTexIdentifier[0] != ((pvrTag >>  0) & 0xff) ||
  gPVRTexIdentifier[1] != ((pvrTag >>  8) & 0xff) ||
  gPVRTexIdentifier[2] != ((pvrTag >> 16) & 0xff) ||
  gPVRTexIdentifier[3] != ((pvrTag >> 24) & 0xff))
 {
  return FALSE;
 }

 flags = CFSwapInt32LittleToHost(header->flags);
 formatFlags = flags & PVR_TEXTURE_FLAG_TYPE_MASK;

 if (formatFlags == kPVRTextureFlagTypePVRTC_4 || formatFlags == kPVRTextureFlagTypePVRTC_2)
 {
  [_imageData removeAllObjects];

  if (formatFlags == kPVRTextureFlagTypePVRTC_4)
   _internalFormat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
  else if (formatFlags == kPVRTextureFlagTypePVRTC_2)
   _internalFormat = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;


  _width = width = CFSwapInt32LittleToHost(header->width);
  _height = height = CFSwapInt32LittleToHost(header->height);

  if (CFSwapInt32LittleToHost(header->bitmaskAlpha))
   _hasAlpha = TRUE;
  else
   _hasAlpha = FALSE;

  dataLength = CFSwapInt32LittleToHost(header->dataLength);

  bytes = ((uint8_t *)[data bytes]) + sizeof(PVRTexHeader);

  // Calculate the data size for each texture level and respect the minimum number of blocks
  while (dataOffset < dataLength)
  {
   if (formatFlags == kPVRTextureFlagTypePVRTC_4)
   {
    blockSize = 4 * 4; // Pixel by pixel block size for 4bpp
    widthBlocks = width / 4;
    heightBlocks = height / 4;
    bpp = 4;
   }
   else
   {
    blockSize = 8 * 4; // Pixel by pixel block size for 2bpp
    widthBlocks = width / 8;
    heightBlocks = height / 4;
    bpp = 2;
   }

   // Clamp to minimum number of blocks
   if (widthBlocks < 2)
    widthBlocks = 2;
   if (heightBlocks < 2)
    heightBlocks = 2;

   dataSize = widthBlocks * heightBlocks * ((blockSize  * bpp) / 8);

   [_imageData addObject:[NSData dataWithBytes:bytes+dataOffset length:dataSize]];

                   for (int i=0; i < mipmapCount; i++)
                    {

              NSLog(@"width:%d, height:%d",width,height);

              data = [[NSData alloc] initWithData:[_imageData objectAtIndex:i]];
              NSLog(@"data length:%d",[data length]);

//extracted 20 sample data, but all u could see are large integer number for(int i = 0; i < 20; i++){ NSLog(@"data[%d]:%d",i,data[i]); }

A: 

PVRTC is a 4x4 (or 8x4) texel, block-based compression system that takes into account surrounding blocks to represent two low frequency images with which higher frequency modulation data is combined in order to produce the actual texel output. A better explanation is available here:

http://web.onetel.net.uk/~simonnihal/assorted3d/fenney03texcomp.pdf

So the values you're extracting are actually parts of the encoded blocks and these need to be decoded correctly in order to get sensible values.

There are two ways to get to the colour information: decode/decompress the PVR texture information using a software decompressor or render the texture using a POWERVR graphics core and then read the result back. I'll only discuss the first option here.

It's rather tricky to assemble a decompressor from only the information there, but fortunately there's C++ decompression source code in the POWERVR SDK which you can get here - download one of the iPhone SDKs for instance:

http://www.imgtec.com/powervr/insider/powervr-sdk.asp

It's in the Tools/PVRTDecompress.cpp file.

Hope that helps.

gmaclachlan