By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
459,576 Members | 1,360 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 459,576 IT Pros & Developers. It's quick & easy.

Howto Extract PNG from binary file @ 0x80?

P: n/a
Hi,

As a newbie to the language, I have no idea where to start..please bare
with me..

The simcity 4 savegame file has a png image stored at the hex location
0x80. What I want to extract it and create a file with the .png
extension in that directory.

Can somebody explain with a snippet of code how I would accomplish
this? I've looked around but the information is too vague and I don't
know how to start.

-thanks in advance

Jul 18 '05 #1
Share this Question
Share on Google+
7 Replies


P: n/a
"flamesrock" <mi******@telus.net> wrote:
As a newbie to the language, I have no idea where to start..please bare
with me..

The simcity 4 savegame file has a png image stored at the hex location
0x80. What I want to extract it and create a file with the .png
extension in that directory.

Can somebody explain with a snippet of code how I would accomplish
this? I've looked around but the information is too vague and I don't
know how to start.


there are *many* ways to ignore the first 128 bytes when you read a file
(you can seek to the right location, you can read 128 bytes and throw them
a way, you can read one byte 128 times and throw each one of them away,
you can read all data and remove the first 128 bytes, etc).

here's a snippet that understands the structure of the PNG, and stops copying
when it reaches the end of the PNG:

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

to use this, open the input file (the simcity file) and the output file
(the png file you want to create) in binary mode, use the "seek"
method to move to the right place in the simcity file, and call "pngcopy"
with the two file objects.

infile = open("mysimcityfile", "rb")
infile.seek(0x80)
outfile = open("myimage.png", "wb")
pngcopy(infile, outfile)
outfile.close()
infile.close()

hope this helps!

</F>

Jul 18 '05 #2

P: n/a
On Sat, 11 Dec 2004 10:53:19 +0100, Fredrik Lundh wrote:
"flamesrock" <mi******@telus.net> wrote:
As a newbie to the language, I have no idea where to start..please bare
with me..

The simcity 4 savegame file has a png image stored at the hex location
0x80. What I want to extract it and create a file with the .png
extension in that directory.

Can somebody explain with a snippet of code how I would accomplish
this? I've looked around but the information is too vague and I don't
know how to start.


there are *many* ways to ignore the first 128 bytes when you read a file
(you can seek to the right location, you can read 128 bytes and throw them
a way, you can read one byte 128 times and throw each one of them away,
you can read all data and remove the first 128 bytes, etc).

here's a snippet that understands the structure of the PNG, and stops copying
when it reaches the end of the PNG:

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

to use this, open the input file (the simcity file) and the output file
(the png file you want to create) in binary mode, use the "seek"
method to move to the right place in the simcity file, and call "pngcopy"
with the two file objects.

infile = open("mysimcityfile", "rb")
infile.seek(0x80)
outfile = open("myimage.png", "wb")
pngcopy(infile, outfile)
outfile.close()
infile.close()

hope this helps!

</F>


Thanks! And what a pleasant surprise! I just noticed you authored the book
I've been studying - Python Standard Library. Its awesome ;)

Oh- and Sorry for the late response. Google groups wouldn't allow me to
followup. I'm using pan now.

Jul 18 '05 #3

P: n/a
Well, I've been working on getting this code to work, and I think I
*almost* have it...

First, according to ghex, it seems the PNG starts at the 97th byte of
the file
infile = open("mysimcityfile.sc4", "rb")
infile.seek(97)
print (infile.read(4))
output:
flamesrock@flames:~/score$ python sc4png.py
PNG
(for 5 bytes it outputs an extra line, and for 6- 
(the biology symbol for a male)) So to debug further, I took out the
exception and modified the code like this:

#import struct
#
#def pngcopy(infile, outfile):
#
# # copy header
# header = infile.read(4)
# #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("mysimcityfile.sc4", "rb")
#infile.seek(97)
#outfile = open("myimage.png", "wb")
#pngcopy(infile, outfile)
#outfile.close()
#infile.close()

returning the following output:
flamesrock@flames:~/score$ python sc4png.py
Traceback (most recent call last):
File "sc4png.py", line 26, in ?
pngcopy(infile, outfile)
File "sc4png.py", line 14, in pngcopy
size, cid = struct.unpack("!l4s", chunk)
struct.error: unpack str size does not match format

Any ideas on how to fix it? If I understand this page correctly,
http://www.python.org/doc/current/li...le-struct.html
a png is basically a 'big endian string of 14 chars'? Changing it to
!14b" gives a"ValueError: unpack tuple of wrong size"
-thanks in advance for any help

Jul 18 '05 #4

P: n/a
flamesrock wrote:

[snip]
flamesrock@flames:~/score$ python sc4png.py
Traceback (most recent call last):
File "sc4png.py", line 26, in ?
pngcopy(infile, outfile)
File "sc4png.py", line 14, in pngcopy
size, cid = struct.unpack("!l4s", chunk)
struct.error: unpack str size does not match format

Any ideas on how to fix it? If I understand this page correctly,
http://www.python.org/doc/current/li...le-struct.html
a png is basically a 'big endian string of 14 chars'? Changing it to
!14b" gives a"ValueError: unpack tuple of wrong size"
-thanks in advance for any help


No, the chunk header is specified as "!l4s" where that second character
is a lower-case "L", not one "1". The struct is "a 4-byte long integer
in big-endian format followed by a 4-character string".

I think the error you are running into is that the chunk you are passing
in does not have 8 characters. Is your input truncated somehow?

--
Robert Kern
rk***@ucsd.edu

"In the fields of hell where the grass grows high
Are the graves of dreams allowed to die."
-- Richard Harter
Jul 18 '05 #5

P: n/a
Hmm...I'm not sure exactly. One of the things I've read is that
sometimes stuff is compressed in a savegame file, but I don't know why
they'd do that with a png..

I have some code that does the exact same thing in php only I don't
understand php syntax and how they did it. Does it give any clues as to
whether its truncated or not? (assuming you understand php)
http://simcitysphere.com/sc4Extractor.php.txt (original, only extracts
png)
http://simcitysphere.com/regionFileDecode_inc.php.txt (extracts png and
some fancy stuff like image map position)

-thanks

Jul 18 '05 #6

P: n/a
Don't seek to position 97. Seek to 96. You're off by one. That's why
there's the test for the header (which you removed).

Files (and Python strings for that matter) are 0-indexed. The first
character is 0, the second 1, and so on. If you want the 97th character,
you have to seek to position 96.

--
Robert Kern
rk***@ucsd.edu

"In the fields of hell where the grass grows high
Are the graves of dreams allowed to die."
-- Richard Harter
Jul 18 '05 #7

P: n/a
omg, it works!! thankyou!!!!!
and thankyou again, Frederick for the original code!

I've discovered a weird thing when changing header = infile.read(8) to
header = infile.read(4):
For some reason, the extracted png image is the exact same size as the
savegame archive (10.1 megs.) When reading 8bytes, its closer to
~200kb. Any clue as to why that is?

-thanks

#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("mysimcityfile.sc4", "rb")
#infile.seek(96)
###print (infile.read(4))
#outfile = open("myimage.png", "wb")
#pngcopy(infile, outfile)
#outfile.close()
#infile.close()

(http://simcitysphere.com/peachville.sc4)

Jul 18 '05 #8

This discussion thread is closed

Replies have been disabled for this discussion.