View TIM files with PHP? ...done it, see how

  • Thread starter Thread starter scmark15
  • Start date Start date
Status
Not open for further replies.
S

scmark15

Guest
Okay for those who read my "TIM files for those starting out" (https://www.ff7catalog.com/threads/6560/)
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)

Code: [Select]
Code:
<html><head>  <title>TIM Viewer</title>  <style>    <!--      body, table, tr, td{        font-family: courier new;        font-size:   11px;      }    -->  </style></head><body><?phpif(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 . '
' . "\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 . '
' . "\n";echo '
';if($timType == 0x08 || $timType == 0x09){  echo '<b>CLUT Header</b><br />' . "\n";  echo 'CLUT Size:   ' . $clutLength . ' Bytes
' . "\n";  echo 'H. Res:      ' . $clutX . '
' . "\n";  echo 'V. Res:      ' . $clutY . '
' . "\n";  echo '# of Colors: ' . $colorNum . '
' . "\n";  echo '# of CLUTS:  ' . $clutCount . '
' . "\n";  echo '
' . "\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 '
' . "\n";}echo '<b>Image Header</b><br />' . "\n";echo 'Image Size: ' . $imgLength . ' Bytes
' . "\n";echo 'Org. X:     ' . $imgX . '
' . "\n";echo 'Org. Y:     ' . $imgY . '
' . "\n";echo 'Width:      ' . $imgWidth . 'px
' . "\n";echo 'Height:     ' . $imgHeight . 'px
' . "\n";echo '
' . "\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
 
Last edited:
Status
Not open for further replies.
Back
Top