Okay for those who read my "TIM files for those starting out" (
http://forums.qhimm.com/index.php?topic=9754.0)
thread my last post had a sample code to use PHP to read 8 bit TIM files. I decided this should have its own thread because
this thread isn't about how TIM files store there data but how to view them using PHP.
What you need to begin:
-IIS or Apache Server running PHP 5
-A copy of the script below (Just copy & paste it to notepad and save it as TIMViewer.php)
-A few TIM files (must be copied to the same directory as the TIMViewer.php script)
<html>
<head>
<title>TIM Viewer</title>
<style>
<!--
body, table, tr, td{
font-family: courier new;
font-size: 11px;
}
-->
</style>
</head>
<body>
<?php
if(isset($_GET['file'])){
$infile = $_GET['file'];
}else{
die("Error: no file selected");
}
$curCLUT = 1;
if(isset($_GET['clut'])){
$curCLUT = $_GET['clut'];
}
$handle = fopen($infile, 'rb');
//
// HEX => CONVERT => BINARY
//
function hexbin($strHex) {
$strBin = '';
for($i = 0; $i < strlen($strHex); $i++){
$strBin .= sprintf("%04s", decbin(hexdec($strHex[$i])));
}
return $strBin;
}
//
// ABGR[1555] => CONVERT => RGB[888]
//
function getRGB($color){
$colorBin = hexbin(str_repeat("0", 4 - strlen(dechex($color))) . dechex($color));
$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;
return $RGB;
}
//
// FILE HEADER
//
$data = unpack("V2", fread($handle, 8));
$timMagic = '0x' . dechex($data[1]);
$timType = '0x0' . $data[2];
unset($data);
if($timType == 0x08 || $timType == 0x09){
//
// CLUT HEADER
//
$data = unpack('Vlong/v4short', fread($handle, 12));
$clutLength = $data['long'];
$clutX = $data['short1'];
$clutY = $data['short2'];
$colorNum = $data['short3'];
$clutCount = $data['short4'];
unset($data);
//
// CLUT DATA
//
for($x = 1; $x <= $clutCount; $x++){
for($i = 1; $i <= $colorNum; $i++){
$data = unpack('v', fread($handle, 2));
$clutData[$x][$i] = getRGB($data[1]);
}
}
unset($data);
}
//
// IMAGE HEADER
//
$data = unpack('Vlong/v4short', fread($handle, 12));
$imgLength = $data['long'];
$imgX = $data['short1'];
$imgY = $data['short2'];
$imgPitch = $data['short3'];
$imgHeight = $data['short4'];
unset($data);
//
// IMAGE WIDTH FIX
//
if($timType == 0x08){
$imgWidth = $imgPitch * 4;
$imgArea = ($imgPitch * 2) * $imgHeight;
}else if($timType == 0x09){
$imgWidth = $imgPitch * 2;
$imgArea = $imgWidth * $imgHeight;
}else if($timType == 0x02){
$imgWidth = $imgPitch;
$imgArea = $imgWidth * $imgHeight;
}else if($timType == 0x03){
$imgWidth = $imgPitch / 1.5;
$imgArea = $imgWidth * $imgHeight;
}
//
// File Info
//
echo '<h3>File Info</h3>' . "\n";
echo 'TIM Header: ' . $timMagic . '<br/>' . "\n";
if($timType == 0x08){
$bpp = '4bpp';
}else if($timType == 0x09){
$bpp = '8bpp';
}else if($timType == 0x02){
$bpp = '16bpp';
}else if($timType == 0x03){
$bpp = '24bpp';
}
echo 'TIM Type: ' . $timType . ' => ' . $bpp . '<br/>' . "\n";
echo '<br/>';
if($timType == 0x08 || $timType == 0x09){
echo '<b>CLUT Header</b><br />' . "\n";
echo 'CLUT Size: ' . $clutLength . ' Bytes<br/>' . "\n";
echo 'H. Res: ' . $clutX . '<br/>' . "\n";
echo 'V. Res: ' . $clutY . '<br/>' . "\n";
echo '# of Colors: ' . $colorNum . '<br/>' . "\n";
echo '# of CLUTS: ' . $clutCount . '<br/>' . "\n";
echo '<br/>' . "\n";
echo '<b>CLUT (Color Look-Up Table)</b><br />' . "\n";
echo '<table border="0" cellpadding="0" cellspacing="2"><tr>' . "\n";
$count = 0;
for($i = 1; $i <= $colorNum; $i++){
$color = $clutData[$curCLUT][$i];
echo '<td style="border: #000000 1px solid; background-color: #' . $color . '; height: 16px; text-align: center; width: 16px;"> </td>' . "\n";
$count++;
if($count == 4 && $colorNum == 16){
echo '</tr><tr>' . "\n";
$count = 0;
}else if($count == 16 && $colorNum == 256){
echo '</tr><tr>' . "\n";
$count = 0;
}
}
echo '</tr></table>' . "\n";
echo '<br/>' . "\n";
}
echo '<b>Image Header</b><br />' . "\n";
echo 'Image Size: ' . $imgLength . ' Bytes<br/>' . "\n";
echo 'Org. X: ' . $imgX . '<br/>' . "\n";
echo 'Org. Y: ' . $imgY . '<br/>' . "\n";
echo 'Width: ' . $imgWidth . 'px<br/>' . "\n";
echo 'Height: ' . $imgHeight . 'px<br/>' . "\n";
echo '<br/>' . "\n";
echo '<h3>Output</h3>' . "\n";
echo '<table border="0" cellpadding="0" cellspacing="0" height="' . $imgHeight . '" width="' . $imgWidth . '"><tr>' . "\n";
if($timType == 0x08 || $timType == 0x09){
$count = 0;
for($i = 1; $i <= $imgArea; $i++){
if($timType == 0x08){
$buff = fread($handle, 1);
$data = unpack('h', $buff);
$highNibble = hexdec($data[1]) + 1;
unset($data);
$data = unpack('H', $buff);
$lowNibble = hexdec($data[1]) + 1;
unset($data);
$count++;
echo '<td style="background-color: #' . $clutData[$curCLUT][$highNibble] .'"></td>' . "\n";
$count++;
echo '<td style="background-color: #' . $clutData[$curCLUT][$lowNibble] .'"></td>' . "\n";
}else if($timType == 0x09){
$buff = fread($handle, 1);
$data = unpack('C', $buff);
$picked = $data[1] + 1;
unset($data);
$count++;
echo '<td style="background-color: #' . $clutData[$curCLUT][$picked] .'"></td>' . "\n";
}
if($count == $imgWidth){
$count = 0;
echo '</tr><tr>' . "\n";
}
}
echo '</tr></table>' . "\n";
}else if($timType == 0x02){
$count = 0;
for($i = 1; $i <= $imgArea; $i++){
$data = unpack('v', fread($handle, 2));
$rawData = getRGB($data[1]);
unset($data);
$count++;
echo '<td style="background-color: #' . $rawData . '"></td>' . "\n";
if($count == $imgWidth){
$count = 0;
echo '</tr><tr>' . "\n";
}
}
}else if($timType == 0x03){
$count = 0;
for($i = 1; $i <= $imgArea; $i++){
$data = unpack('C3', fread($handle, 3));
$rawData = strtoupper(str_repeat("0", 2 - strlen(dechex($data[1]))) . dechex($data[1])) .
strtoupper(str_repeat("0", 2 - strlen(dechex($data[2]))) . dechex($data[2])) .
strtoupper(str_repeat("0", 2 - strlen(dechex($data[3]))) . dechex($data[3]));
unset($data);
$count++;
echo '<td style="background-color: #' . $rawData . '"></td>' . "\n";
$rawData = '';
if($count == $imgWidth){
$count = 0;
echo '</tr><tr>' . "\n";
}
}
}else{
die("Error: Invalid TIM file");
}
echo '</tr></table>' . "\n";
fclose($handle);
?>
</body>
</html>
Usage:
Open your browser and type in the address of the script ie. "localhost/TIMViewer.php?file=tim.tim"
Where "tim.tim" is change it to the file name of your TIM file.
If the file is a 4 bit or an 8 bit TIM add "&clut=x" (x is which clut you wish to use to view the image, default is 1)
=> "localhost/TIMViewer.php?file=mytim.tim&clut=1" (this would view the image with the 1st clut from the mytim.tim file)
Notes:
-This is not the most efficient coding or fastest loading but it does work.
-Big TIM files might take a long time to load.
-This script is writen purely by me and can be edited freely (Please post your updated code if you modify)
-Script does not show image as any graphic file (it's actually a table <= maybe why it's slow loading)
Tested with:
- Works with FF6 character faces (4bpp)
- Works with FF7 character faces (8bpp)
- Works with FF9 game over screen (16bpp)
- Works with adobe TIM plugin for all bpp (used to test 24bpp)
----------------------------------------------------------------------------------------------------------
-Enjoy
SCMark15