Convert 32-bit TGA to PNG

I work from this code and taking into account the comments to “fix” it for 32-bit, but it seems to Work. I am sure this is due to the TGA descriptor . This will be bit 0-3 as the depth of the alpha channel, which will always be 8 for 32 bits, and the code does not take this into account.

I tried to figure out how to build it using this C code as a guide, but no luck.

It seems that when you take into account that a pixel has a length of 4 (according to the patch in the comments), dwordizeonly 3 of 4 bytes take it into account, and the 4th byte is the alpha bits that I think.

I tried changing the function from

function dwordize($str)
{
    $a = ord($str[0]);
    $b = ord($str[1]);
    $c = ord($str[2]);
    return $c*256*256 + $b*256 + $a;
}

to

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;
}

which did not work and then tried

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-.

, , , -, .

+4
1

. RLE- 32- : i.e: AARRGGBB

, , , 99

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(), , int for, , , :

141: $data = rle_decode($data, $size, $bytes);

:

9: function rle_decode($data, $datalen, $pixel_size)

, 3 (i.e: for ($j = 0; $j<3*$value; $j++) 29). . ( 3 24 bits 4 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, script: Eyebrows PNG output

, , php: https://www.sendspace.com/file/92uir9

tga.php, .

+3

Source: https://habr.com/ru/post/1548160/


All Articles