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
<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 = '';
$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($fileHex, 0, 8), 2, " ", true);
$timType = wordwrap(substr($fileHex, 8, 8), 2, " ", true);
// CLUT HEADER
$CLUTLength = wordwrap(substr($fileHex, 16, 8), 2, " ", true);
$PalX = wordwrap(substr($fileHex, 24, 4), 2, " ", true);
$PalY = wordwrap(substr($fileHex, 28, 4), 2, " ", true);
$NumColors = wordwrap(substr($fileHex, 32, 4), 2, " ", true);
$NumCLUTs = wordwrap(substr($fileHex, 36, 4), 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, $offset, 4), 2, " ", true);
$offset += 4;
}
//}
// IMAGE HEADER
$IMGLength = wordwrap(substr($fileHex, $offset, 8), 2, " ", true);
$IMGX = wordwrap(substr($fileHex, $offset + 8, 4), 2, " ", true);
$IMGY = wordwrap(substr($fileHex, $offset + 12, 4), 2, " ", true);
$Pitch = wordwrap(substr($fileHex, $offset + 16, 4), 2, " ", true);
$Height = wordwrap(substr($fileHex, $offset + 20, 4), 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($colorBin, 0, 1);
$b5 = substr($colorBin, 1, 5);
$g5 = substr($colorBin, 6, 5);
$r5 = substr($colorBin, 11, 5);
$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 = '#' . $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 ' -> ' . "\n";
$colorBin = hexbin($colorLE);
echo $colorBin;
echo ' -> ' . "\n";
echo getRGB($colorBin, $x);
echo '<br />' . "\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 '<table border="0" cellpadding="0" cellspacing="0"><tr>' ."\n";
$count = 0;
for($i = 0; $i < $RawLength; $i++){
$IMGRaw = substr($fileHex, $offset, 2);
$offset += 2;
$picked = hexdec($IMGRaw);
echo '<td style="background-color: ' . $Palette[$picked] . ';><img src="spacer.gif" border="0" height="1" width="1" /></td>' . "\n";
$count++;
if($count == $Width){
echo '</tr></tr>' ."\n";
$count = 0;
}
}
echo '</tr></table>';
?>
</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