[Tutor] Extracting a PNG Image File from a Binary File..
Aaron Elbaz
flamesrock at gmail.com
Mon Jan 3 11:33:30 CET 2005
Hi,
My question is sort of on the difficult side, but I promise I'm a newb
;) So maybe it isn't..
Frederick Lundh himself gave me this chunk of code..and I can't get it
to work. I was hoping someone could spot the error.
The goal is to extract a png image file from a binary simcity 4 file.
#import struct
#
#def pngcopy(infile, outfile):
#
# # copy header
# header = infile.read(8)
# if header != "\211PNG\r\n\032\n":
# raise IOError("not a valid PNG file")
# outfile.write(header)
#
# # copy chunks, until IEND
# while 1:
# chunk = infile.read(8)
# size, cid = struct.unpack("!l4s", chunk)
# outfile.write(chunk)
# outfile.write(infile.read(size))
# outfile.write(infile.read(4)) # checksum
# if cid == "IEND":
# break
#
#infile = open("/home/flamesrock/Desktop/peachville.sc4", "rb")
#infile.seek(0x50)
#outfile = open("myimage.png", "wb")
#pngcopy(infile, outfile)
#outfile.close()
#infile.close()
It returns the IO error when I try it on this and other files:
http://simcitysphere.com/peachville.sc4
I've confirmed the position using a hex editor (its the first 'P' or
0x50 in the file)
http://simcitysphere.com/peachville.png
The idea comes from this php code which works -if only I could
understand how to translate it. The code may or may not also extract
data which denotes a relative position on an image map:
also available at http://simcitysphere.com/regionFileDecode_inc.php.txt
<?php
function fileDecode($inbuf, $Cname)
{
/* length of data */
$inlen=strlen($inbuf);
$outlen = unpack1($inbuf[6],'C') << 16;
$outlen += unpack1($inbuf[7],'C') << 8;
$outlen += unpack1($inbuf[8],'C');
/* position in file */
$inpos=9;
$outpos=0;
$outbuf =array();
while (($inpos<$inlen)&&(unpack1($inbuf[$inpos],'C')<0xFC))
{
$packcode=$inbuf[$inpos];
$packcode=unpack1($packcode,'C');
$a=unpack1($inbuf[$inpos+1],'C');
$b=unpack1($inbuf[$inpos+2],'C');
//decho("inlen: {$inlen} | outlen: {$outlen} | inpos: {$inpos} |
outpos: {$outpos} | packcode: $packcode");
if (!($packcode&0x80)) {
//decho('match 0x80');
$lena=$packcode&3;
mmemcpy($outbuf,$outpos,$inbuf,$inpos+2,$lena);
$inpos+=$lena+2;
$outpos+=$lena;
$lenb=(($packcode&0x1c)>>2)+3;
$offset=(($packcode>>5)<<8)+$a+1;
mmemcpy($outbuf,$outpos,$outbuf,$outpos-$offset,$lenb);
$outpos+=$lenb;
//decho ("Code $packcode len plain: $lena len: $lenb offset:
$offset outpos: $outpos");
}
else if (!($packcode&0x40)) {
//decho('match 0x40');
$lena=($a>>6)&3;
mmemcpy($outbuf,$outpos,$inbuf,$inpos+3,$lena);
$inpos+=$lena+3;
$outpos+=$lena;
$lenb=($packcode&0x3f)+4;
$offset=($a&0x3f)*256+$b+1;
mmemcpy($outbuf,$outpos,$outbuf,$outpos-$offset,$lenb);
$outpos+=$lenb;
//decho ("Code $packcode len plain: $lena len: $lenb offset:
$offset outpos: $outpos");
}
else if (!($packcode&0x20)) {
//decho('match 0x20');
$c=unpack1($inbuf[$inpos+3],'C');
$lena=$packcode&3;
mmemcpy($outbuf,$outpos,$inbuf,$inpos+4,$lena);
$inpos+=$lena+4;
$outpos+=$lena;
$lenb=(($packcode>>2)&3)*256+$c+5;
$offset=(($packcode&0x10)<<12)+256*$a+$b+1;
mmemcpy($outbuf,$outpos,$outbuf,$outpos-$offset,$lenb);
$outpos+=$lenb;
//decho ("Code $packcode len plain: $lena len: $lenb offset:
$offset outpos: $outpos");
}
else {
//decho('match 0x1f');
$len=($packcode&0x1f)*4+4;
mmemcpy($outbuf,$outpos,$inbuf,$inpos+1,$len);
$inpos+=$len+1;
$outpos+=$len;
//decho ("Code $packcode Plain Chars: $len outpos: $outpos");
//Code 224 Plain Chars: 4 outpos: 0
}
}
/* trailing bytes
if (($inpos<$inlen)&&($outpos<$outlen)) {
mmemcpy($outbuf,$outpos,$inbuf,$inpos+1,unpack1($inbuf[$inpos],'C')&3);
$outpos+=unpack1($inbuf[$inpos],'C')&3;
}
*/
/*
if ($outpos!=$outlen)
decho("Warning: bad length ? {$outpos} instead of {$outlen} with
{$Cname}");
*/
$buflen=$outlen;
return $outbuf;
}
function mmemcpy(&$dest, $destpos, &$src, $srcpos, $len)
{
while ($len--)
{
//decho ("destpos: $destpos | srcpos: {$src[$srcpos]}");
$dest[$destpos] = $src[$srcpos];
$destpos++;
$srcpos++;
}
}
function unpack1($bytes, $type=false)
{
if($type)
{
$dat = unpack("{$type}int",$bytes);
return $dat['int'];
} else {
$dat = unpack('Vint',$bytes);
return $dat['int'];
}
}
?>
ANY replies are welcome. Even if you don't know the answer, something
to point me in the right direction would be greatly appreciated. I'm
completely stuck.
-thanks
More information about the Tutor
mailing list