Author Topic: TIM files for those starting out  (Read 5149 times)

scmark15

  • *
  • Posts: 9
    • View Profile
TIM files for those starting out
« on: 2010-05-08 02:39:52 »
Here is some notes I made using a hex editor and playing around...
Code: [Select]
Everything below is from this 4x4 pixel image with 4 colors (Red, Green, Blue & White)...

+-------+-------+-------+-------+
|  Red  |  Red  | Green | Green |
+-------+-------+-------+-------+
|  Red  |  Red  | Green | Green |
+-------+-------+-------+-------+
|  Blue |  Blue | White | White |
+-------+-------+-------+-------+
|  Blue |  Blue | White | White |
+-------+-------+-------+-------+


--------- 4-Bit TIM (Paletted)-------------

-- HEADER ---------------------------------
  Format:  10 00 00 00  TIM Magic
  BPP:     08 00 00 00  4bpp

-- CLUT DATA HEADER------------------------
  Length:  2C 00 00 00  44 bytes (32 bytes/palette + 12 bytes for this header)
  palX:    00 00        0px
  palY:    00 00        0px
  colr#:   10 00        16 (Always 16)
  #CLUT:   01 00        1 CLUT

-- CLUT - 2 byte (ABGR[1555] Color) little endian-------
   HEX  ->  HEX  -> BINARY              -> COLOR -> COLOR-REF
   LE   ->  BE   -> A BBBBB GGGGG RRRRR ->   -   ->     -
  -----------------------------------------------------------
  1F 00 -> 00 1F -> 0 00000 00000 11111 -> RED   -> 0000
  E0 03 -> 03 E0 -> 0 00000 11111 00000 -> GREEN -> 0001
  00 7C -> 7C 00 -> 0 11111 00000 00000 -> BLUE  -> 0010
  FF 7F -> 7F FF -> 0 11111 11111 11111 -> WHITE -> 0100

  There is only 4 Colors in palette rest is "Black" padding -> 00 00
    00 00 -> 0 00000 00000 00000 -> BLACK -> 1000
    00 00 -> 0 00000 00000 00000 -> BLACK -> 1001
    00 00 -> 0 00000 00000 00000 -> BLACK -> 1010
  ...repeat until this CLUT is a total of 32 bytes/16 color entries (last index: 00 00 -> 0 00000 00000 00000 -> BLACK -> 1111)

  (Example: We only have 4 colors so there will be 24 bytes of padding or
            "00 00" 12 times (PADDING: 00 00 -> 0 00000 00000 00000 -> BLACK --> XXXX)

-- IMAGE HEADER ---------------------------
  Length:  14 00 00 00  20 bytes (1 byte for each 2 pixel set + 12 bytes for this header)
  Hres:    C0 03        960
  Vres:    00 00        0
  Width:   01 00        4px (multiplied by 4 to get actual)
  Height:  04 00        4px

-- IMAGE DATA (Like 8-bit TIM, REFERENCED, only 4 bits instead of 8 bits)----------------
  HEX -> BINARY    -> PX2Cr | PX1Cr
      -> px2  px1  ->   -   |   -
  ------------------------------------------------
  00  -> 0000 0000 -> RED   | RED
  11  -> 0001 0001 -> GREEN | GREEN

  00  -> 0000 0000 -> RED   | RED
  11  -> 0001 0001 -> GREEN | GREEN

  22  -> 0010 0010 -> BLUE  | BLUE
  33  -> 0100 0100 -> WHITE | WHITE

  22  -> 0010 0010 -> BLUE  | BLUE
  33  -> 0100 0100 -> WHITE | WHITE


  Read 2 pixels at a time but second pixel is output'd first (ie right to left)
    1st byte...
      1st 4-bit set -> 2nd pixel
      2nd 4-bit set -> 1st pixel

    2nd byte...
      3rd 4-bit set -> 4th pixel
      4th 4-bit set -> 3rd pixel

    3rd byte...
      5th 4-bit set -> 6th pixel
      6th 4-bit set -> 5th pixel

    4th byte...
      7th 4-bit set -> 8th pixel
      8th 4-bit set -> 7th pixel

    Visual Example (4 x 2 px image):
    +-------+-------+-------+-------+
    |  2nd  |  1st  |  4th  |  3rd  |
    +-------+-------+-------+-------+
    |  6th  |  5th  |  8th  |  7th  |
    +-------+-------+-------+-------+

  So... 00 -> Output is: RED   | RED
        11 -> Output is: GREEN | GREEN
        01 -> Output is: GREEN | RED
        10 -> Output is: RED   | GREEN
         ^-- RED is 0 and GREEN is 1

IMAGE (1 CLUT):
+-------+-------+-------+-------+
|  Red  |  Red  | Green | Green |
+-------+-------+-------+-------+
|  Red  |  Red  | Green | Green |
+-------+-------+-------+-------+
|  Blue |  Blue | White | White |
+-------+-------+-------+-------+
|  Blue |  Blue | White | White |
+-------+-------+-------+-------+


====================================================================
--------- 8-Bit TIM (Paletted)-------------

-- HEADER ---------------------------------
  Format:  10 00 00 00  TIM Magic
  BPP:     09 00 00 00  8bpp

-- CLUT DATA HEADER------------------------
  Length:  0C 02 00 00  524 bytes (512 bytes/palette + 12 bytes for this header)
  palX:    00 00        0px
  palY:    00 00        0px
  colr#:   00 01        256 (Always 256)
  #CLUT:   01 00        1 CLUT

-- CLUT - 2 byte (ABGR[1555] Color) little endian -------
  *Each CLUT or Color LookUp Table is 256 colors or 512 bytes
  
   HEX  ->  HEX  -> BINARY              -> COLOR -> COLOR-REF
   LE   ->  BE   -> A BBBBB GGGGG RRRRR ->   -   ->     -
  ------------------------------------------------------------
  1F 00 -> 00 1F -> 0 00000 00000 11111 -> RED   -> color00
  E0 03 -> 03 E0 -> 0 00000 11111 00000 -> GREEN -> color01
  00 7C -> 7C 00 -> 0 11111 00000 00000 -> BLUE  -> color02
  FF 7F -> 7F FF -> 0 11111 11111 11111 -> WHITE -> color03

  There is only 4 Colors in palette rest is "Black" padding -> 00 00 ...
    00 00 -> 0 00000 00000 00000 -> BLACK -> color04
    00 00 -> 0 00000 00000 00000 -> BLACK -> color05
  ...repeat until this CLUT is a total of 512 bytes/256 color entries

  (Example: We only have 4 colors so there will be 504 bytes of padding or
            "00 00" 252 times (PADDING: 00 00 -> 0 00000 00000 00000 -> BLACK -> colorXX)

-- IMAGE HEADER ---------------------------
  Length:  1C 00 00 00  28 bytes (1 byte for each pixel + 12 bytes for this header)
  Hres:    C0 03        960
  Vres:    00 00        0
  Width:   02 00        4px (multiplied by 2 to get actual)
  Height:  04 00        4px

-- IMAGE DATA (Just like paletted BMP, REFERENCE each color from CLUT) --
 HEX -> REF     -> COLOR
 -----------------------
  00 -> color00 -> RED
  00 -> color00 -> RED
  01 -> color01 -> GREEN
  01 -> color01 -> GREEN

  00 -> color00 -> RED
  00 -> color00 -> RED
  01 -> color01 -> GREEN
  01 -> color01 -> GREEN

  02 -> color02 -> BLUE
  02 -> color02 -> BLUE
  03 -> color03 -> WHITE
  03 -> color03 -> WHITE

  02 -> color02 -> BLUE
  02 -> color02 -> BLUE
  03 -> color03 -> WHITE
  03 -> color03 -> WHITE

IMAGE (1 CLUT):
+-------+-------+-------+-------+
|  Red  |  Red  | Green | Green |
+-------+-------+-------+-------+
|  Red  |  Red  | Green | Green |
+-------+-------+-------+-------+
|  Blue |  Blue | White | White |
+-------+-------+-------+-------+
|  Blue |  Blue | White | White |
+-------+-------+-------+-------+


====================================================================
------- 16-Bit TIM (NO CLUT DATA)----------

-- HEADER ---------------------------------
  Format:  10 00 00 00  TIM Magic
  BPP:     02 00 00 00  16bpp

-- IMAGE DATA HEADER-----------------------
  Length:  2C 00 00 00  44 bytes (2 bytes for each pixel + 12 bytes for this header)
  Hres:    C0 03        960
  Vres:    00 00        0
  Width:   04 00        4px
  Height:  04 00        4px

-- RAW IMAGE DATA - 2 byte (ABGR[1555] Color) little endian-------
   HEX  ->  HEX  -> BINARY              -> COLOR
   LE   ->  BE   -> A BBBBB GGGGG RRRRR ->   -
  -----------------------------------------------
  1F 00 -> 00 1F -> 0 00000 00000 11111 -> RED
  1F 00 -> 00 1F -> 0 00000 00000 11111 -> RED
  E0 03 -> 03 E0 -> 0 00000 11111 00000 -> GREEN
  E0 03 -> 03 E0 -> 0 00000 11111 00000 -> GREEN

  1F 00 -> 00 1F -> 0 00000 00000 11111 -> RED
  1F 00 -> 00 1F -> 0 00000 00000 11111 -> RED
  E0 03 -> 03 E0 -> 0 00000 11111 00000 -> GREEN
  E0 03 -> 03 E0 -> 0 00000 11111 00000 -> GREEN

  00 7C -> 7C 00 -> 0 11111 00000 00000 -> BLUE
  00 7C -> 7C 00 -> 0 11111 00000 00000 -> BLUE
  FF 7F -> 7F FF -> 0 11111 11111 11111 -> WHITE
  FF 7F -> 7F FF -> 0 11111 11111 11111 -> WHITE

  00 7C -> 7C 00 -> 0 11111 00000 00000 -> BLUE
  00 7C -> 7C 00 -> 0 11111 00000 00000 -> BLUE
  FF 7F -> 7F FF -> 0 11111 11111 11111 -> WHITE
  FF 7F -> 7F FF -> 0 11111 11111 11111 -> WHITE

IMAGE:
+-------+-------+-------+-------+
|  Red  |  Red  | Green | Green |
+-------+-------+-------+-------+
|  Red  |  Red  | Green | Green |
+-------+-------+-------+-------+
|  Blue |  Blue | White | White |
+-------+-------+-------+-------+
|  Blue |  Blue | White | White |
+-------+-------+-------+-------+


====================================================================  
-------- 24-Bit TIM (NO CLUT DATA)---------
 NOTE: Some TIM programs don't support 24-bit TIMs
       Example...Yu_Ri doesn't but TIM viewer does

-- HEADER ---------------------------------
  Format:  10 00 00 00  TIM Magic
  BPP:     03 00 00 00  24bpp

-- IMAGE DATA HEADER ----------------------
  Length:  3C 00 00 00  60 bytes (3 bytes for each pixel + 12 bytes for this header)
  Hres:    C0 03        960
  Vres:    00 00        0
  Width:   06 00        4px (Divided by 1.5 to get actual)
  Height:  04 00        4px

-- RAW IMAGE DATA - 3 byte RGB[888] big endian ----
  HEX      -> COLOR
  RR GG BB ->   -
  -----------------
  FF 00 00 -> Red
  FF 00 00 -> Red
  00 FF 00 -> Green
  00 FF 00 -> Green

  FF 00 00 -> Red
  FF 00 00 -> Red
  00 FF 00 -> Green
  00 FF 00 -> Green

  00 00 FF -> Blue
  00 00 FF -> Blue
  FF FF FF -> White
  FF FF FF -> White

  00 00 FF -> Blue
  00 00 FF -> Blue
  FF FF FF -> White
  FF FF FF -> White

IMAGE:
+-------+-------+-------+-------+
|  Red  |  Red  | Green | Green |
+-------+-------+-------+-------+
|  Red  |  Red  | Green | Green |
+-------+-------+-------+-------+
|  Blue |  Blue | White | White |
+-------+-------+-------+-------+
|  Blue |  Blue | White | White |
+-------+-------+-------+-------+


Updated: for those who just wanna copy and paste to have a copy (see my next post to see what was fixed)
« Last Edit: 2010-05-17 11:06:22 by scmark15 »

m35

  • *
  • Posts: 52
    • View Profile
    • jPSXdec
Re: TIM files for those starting out
« Reply #1 on: 2010-05-08 04:58:36 »
Thanks for this. Perhaps some of it can be merged with the documentation on the wiki? Also, I don't notice anything about TIMs with an odd width. I included some handling for that case in my (currently unused) library, but haven't ever tested it.

scmark15

  • *
  • Posts: 9
    • View Profile
Re: TIM files for those starting out
« Reply #2 on: 2010-05-08 11:46:07 »
:o I forgot to note that you have to change the hex in the CLUT/Raw Image Data (4, 8 & 16 bit palettes)  to Big Endian before converting it to binary to get A BBBBB GGGGG RRRRR
because its stored in Little Endian as GGG RRRRR A BBBBB GG. :-D

Code: [Select]
For example... Little Endian 1F 00 (Binary: 000 11111 0 00000 00) -> Big Endian: 00 1F  (Binary: 0 00000 00000 11111)
this will output pure red.

Code: [Select]
   HEX  ->  HEX  -> BINARY              -> COLOR -> COLOR-REF
   LE   ->  BE   -> A BBBBB GGGGG RRRRR ->   -   ->     -
  -----------------------------------------------------------
  1F 00 -> 00 1F -> 0 00000 00000 11111 -> RED   -> 0000
  E0 03 -> 03 E0 -> 0 00000 11111 00000 -> GREEN -> 0001
  00 7C -> 7C 00 -> 0 11111 00000 00000 -> BLUE  -> 0010
  FF 7F -> 7F FF -> 0 11111 11111 11111 -> WHITE -> 0011

I just thought people who didn't know anything or not enough about TIM files might enjoy this so I thought I'd share.
I only used a 4x4 image with 4 colors because it was easier to figure out then a smaller image and a bigger image had
too much to sort through. As for odd pixeled images I think I tried once and I couldn't get it to display, maybe because of
the CLUT data, or BPP I tried... I can't remember, I'll have to look into that ^_^

Please note: that these are my notes and may not be 100% correct...so if anyone could or wants to add/update
these notes please do so and share with the community, especially me... could always use some more info & feedback.

Oh, and if they want to add some of these notes to the wiki I have no problem with that at all.

Peace,
scmark15
<[email protected]>
« Last Edit: 2010-05-08 12:07:15 by scmark15 »

scmark15

  • *
  • Posts: 9
    • View Profile
Re: TIM files for those starting out
« Reply #3 on: 2010-05-08 11:57:23 »
I'm always forgetting to mention something ^_^

If anyone wants a copy of Yu_Ri 0.99e in english drop me an email at <[email protected]>
just make sure to add "NEED YU_RI" as the Subject or I won't read it.

Yu_Ri is a TIM, BMP extractor... it searches through big and small files for images.
It will take a multi CLUT TIM and open an image for each CLUT to view as well as save/multi-save
to BMP or TIFF. Version 0.99e includes GIF and JPEG ripping plugins.

Yu_Ri 0.99e is the last version of yu_ri released and is hard to find most websites only
have version 0.99c. I translated 90% of it to english for personal use but I'm willing to share ^_^

-later

« Last Edit: 2010-05-08 12:11:42 by scmark15 »

scmark15

  • *
  • Posts: 9
    • View Profile
Re: TIM files for those starting out
« Reply #4 on: 2010-05-21 22:37:58 »
I wanted to see if this could be done....

I made a TIM reader using PHP. It only works for 8bpp images with only 1 CLUT...for now anyway. I got it to work with the FF7 character faces in the psx versions "MENU" folder.

Test Requirements:
-PHP 5 (this is what I used)
-IIS or Apache Server running PHP
-A copy of FF7 for PSX
-A 1x1 GIF image thats completely transparent (must be named "spacer.gif")
            - place it in the same folder as the php script.
            - (its for drawing a table to display the TIM)
 -A copy of the script below
            - Copy it to notepad and save it as TIMReader.php
Code: [Select]
<html>
<head>
  <title></title>
  <style>
    <!--
      body {
       margin:      10px;
       padding:     0px;
       font-family: courier new;
       font-size:   11px;
      }
    -->
  </style>
</head>
<body>
<?php
$file 
"test.tim";
// Dummy out file
$fileHex = &#39;&#39;;

$handle fopen($file"rb") or die("Error: Check your permissions");
while(!
feof($handle)){
  foreach(
unpack("C*"fgets($handle)) as $dec){
    
$tmp dechex($dec);
    
$fileHex .= strtoupper(str_repeat("0"2-strlen($tmp)) . $tmp);
  }
}
fclose($handle);

function 
hexbin($str_hex) {
  
$str_bin FALSE;
  for (
$i=0$i strlen($str_hex); $i++) {
    
$str_bin .= sprintf("%04s"decbin(hexdec($str_hex[$i])));
  }
  return 
$str_bin;
}
// FILE HEADER
//                          file, offset, numchar
$timMagic wordwrap(substr($fileHex08), 2" "true);
$timType  wordwrap(substr($fileHex88), 2" "true);
// CLUT HEADER
$CLUTLength wordwrap(substr($fileHex168), 2" "true);
$PalX       wordwrap(substr($fileHex244), 2" "true);
$PalY       wordwrap(substr($fileHex284), 2" "true);
$NumColors  wordwrap(substr($fileHex324), 2" "true);
$NumCLUTs   wordwrap(substr($fileHex364), 2" "true);
// CLUT DATA ~~~~ offsex starts at 40
$offset 40;
//for($i = 0; $i < $NumCLUTs; $i++){
  
for($i 0$i 256$i++){
    
$colorArray[] = wordwrap(substr($fileHex$offset4), 2" "true);
    
$offset += 4;
  }
//}
// IMAGE HEADER
$IMGLength wordwrap(substr($fileHex$offset8), 2" "true);
$IMGX      wordwrap(substr($fileHex$offset 84), 2" "true);
$IMGY      wordwrap(substr($fileHex$offset 124), 2" "true);
$Pitch     wordwrap(substr($fileHex$offset 164), 2" "true);
$Height    wordwrap(substr($fileHex$offset 204), 2" "true);

// Fix Offset for the next block;
$offset += 24;

// OUTPUT
echo "TIM Header: " $timMagic "<br />" "\n";
echo 
"TIM Type: " $timType "<br />" "\n";
echo 
"<br />" ."\n";
echo 
"CLUT Length: " $CLUTLength "<br />" "\n";
echo 
"PalX: " $PalX "<br />" "\n";
echo 
"PalY: " $PalY "<br />" "\n";
echo 
"# of Colors: " $NumColors "<br />" "\n";
echo 
"# of CLUTs: " $NumCLUTs "<br />" "\n";
echo 
"<br />" ."\n";
$x 0;

// BGR[1555] to RGB[888]
function getRGB($colorBin$int){
  global 
$Palette;

  
$a1 substr($colorBin01);
  
$b5 substr($colorBin15);
  
$g5 substr($colorBin65);
  
$r5 substr($colorBin115);

  
$alphadec bindec($a1);
  
$bluedec bindec($b5);
  
$greendec bindec($g5);
  
$reddec bindec($r5);

  
$a8 $alphadec 8;
  
// Older BGR[1555] to RGB[888] Conversion
  // (Output is slightly darker)
  // $r8 = $reddec * 8;
  // $g8 = $greendec * 8;
  // $b8 = $bluedec * 8;

  // New BGR[1555] to RGB[888] Conversion
  // (Output is slightly brighter)
  
$r8 round(($reddec 8) + ($reddec 31 7));
  
$g8 round(($greendec 8) + ($greendec 31 7));
  
$b8 round(($bluedec 8) + ($bluedec 31 7));

  
// Alpha is ignored
  // $RGBAlpha = strtoupper(str_repeat("0", 2-strlen(dechex($a8))) . dechex($a8));
  
$RGBRed   strtoupper(str_repeat("0"2-strlen(dechex($r8))) . dechex($r8));
  
$RGBGreen strtoupper(str_repeat("0"2-strlen(dechex($g8))) . dechex($g8));
  
$RGBBlue  strtoupper(str_repeat("0"2-strlen(dechex($b8))) . dechex($b8));

  
$RGB = &#39;#&#39; . $RGBRed . $RGBGreen . $RGBBlue;
  
$Palette[$int] = $RGB;
  return 
$RGB;
}

foreach(
$colorArray as $color){
  
$tmp explode(" "$color);
  
$colorLE $tmp[1] . $tmp[0];
  unset(
$tmp);
  echo 
"Color " strtoupper(str_repeat("0"2-strlen(dechex($x))) . dechex($x)) . ": " $color "\n";
  echo &
#39; -> &#39; . "\n";
  
$colorBin hexbin($colorLE);
  echo 
$colorBin;
  echo &
#39; -> &#39; . "\n";
  
echo getRGB($colorBin$x);
  echo &
#39;<br />&#39; . "\n";
  
$x++;
}
echo 
"<br />" ."\n";
echo 
"IMG Length: " $IMGLength "<br />" "\n";
echo 
"IMGX: " $IMGX "<br />" "\n";
echo 
"IMGY: " $IMGY "<br />" "\n";
echo 
"Pitch: " $Pitch "<br />" "\n";
echo 
"Height: " $Height "<br />" "\n";
echo 
"<br />" ."\n";

$tmp explode(" "$Pitch);
$Pitch $tmp[1] . $tmp[0];
$Width hexdec($Pitch) * 2;
unset(
$tmp);
$tmp explode(" "$Height);
$tHeight $tmp[1] . $tmp[0];
$High hexdec($tHeight);
$RawLength $High $Width;
echo &
#39;<table border="0" cellpadding="0" cellspacing="0"><tr>&#39; ."\n";
$count 0;
for(
$i 0$i $RawLength$i++){
  
$IMGRaw substr($fileHex$offset2);
  
$offset += 2;
  
$picked hexdec($IMGRaw);
  echo &
#39;<td style="background-color: &#39; . $Palette[$picked] . &#39;;><img src="spacer.gif" border="0" height="1" width="1" /></td>&#39; . "\n";
  
$count++;
  if(
$count == $Width){
    echo &
#39;</tr></tr>&#39; ."\n";
    
$count 0;
  }
}
echo &
#39;</tr></table>&#39;;
?>

</body>
</html>

To use: copy the TIM file to the same folder as the script and rename it to "test.tim"
Run the script to see if it worked.

This is only a work in progress, so I appologize for my messy code (I wasn't trying to impress ^_^)
I hope to add functionality to work with Multi-CLUT tims as well as 4, 16 & 24 bpp also.

SCMark15

P.S.
Any feedback or comments are welcome anytime. I need to know if this worked for you, or what
other files you tried it out on. I'll update this when I have more time to play around with it.

-later
« Last Edit: 2010-05-21 22:40:18 by scmark15 »