Results 1 to 21 of 21

Thread: Compressed Pixel Formats

  1. #1
    Member
    Join Date
    Mar 2014
    Location
    Greece
    Posts
    10
    Thanks
    1
    Thanked 1 Time in 1 Post

    Compressed Pixel Formats

    Greetings to the geekiest and COOLEST community existing

    To be honest i registered when searching about the LZSS compression but until i got my account activated (thanks encode) i resolved my issue, and here i am with another one.

    I am ripping 3d models from game files. Most of the time the model data is relatively easy to find, but i have serious trouble with the textures.

    In many files the textures stored are stripped of their original header. They are assigned a local distinctive type in order for the game to be able to recognize each of them and near that type there is the width and the height of the texture.

    So in the end i have this info and all the raw data of the image.

    From type to type the relation between the number of the pixels of the image and the total bytes of the data is different. That means that in some cases i have compressed pixel formats as well.

    I made a quick search on the internet and i literally got lost by all the possibilities available.

    So my question is: How the heck can i recognize in which format the pixels are stored in the data, just by seeing the data in hex? At least how can i make an initial guess in order to decrease the number of possible formats?

    And in addition to that, is there any way to preview raw image data? Every piece of software i've tried so far crashes because of the lack of a valid header of the file.

    I start to believe that its inevitable to sit down and write a piece of software that does exactly that...

    PS: To be honest after struggling with some raw data taken from a wii game, i ended up that i have a 4bit per pixel relation (so its a compressed image) and i started messing around with PVR compressions and stuff llike that but it seems like its a DXT1 compressed image. I've not cleared it out yet, but i think its more like that. I just can't afford so much time on searching for images, i think its really embarrassing...

  2. #2
    Member
    Join Date
    Nov 2013
    Location
    US
    Posts
    131
    Thanks
    31
    Thanked 29 Times in 19 Posts
    There are very few texture compression formats supported by GPUs because these are meant for high speed and usually fixed compression ratios. The most common family is probably DXTn, there is some information on Wikipedia under "S3 Texture Compression". 3Dc is another well-known method.

    If you can guess the size and width of an image, you can make a simple viewer in Direct3D/OpenGL by passing the raw bytes in texture generation and specifying the format as, example, DXT5 instead of RGBA8. The headers are only useful to the program, not the GPU or driver that draws the actual texture. The simple way to guess is to pass in as DXT1..n, and see which format shows an image.

  3. #3
    Member
    Join Date
    Mar 2014
    Location
    Greece
    Posts
    10
    Thanks
    1
    Thanked 1 Time in 1 Post
    Yesterday i started writing my own dxt1 decoder, because i could not visualize correctly some texture information (from files of a wii game as i mentioned on the first post).

    So i ended up with this piece of python code:


    Code:
     from PIL import Image
    
     import struct
     
    
     
    
     f=open('raw_200_200','rb')
    
     width=0x200
     height=0x200
    
     img=Image.new('RGB',(width,height),'white')
     index_table=[]
     
    
     
    
     #iterate in 16 Pixel Blocks
            
     for block_i in range(0,width,4):
         for block_j in range(0,height,4):
             #Read Pixel information
             
             #Grab the Color Bytes        
             #Color0        
             color0=struct.unpack('<H',f.read(2))[0]        
             #Unpack        
    
             b0=(color0 & 0x1f)<<3
             g0=((color0 >>5)&0x3f)<<2
    
             r0=((color0 >>11)&0x1f)<<3
             
             #Expansion Not Needed, Basically only the first part is applied        
             #r0=r0<<3 | r0>>2
             #g0=g0<<2 | g0>>4
             #r0=b0<<3 | b0>>2
             
             color0=(r0,g0,b0)
             
             #Grab the Color Bytes        
             #Color1        
             
    
             color1=struct.unpack('<H',f.read(2))[0]        
    
             b1=(color1 & 0x1f)<<3
             g1=((color1 >>5)&0x3f)<<2
             r1=((color1 >>11)&0x1f)<<3
             
             #Expand        
             #r1=r1<<3 | r1>>2
             #g1=g1<<2 | g1>>4
             #r1=b1<<3 | b1>>2
             
             color1=(r1,g1,b1)
    
             
             
             #Interpolate the other colors
    
             if not color1>color0:
                 
                 color3=((color0[0]+color1[0])//2,(color0[1]+color1[1])//2,(color0[2]+color1[2])//2)
    
                 color4= 0x000000
             else:
                 #color3=color0
                 #color4=color1
                 color3=((2*color0[0]+color1[0])//3,(2*color0[1]+color1[1])//3,(2*color0[2]+color1[2])//3)
                 color4=((2*color1[0]+color0[0])//3,(2*color1[1]+color0[1])//3,(2*color1[2]+color0[2])//3)
                 
             
             #Grab Index Bytes
             index_bytes=struct.unpack('<I',f.read(4))[0]
    
             
    
             #Iterate in Each Block
                     
             col=0        
                     
             for pixel_id in range(16):
                 index=index_bytes & 0b11
                 index_bytes=index_bytes>>2
                             
                 row=pixel_id % 4
                 if row==0:
                     col+=1
    
                 if index==0:
                     colorx=color0
                 elif index==1:
    
                     colorx=color1
                 elif index==2:
                     colorx=color3
                 else:
                     #print(index_data[pixel_id])
                     colorx=color4
                 
                             
                 
                 
                 img.putpixel((block_j+(row),block_i+col-1),colorx)
    
                 
    
                 
    
     #print(list(img.getdata()))            
    
     img.save('test.png')
    This piece of code works perfectly for DXT1 compressed textures, but for my piece of data does, it does not produce good results:

    Click image for larger version. 

Name:	apokleietai.png 
Views:	275 
Size:	39.0 KB 
ID:	2798

    This is the raw data i am attempting to read:
    https://www.dropbox.com/s/2p7qde7fs4aj12j/raw_200_200

    The relation between the data size and and the actual reffered pixels of the image is 1/2, which is the same compression ratio with dxt1 where we have 16 pixels in 8 bytes (1/2 byte per pixel).

    Could this be a modified dxt1 compression??? Or is it my code's problem?
    Last edited by gregkwaste; 29th March 2014 at 17:34.

  4. #4
    Member
    Join Date
    Nov 2013
    Location
    US
    Posts
    131
    Thanks
    31
    Thanked 29 Times in 19 Posts
    It might be DXT3 or 5.

    If you want to just load and view textures, make a simple viewer in OpenGL. You can upload the texture directly as raw bytes (what you have right now) in one of these formats: https://www.opengl.org/wiki/S3_Textu...tures_and_S3TC

    If you load like that, you don't have to make your own loader for every format, so it's easy to find out the format of a texture (the one that works). You can then use glGetTexImage to read out RGB8 and save it to a file: https://www.opengl.org/wiki/GlGetTexImage

  5. The Following User Says Thank You to cade For This Useful Post:

    gregkwaste (29th March 2014)

  6. #5
    Member
    Join Date
    Mar 2014
    Location
    Greece
    Posts
    10
    Thanks
    1
    Thanked 1 Time in 1 Post
    Quote Originally Posted by cade View Post
    It might be DXT3 or 5.

    If you want to just load and view textures, make a simple viewer in OpenGL. You can upload the texture directly as raw bytes (what you have right now) in one of these formats: https://www.opengl.org/wiki/S3_Textu...tures_and_S3TC

    If you load like that, you don't have to make your own loader for every format, so it's easy to find out the format of a texture (the one that works). You can then use glGetTexImage to read out RGB8 and save it to a file: https://www.opengl.org/wiki/GlGetTexImage
    If forgot to mention that i did write a simple loaded that uses those types in order to import compressed images in opengl. I still got the same results. The normal textures are looking good. The data i am interested in is not shown correctly. Basically it is shown exactly like the picture i showed you above.

    Btw it just figured out that the image description just LIES... While it states a 512 to 512 image, its actually a 256x512 image, and the data is the same assuming a dxt3 or 5 image and 1 mipmap...

    Japanese cunts...

  7. #6
    Member
    Join Date
    Nov 2013
    Location
    US
    Posts
    131
    Thanks
    31
    Thanked 29 Times in 19 Posts
    You might have found stride, which is the number of bytes between the start of one row and the next. Depending on the target hardware, textures can internally (within GL) occupy the nearest power of two size.

    DXT3 and 5 differ on how the alpha channels are stored. Mipmap generation is probably left until runtime, it's very cheap (with a box filter) and needs 33% more space.

  8. #7
    Member
    Join Date
    Mar 2014
    Location
    Greece
    Posts
    10
    Thanks
    1
    Thanked 1 Time in 1 Post
    Quote Originally Posted by cade View Post
    You might have found stride, which is the number of bytes between the start of one row and the next. Depending on the target hardware, textures can internally (within GL) occupy the nearest power of two size.

    DXT3 and 5 differ on how the alpha channels are stored. Mipmap generation is probably left until runtime, it's very cheap (with a box filter) and needs 33% more space.
    You are probably right... The image still does not show up correctly if i use dxt3 or dxt5. It could be indeed a stride inside the image, but i am struggling to apply that with opengl.

    I read somewhere that i need to use glPixelStorei(GL_UNPACK_ROW_LENGTH,stride) before using the glCompressedTexture2D command, but it does not seem to apply. Whatever value i put it has no impact on the image. :S:S
    Last edited by gregkwaste; 30th March 2014 at 13:32.

  9. #8
    Member
    Join Date
    Nov 2013
    Location
    US
    Posts
    131
    Thanks
    31
    Thanked 29 Times in 19 Posts
    Compressed texture images in this context are not DXT. DXT are fixed memory reductions that the GPU can natively used. These are meant to save GPU memory.

    Compressed texture images are dynamic and not immediately readable by the GPU, these are decompressed by the driver in memory. These are only to reduce storage on disk.

  10. #9
    Member
    Join Date
    Mar 2014
    Location
    Greece
    Posts
    10
    Thanks
    1
    Thanked 1 Time in 1 Post
    So there is no way that i'll be able to present them normaly via opengl?

  11. #10
    Member
    Join Date
    Nov 2013
    Location
    US
    Posts
    131
    Thanks
    31
    Thanked 29 Times in 19 Posts
    There are three possibilities:

    1) It is DXT/S3TC, 3Dc, another variant (all of which are GPU supported), or some custom variant unpacked in a shader. Since you tried this, this is probably not the case.

    2) It is one of the standard compressible formats that OpenGL recognizes. Those are listed here: https://www.opengl.org/wiki/Image_Fo...ressed_formats and can be simply loaded with glCompressedTexImage2D.

    3) It's custom (block-based? looks like it) compression. In this case, it is easier to view and save it from memory. I wrote an OpenGL debugger that supports viewing textures in memory which might help you: http://nauful.com/pages/gltrace.php

  12. #11
    Member
    Join Date
    Mar 2014
    Location
    Greece
    Posts
    10
    Thanks
    1
    Thanked 1 Time in 1 Post
    But what about the stride that you mentioned above? Is there nothing we can do about it through opengl?

    Its undoubtely something near the DXT/S3TC formats, the data is structured into blocks of 8 bytes. Can't be anything else.


    As for your tool. I assume that i need to debug the game in order to see what is loaded into memory uh?

  13. #12
    Member
    Join Date
    Nov 2013
    Location
    US
    Posts
    131
    Thanks
    31
    Thanked 29 Times in 19 Posts
    Quote Originally Posted by gregkwaste View Post
    But what about the stride that you mentioned above? Is there nothing we can do about it through opengl?
    You can try loading the image with different strides as multiples of the width, but it probably won't help. I mentioned it because that is what you might have read from the header instead of actual width and height.

    Quote Originally Posted by gregkwaste View Post
    Its undoubtely something near the DXT/S3TC formats, the data is structured into blocks of 8 bytes. Can't be anything else.
    Discrete cosine transform for JPEG and other block-based image transforms also work with blocks.

    Quote Originally Posted by gregkwaste View Post
    As for your tool. I assume that i need to debug the game in order to see what is loaded into memory uh?
    Correct.

  14. #13
    Member
    Join Date
    Mar 2014
    Location
    Greece
    Posts
    10
    Thanks
    1
    Thanked 1 Time in 1 Post
    Quote Originally Posted by cade View Post
    You can try loading the image with different strides as multiples of the width, but it probably won't help. I mentioned it because that is what you might have read from the header instead of actual width and height.


    Discrete cosine transform for JPEG and other block-based image transforms also work with blocks.


    Correct.

    It was an alternative compression method. As i mentioned above the file came from a Wii game. Developers tend to use an alternative compression format called CMPR. It is quite identical to the DXT1/BC1 compression, the only difference is they way that the 16 pixel blocks are stored.

    Thanks for your help mate. We narrowed it down eventually

  15. #14
    Member
    Join Date
    Nov 2013
    Location
    US
    Posts
    131
    Thanks
    31
    Thanked 29 Times in 19 Posts
    Interesting. The single isolated pixels (one per block) looked like the base offset for DCT/wavelet transforms.

  16. #15
    Member
    Join Date
    Mar 2014
    Location
    Greece
    Posts
    10
    Thanks
    1
    Thanked 1 Time in 1 Post
    Quote Originally Posted by cade View Post
    Interesting. The single isolated pixels (one per block) looked like the base offset for DCT/wavelet transforms.
    ? don't even want to think about it xD and btw aren't those transformations applied only in greyscale images?? :S:S

  17. #16
    Member
    Join Date
    Nov 2013
    Location
    US
    Posts
    131
    Thanks
    31
    Thanked 29 Times in 19 Posts
    Those can be applied for any channel in a coloured format (greyscale has 1 channel, RGB has 3, YUV has 3, etc). YUV or YCbCr would be the most common colour-spaces for image compression.

  18. #17
    Member
    Join Date
    Mar 2014
    Location
    Greece
    Posts
    10
    Thanks
    1
    Thanked 1 Time in 1 Post
    Quote Originally Posted by cade View Post
    Those can be applied for any channel in a coloured format (greyscale has 1 channel, RGB has 3, YUV has 3, etc). YUV or YCbCr would be the most common colour-spaces for image compression.
    I see. Is the decompression fast enough for the needs of a (console) game though?

  19. #18
    Member
    Join Date
    Nov 2013
    Location
    US
    Posts
    131
    Thanks
    31
    Thanked 29 Times in 19 Posts
    Yes, they are unpacked into CPU memory then uploaded onto the GPU into RGB8 or DXTn. Do you ever wonder why loading screens for games are so slow?

    Serious compressors (such as full wavelets instead of small blocks) are slower but get much better results compared to simpler ones (such as JPEG).

  20. #19
    Member
    Join Date
    Oct 2013
    Location
    Filling a much-needed gap in the literature
    Posts
    350
    Thanks
    177
    Thanked 49 Times in 35 Posts
    gregkwaste,

    I'm curious what texture that turned out to really be, properly uncompressed... could you post that picture, too? (And ideally an explanation of why it looked the way it did when you got it wrong, with the not-quite-perfect stripes and so on?)

    I do a lot of bottom-up data layout analysis, and that was an interesting image. (At first I thought you just had the basic raster stride wrong by a factor of 2, because it was a smallish image in the lower left quadrant of a larger format, and striped with black, but it's clearly not that, or not just that. Then I thought it was the DCT of some pixel-aligned texture with mostly close-to-a-power-of-2 rhythms, but it's not that either.)

  21. #20
    Member
    Join Date
    Mar 2014
    Location
    Greece
    Posts
    10
    Thanks
    1
    Thanked 1 Time in 1 Post
    Quote Originally Posted by Paul W. View Post
    gregkwaste,

    I'm curious what texture that turned out to really be, properly uncompressed... could you post that picture, too? (And ideally an explanation of why it looked the way it did when you got it wrong, with the not-quite-perfect stripes and so on?)

    I do a lot of bottom-up data layout analysis, and that was an interesting image. (At first I thought you just had the basic raster stride wrong by a factor of 2, because it was a smallish image in the lower left quadrant of a larger format, and striped with black, but it's clearly not that, or not just that. Then I thought it was the DCT of some pixel-aligned texture with mostly close-to-a-power-of-2 rhythms, but it's not that either.)

    Hi paul, your statements are exactly what i was thinking as well, and that is why i turned to opengl to manage to preview the image using dxt compressions or tweaking the image size and width and use an alternative dxt compression.

    Click image for larger version. 

