我是从这段代码工作,并考虑到评论,以“修复”32位,但它似乎仍然不起作用。我很确定这和TGA描述符有关。这将有位0-3作为阿尔法通道深度,这将始终是8的32位,而代码没有考虑到这一点。
我试着理解如何使用这个C代码作为向导将其拼凑在一起,但没有运气。
一旦考虑到像素长度为4(按照注释中的补丁程序),他的dwordize
只占4个字节中的3个,第4个字节是我认为的alpha位。
我尝试将函数更改为
function dwordize($str)
{
$a = ord($str[0]);
$b = ord($str[1]);
$c = ord($str[2]);
return $c*256*256 + $b*256 + $a;
}
至
function dwordize($str)
{
$a = ord($str[0]);
$b = ord($str[1]);
$c = ord($str[2]);
$d = ord($str[3]);
return $d*256*256*256 + $c*256*256 + $b*256 + $a;
}
不起作用,然后试着
function dwordize($str)
{
$a = ord($str[0]);
$b = ord($str[1]);
$c = ord($str[2]);
$d = ord($str[3]);
return $c*256*256 + $b*256 + $a + $d*256*256*256;
}
所有这些我都试图摆脱C代码,从RBGA到BGRA,然后所有的索引都很奇怪。我真的不太理解C代码,无法将它应用到PHP代码中。
我还找到了可能有帮助的本站,我现在正在阅读它,如果我想出什么,我会更新的。
发布于 2014-07-20 14:52:25
我已经找到你的解决办法了。需要对RLE解码函数进行调整,以支持32位像素格式:即:AARRGGBB
。
因此,首先,我们需要按照注释中的建议绕过库的颜色深度检查,所以我们将行的检查更改为这个
if ($header['pixel_size'] != 24 && $header['pixel_size'] != 32) {
die('Unsupported TGA color depth');
}
然后,我们需要改变一些变量,是颜色的深度相关。它们中的大多数将用于数据格式化,因此无论颜色深度如何,我们都需要它们具有正确的值。这将是:
104
$bytes = $header['pixel_size'] / 8;
117
$size = $header['width'] * $header['height'] * $bytes;
154
$pixels = str_split($data, $bytes);
删除行153
**:** $num_bytes = $header['pixel_size']/8;
我们不再需要它了。
然后,我们将需要rle_decode()
函数来知道像素的格式大小,因此在调用for
循环时,我们需要传递这个参数,因此我们还需要更改以下一行:
141
**:** 线 $data = rle_decode($data, $size, $bytes);
因此,函数原型转换为:
9
:线 function rle_decode($data, $datalen, $pixel_size)
现在您可以在这个函数上看到多个3
魔术数字(即第29行上的for ($j = 0; $j<3*$value; $j++)
)。所有这些都必须由像素大小参数替换。(3 for 24 bits
,4 for 32 bits
)
此外,在创建像素时,有时它只编写3字节,而不是4,因此我们也必须对此进行调整。
最后,这给出了以下算法:
function rle_decode($data, $datalen, $pixel_size)
{
$len = strlen($data);
$out = '';
$i = 0;
$k = 0;
while ($i<$len)
{
dec_bits(ord($data[$i]), $type, $value);
if ($k >= $datalen)
{
break;
}
$i++;
if ($type == 0) //raw
{
for ($j=0; $j<$pixel_size*$value; $j++)
{
$out .= $data[$j+$i];
$k++;
}
$i += $value*$pixel_size;
}
else //rle
{
for ($j=0; $j<$value; $j++)
{
$out .= $data[$i] . $data[$i+1] . $data[$i+2];
if ($pixel_size == 4) $out .= $data[$i+3];
$k++;
}
$i += $pixel_size;
}
}
return $out;
}
就是这样,您现在将得到您的TGA图像完美转换。我给您提供了完整的tga.php
代码,这样您就可以直接粘贴它并自行测试它:
<?php
// Author: de77
// Licence: MIT
// First-version: 9.02.2010
// Version: 24.08.2010
// http://de77.com
function rle_decode($data, $datalen, $pixel_size)
{
$len = strlen($data);
$out = '';
$i = 0;
$k = 0;
while ($i<$len)
{
dec_bits(ord($data[$i]), $type, $value);
if ($k >= $datalen)
{
break;
}
$i++;
if ($type == 0) //raw
{
for ($j=0; $j<$pixel_size*$value; $j++)
{
$out .= $data[$j+$i];
$k++;
}
$i += $value*$pixel_size;
}
else //rle
{
for ($j=0; $j<$value; $j++)
{
$out .= $data[$i] . $data[$i+1] . $data[$i+2];
if ($pixel_size == 4) $out .= $data[$i+3];
$k++;
}
$i += $pixel_size;
}
}
return $out;
}
function dec_bits($byte, &$type, &$value)
{
$type = ($byte & 0x80) >> 7;
$value = 1 + ($byte & 0x7F);
}
function getimagesizetga($filename)
{
$f = fopen($filename, 'rb');
$header = fread($f, 18);
$header = @unpack( "cimage_id_len/ccolor_map_type/cimage_type/vcolor_map_origin/vcolor_map_len/" .
"ccolor_map_entry_size/vx_origin/vy_origin/vwidth/vheight/" .
"cpixel_size/cdescriptor", $header);
fclose($f);
$types = array(0,1,2,3,9,10,11,32,33);
if (!in_array($header['image_type'], $types))
{
return array(0, 0, 0, 0, 0);
}
if ($header['pixel_size'] > 32)
{
return array(0, 0, 0, 0, 0);
}
return array($header['width'], $header['height'], 'tga', $header['pixel_size'], $header['image_type']);
}
function imagecreatefromtga($filename)
{
$f = fopen($filename, 'rb');
if (!$f)
{
return false;
}
$header = fread($f, 18);
$header = unpack( "cimage_id_len/ccolor_map_type/cimage_type/vcolor_map_origin/vcolor_map_len/" .
"ccolor_map_entry_size/vx_origin/vy_origin/vwidth/vheight/" .
"cpixel_size/cdescriptor", $header);
switch ($header['image_type'])
{
case 2: echo "Image is not compressed\n";//no palette, uncompressed
case 10: //no palette, rle
break;
default: die('Unsupported TGA format');
}
if ($header['pixel_size'] != 24 && $header['pixel_size'] != 32)
{
die('Unsupported TGA color depth');
}
$bytes = $header['pixel_size'] / 8;
if ($header['image_id_len'] > 0)
{
$header['image_id'] = fread($f, $header['image_id_len']);
}
else
{
$header['image_id'] = '';
}
$im = imagecreatetruecolor($header['width'], $header['height']);
$size = $header['width'] * $header['height'] * $bytes;
//-- check whether this is NEW TGA or not
$pos = ftell($f);
fseek($f, -26, SEEK_END);
$newtga = fread($f, 26);
if (substr($newtga, 8, 16) != 'TRUEVISION-XFILE')
{
$newtga = false;
}
fseek($f, 0, SEEK_END);
$datasize = ftell($f) - $pos;
if ($newtga)
{
$datasize -= 26;
}
fseek($f, $pos, SEEK_SET);
//-- end of check
$data = fread($f, $datasize);
if ($header['image_type'] == 10)
{
$data = rle_decode($data, $size, $bytes);
}
if (bit5($header['descriptor']) == 1)
{
$reverse = true;
}
else
{
$reverse = false;
}
$i = 0;
$pixels = str_split($data, $bytes);
//read pixels
if ($reverse)
{
for ($y=0; $y<$header['height']; $y++)
{
for ($x=0; $x<$header['width']; $x++)
{
imagesetpixel($im, $x, $y, dwordize($pixels[$i]));
$i++;
}
}
}
else
{
for ($y=$header['height']-1; $y>=0; $y--)
{
for ($x=0; $x<$header['width']; $x++)
{
imagesetpixel($im, $x, $y, dwordize($pixels[$i]));
$i++;
}
}
}
fclose($f);
return $im;
}
function dwordize($str)
{
$a = ord($str[0]);
$b = ord($str[1]);
$c = ord($str[2]);
return $c*256*256 + $b*256 + $a;
}
function bit5($x)
{
return ($x & 32) >> 5;
}
下面是直接从脚本创建的输出PNG
映像:
如果您更喜欢直接下载链接而不是粘贴固定代码,我在这里给您提供完整的php
文件:https://www.sendspace.com/file/92uir9
最后,只要更改tga.php
文件,一切都会自动工作。
发布于 2022-10-14 13:15:34
基于de77.com代码,但添加了一些内容:
<?php
// References:
// https://stackoverflow.com/questions/24709142/convert-32-bit-tga-to-png
// https://github.com/nothings/stb/blob/master/stb_image.h
// http://tfc.duke.free.fr/coding/tga_specs.pdf
// http://www.paulbourke.net/dataformats/tga/
//
// This class development started with the following code:
// http://de77.com/tga-imagetga-imagecreatefromtga
// Author: de77
// Licence: MIT
// First-version: 9.02.2010
// Version: 24.08.2010
// http://de77.com
//
// C.. oct 2022
// I put the code in a class,
// I added the color-mapped formats,
// I added the 15b & 16b pixel-size formats.
//
// The following is supported:
//
// Pixel-depths: 8b, 15b, 16b, 24b, 32b
//
// Image Type Description
// 0 No Image Data Included
// 1 Uncompressed, Color-mapped Image
// 2 Uncompressed, True-color Image
// 3 Uncompressed, Grayscale Image
// 9 Run-length encoded, Color-mapped Image
// 10 Run-length encoded, True-color Image
// 11 Run-length encoded, Grayscale Image
//
// NOTE: i commented out 16b-alpha code using: //!
// It does not work, and images come out all transparent.
class uje_tga_class {
private function rle_decode(&$data, $bytes) {
$out = '';
$i = 0;
$len = strlen($data);
while ($i<$len) {
$b = ord($data[$i]);
$type = ($b & 0x80);
$count = 1 + ($b & 0x7F);
$i++;
// raw or RLE
if ($type == 0) { //raw
$size = $bytes*$count;
$out .= substr($data, $i, $size);
$i += $size;
} else { //rle
$s = substr($data, $i, $bytes);
$out .= str_repeat($s, $count);
$i += $bytes;
}
}
return $out;
}
private function unmapcolors(&$data, $npixels, $colormapentrybytes, &$palette, $pixelbytes) {
$out = '';
for ($i=0, $i2=0; $i<$npixels; $i++, $i2+=$colormapentrybytes) {
$idx = ord($data[$i2]); // $colormapentrybytes == 1 or 2
if ($colormapentrybytes == 2) $idx += (ord($data[$i2+1]) << 8);
$idx *= $pixelbytes;
$out .= substr($palette, $idx, $pixelbytes);
}
return $out;
}
public function getimagesizetga($filename) {
$f = fopen($filename, 'rb');
$header = fread($f, 18);
$header = @unpack("cimage_id_len/ccolor_map_type/cimage_type/vcolor_map_origin/vcolor_map_len/" .
"ccolor_map_entry_size/vx_origin/vy_origin/vwidth/vheight/" .
"cpixel_size/cdescriptor", $header);
fclose($f);
$types = array(0,1,2,3,9,10,11,32,33);
if (!in_array($header['image_type'], $types)) return array(0, 0, 0, 0, 0);
if ($header['pixel_size'] > 32) return array(0, 0, 0, 0, 0);
return array($header['width'], $header['height'], 'tga', $header['pixel_size'], $header['image_type']);
}
public function imagecreatefromtga($filename) {
// open the TGA file for binary reading
$f = fopen($filename, 'rb');
if (!$f) return false;
// read the file
try {
// read the TGA header
$header = fread($f, 18);
$header = unpack("cimage_id_len/ccolor_map_type/cimage_type/" .
"vcolor_map_origin/vcolor_map_len/ccolor_map_entry_size/" .
"vx_origin/vy_origin/vwidth/vheight/" .
"cpixel_size/cdescriptor", $header);
// check for supported tga formats
switch ($header['image_type']) {
case 1: // color-mapped uncompressed
case 2: // truecolor uncompressed
case 3: // grayscale uncompressed
case 9: // color-mapped run-length encoded
case 10: // truecolor run-length encoded
case 11: // grayscale run-length encoded
break;
default:
throw new RuntimeException('Unsupported format: '. $header['image_type']);
}
$iscolormapped = ($header['image_type'] == 9 || $header['image_type'] == 1);
$isrle = ($header['image_type'] == 9 || $header['image_type'] == 10 || $header['image_type'] == 11);
// check for supported pixel sizes. ($header['pixel_size'])
// But if this is a colormapped image, that "pixel_size" is in fact the width of each entry in the colormap.
// For a colormapped image, the pixelsize is stored in $header['color_map_entry_size'].
if ($iscolormapped) {
if ($header['color_map_type'] == 0) {
throw new RuntimeException('Missing colormap');
}
$pixelbits = $header['color_map_entry_size'];
// the entries in the colormap can be 8 or 16 bit wide
$colormapentrybytes = $header['pixel_size']; // this is really the number of bits..
if (($colormapentrybytes != 8) && ($colormapentrybytes != 16)) {
throw new RuntimeException('Unsupported colormap entry bits: '. $colormapentrybytes);
}
$colormapentrybytes /= 8; // ..now it's bytes
} else {
$pixelbits = $header['pixel_size'];
}
switch ($pixelbits) {
case 8: // grayscale
$pixelbytes = 1;
break;
case 15: // truecolor 5b blue + 5b green + 5b red + 1b dummy
case 16: // truecolor 5b blue + 5b green + 5b red + 1b alpha
$pixelbytes = 2;
break;
case 24: // truecolor
$pixelbytes = 3;
break;
case 32: // truecolor
$pixelbytes = 4;
break;
default:
throw new RuntimeException('Unsupported pixel bits: '. $pixelbits);
}
// skip the image_id
$header['image_id'] = ($header['image_id_len'] > 0)? fread($f, $header['image_id_len']) : '';
// check whether this is a TGA v2.0
$tgav2 = true;
$pos = ftell($f); // store the current filepointer
fseek($f, -26, SEEK_END); // (possibly) read the file footer
$footer = fread($f, 26);
if (substr($footer, 8, 16) != 'TRUEVISION-XFILE') $tgav2 = false;
fseek($f, 0, SEEK_END);
$datasize = ftell($f) - $pos;
if ($tgav2) $datasize -= 26; // pixeldata does not include any footer
fseek($f, $pos, SEEK_SET); // restore filepointer
// if color-mapped then read the palette.
// The palette starts at the file-location where the image-data starts for the other formats.
// So first read the palette, and then correct the final datasize.
if ($iscolormapped) {
$palettesize = $header['color_map_len'] * $pixelbytes;
$pos = ftell($f) + $header['color_map_origin'];
fseek($f, $pos, SEEK_SET); // set filepointer to palette
$palette = fread($f, $palettesize);
$datasize -= $palettesize;
}
// Read the image data.
// If this is a colormapped image then this is not the pixeldata, but the indexes into the colormap.
$data = fread($f, $datasize);
} catch (Exception $e) {
//echo 'Exception: ', $e->getMessage(), "\n";
return false;
} finally {
fclose($f);
}
// get the pixeldata
if ($iscolormapped) {
$npixels = $header['width'] * $header['height'];
// colormapped images have the color-indexes encoded (pixeldata must be looked-up after RL decoding)
if ($isrle) $data = $this->rle_decode($data, $colormapentrybytes);
$pixeldata = $this->unmapcolors($data, $npixels, $colormapentrybytes, $palette, $pixelbytes);
} else
if ($isrle) { // possibly Run Length decode
$pixeldata = $this->rle_decode($data, $pixelbytes);
} else // uncompressed
$pixeldata = $data;
// create the image
$im = imagecreatetruecolor($header['width'], $header['height']);
// if the image has alpha data, then prepare for it
imagealphablending($im, false); // no blending. Just copy the pixel
//! if (!$iscolormapped && ($header['pixel_size'] == 32 || $header['pixel_size'] == 16)) {
if (!$iscolormapped && ($header['pixel_size'] == 32)) {
imagesavealpha($im, true); // be sure to save the alpha data
} else {
imagesavealpha($im, false);
}
// read pixel-ordering
$toptobottom = (($header['descriptor'] & 32) != 0);
$righttoleft = (($header['descriptor'] & 16) != 0);
// process the pixels
$i = 0;
for ($y=0; $y<$header['height']; $y++)
for ($x=0; $x<$header['width']; $x++) {
switch($pixelbytes) {
case 1:
$r = $g = $b = ord($pixeldata[$i]);
$col = imagecolorallocate($im, $r,$g,$b);
break;
case 2:
$r = (ord($pixeldata[$i+1]) & 0x7C) >> 2;
$g = ((ord($pixeldata[$i]) & 0xE0) >> 5) + ((ord($pixeldata[$i+1]) & 0x03) << 3);
$b = ord($pixeldata[$i]) & 0x1F;
$r <<= 3;
$g <<= 3;
$b <<= 3;
//! if ($header['pixel_size'] == 16) {
//! $a = ((ord($pixeldata[$i+1]) & 0x80) == 0)? 127 : 0; // 1b alpha means? transparent : opaque
//! $col = imagecolorallocatealpha($im, $r,$g,$b,$a);
//! } else {
$col = imagecolorallocate($im, $r,$g,$b);
//! }
break;
case 3:
$r = ord($pixeldata[$i+2]);
$g = ord($pixeldata[$i+1]);
$b = ord($pixeldata[$i]);
$col = imagecolorallocate($im, $r,$g,$b);
break;
case 4:
$r = ord($pixeldata[$i+2]);
$g = ord($pixeldata[$i+1]);
$b = ord($pixeldata[$i]);
$a = 127 - (ord($pixeldata[$i+3]) >> 1); // 128 alpha values with png transulency (where 127 = transparent, 0 = opaque)
$col = imagecolorallocatealpha($im, $r,$g,$b,$a);
break;
}
// set the pixel in the image
$xp = ($righttoleft)? $header['width'] - 1 - $x : $x;
$yp = ($toptobottom)? $y : $header['height'] - 1 - $y;
imagesetpixel($im, $xp, $yp, $col);
// next pixel in the pixeldata
$i += $pixelbytes;
}
return $im;
}
public function imagetga($im, $filename) {
list($width, $height) = array(imagesx($im), imagesy($im));
$tga = "\0\0\2\0\0\0\0\0\0\0\0\0" . pack('vv', $width, $height) . ' ';
for ($y=0; $y<$height; $y++)
for ($x=0; $x<$width; $x++) {
$rgb = imagecolorat($im, $x, $y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
$a = ($rgb >> 24) & 0x7F;
$tga .= chr($b).chr($g).chr($r).chr((127-$a)*2);
}
file_put_contents($filename, $tga);
}
public function tga2png($tga_filename, $png_filename) {
$im = $this->imagecreatefromtga($tga_filename);
if (!$im) return false;
//header('Content-Disposition: Attachment;filename=image.png');
//header("Content-type: image/png");
imagepng($im, $png_filename);
imagedestroy($im);
return true;
}
}
?>
https://stackoverflow.com/questions/24709142
复制相似问题