Name:	apokleietai.png 
Views:	193 
Size:	28.0 KB 
ID:	2801

    This is how the image turned out, if you like i can post the python code as well. Just note that i made a huge mistake, i was unpacking the bytes with little endianness while i should have read big endians instead, so the color should be totally wrong in the first image :P If you want to do a proper comparison, just use the code i posted on the first post and change the endianess on the unpacks.

    In the CMPR format the color can be saved in many known formats (as read somewhere on the web). In this particular version the color is in RGB565. The color calculation and assignment is EXACTLY identical to DXT1 compression. 16 pixels per block and 4 bytes for indexing, the 2 additional colors are calculated with interpolation.

    The difference is that in CMPR format there are some subblocks introduced. Let me explain:

    In DXT format we divide the picture into 4x4 pixel blocks stored from row to row.

    In CMPR format we divide the picture first into 8x8 (64 pixel blocks) stored from row to row. Now for each 8x8 block we apply the dxt scheme. So in each of those blocks there are 4 4x4 blocks which we again read from row to row. Thats it :P
    Last edited by gregkwaste; 1st April 2014 at 01:37.

  22. The Following User Says Thank You to gregkwaste For This Useful Post:

    Paul W. (1st April 2014)

  23. #21
    Member
    Join Date
    Oct 2013
    Location
    Filling a much-needed gap in the literature
    Posts
    350
    Thanks
    177
    Thanked 49 Times in 35 Posts
    Thanks for the image & explanation.

Similar Threads

  1. Re: Useful compressed streaming properties
    By Shelwien in forum Data Compression
    Replies: 2
    Last Post: 2nd June 2012, 15:29
  2. Lossless compression formats using LZMA or LZMA2 ?
    By Karhunen in forum Data Compression
    Replies: 6
    Last Post: 3rd February 2012, 05:15
  3. Steganography for universal recompression of lossy formats
    By Shelwien in forum Data Compression
    Replies: 3
    Last Post: 7th November 2011, 18:05
  4. recommended formats for game data and partial updates
    By willvarfar in forum Data Compression
    Replies: 14
    Last Post: 23rd November 2010, 19:26
  5. Dealing with container formats
    By subwolf in forum Data Compression
    Replies: 16
    Last Post: 2nd September 2009, 22:14

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •