Gå til innhold

[forespørsel] Script som leser format


Anbefalte innlegg

Hei, vet ikke om det er lov å komme med slike forespørsler, men det gjenstår vel bare å se?

 

Har et spesielt format, SPR, som består av bitmaps med en fargeindeks. Jeg trenger et script som kan lese en mappe, ta for seg en og en fil av typen .spr, hente ut første BMP lagret og lagre dette i en separat mappe.

 

Så har det seg slik at jeg har funnet et gammelt script som leser en og en fil av formatet, men dumper alle rammene som en HTML-fil med hver pixel som en <span> med bakgrunnsfarge.

 

Det jeg ber om er at noen kan skrive scriptet om slik det altså lagrer det første bildet som BMP i en undermappe, og muligheten for å kunne massedumping ved å spesifisere en mappe til SPR-filene.

 

Informasjon om formatet:

 


magic 	 2 	 int16 	 'PS', magic identifier 	
minor_ver 	1 	int8 	Minor version 	
major_ver 	1 	int8 	Major version 	
num_pal_imgs 	2 	int16 	Number of palette images 	
num_flat_imgs 	2 	int16 	Number of flat images 	present in version > 1.1
{ 	* 	array 	pal images 	
pal_image 	* 	uint8 	pal image 	RLE encoded in version 2.1+
} 				
{ 	* 	array 	flat images 	
flat_image 	* 	uint8 	flat image 	present in version 2.0+
} 				
palette 	256*4 	int32 	Palette 	present in version 1.1+ (seek to end - 1024)

 

Scriptet:

 

#file to read SPR format files
#read the file name off of the command line
my $TargetFile=shift||die "No target SPR file specified.\n";
my @temp=split("\\x5C", $TargetFile);
my $TargetFileName=$temp[-1]; #pull off the file name

#see if it exists
if (!stat($TargetFile)) {die "The SPR file '$TargetFile' does not exist.\n";}

#open the input file and and output file
open(FHI, $TargetFile) or die "Unable to read from target file '$TargetFile'.\n";
open(FHO, ">".$TargetFileName.".html") or die "Unable to create output file.\n";

#create the initial HTML page header and style section
print FHO "<html>\n";
print FHO "<head>\n";
print FHO "<style>\n";
print FHO "TT {\n";
print FHO "	font-size: 8pt;\n";
print FHO "}\n";
print FHO "</style>\n";
print FHO "</head>\n";
print FHO "<body>\n";

my @PaletteArray;
my @FrameArray;
my %FrameHash;

#start reading the data in
my $FileHeader=ReadFileBytes(2);
my $FileMajorVersion=unpack("C1", ReadFileBytes(1));
my $FileMinorVersion=unpack("C1", ReadFileBytes(1));
my $ImageCount=unpack("C4", ReadFileBytes(4));

print FHO "<h1>$TargetFileName</h1>\n";

print "File                ".$TargetFileName."\n";
print "Header              ".$FileHeader."\n";
print "Major version       ".$FileMajorVersion."\n";
print "Minor version       ".$FileMinorVersion."\n";
print "Image count         ".$ImageCount." frames\n";

print FHO "Header: ".$FileHeader."<br>\n";
print FHO "Major version: ".$FileMajorVersion."<br>\n";
print FHO "Minor version: ".$FileMinorVersion."<br>\n";
print FHO "Image count: ".$ImageCount." frames<br>\n";

#read the graphic section of the sprite
for my $FrameNum (0..$ImageCount-1) {
   #need to read the size data in backwards
   #I'm sure there's a better way to do this, but this was faster than looking for the correct method
   my $HB;
   my $LB;

   $LB=ReadFileBytes(1);
   $HB=ReadFileBytes(1);
   my $ImageX=hex(unpack("H4", $HB.$LB)); #88

   $LB=ReadFileBytes(1);
   $HB=ReadFileBytes(1);
   my $ImageY=hex(unpack("H4", $HB.$LB)); #86

   $LB=ReadFileBytes(1);
   $HB=ReadFileBytes(1);
   my $ImageLength=hex(unpack("H4", $HB.$LB)); #7568?

   my $ImageData=ReadFileBytes($ImageLength);
   #     "--------------------"
   print "\n";
   print "Image #".$FrameNum."\n";
   print "Image X             ".$ImageX."\n";
   print "Image Y             ".$ImageY."\n";
   print "Data Length         ".$ImageLength."\n";

   #compression runs from left to right in 2 char pairs
   #when palette "00" is encountered, next byte is count of pixels to repeat the "00" color unless -
   #    the next byte is also "00", then it is just a simple bit and the next byte is NOT a count
   #only the background color 00 is ever compressed (and sometimes it is not compressed)
   #compression can wrap to the next line

   my @SpriteFramePixelArrary;
   my $DataIndex=0;
   my $RawData="";

   #walk the length of the array
   while ($DataIndex<$ImageLength) {
       my $temp="";
       my $BitLength=1;
       my $Bit=unpack("H2", substr($ImageData, $DataIndex, 1));
       #check for the background bit to be set
       if ($Bit eq "00") {
           $DataIndex++;
           $BitLength=hex(unpack("H2", substr($ImageData, $DataIndex, 1)));
           #is it compressed data?
           if ($BitLength==0) {
               #nope, not compressed data, reset the bit length
               $BitLength=1;
               $DataIndex--; #Oops, uncompressed data, go backwards 1 byte since we looked ahead
           } #end uncompressed data chack if
       } #end background bit check if

       #now uncompress the data into a temp array
       for my $subindex (1..$BitLength) {push(@SpriteFramePixelArrary, $Bit); $temp.=$Bit." ";}
       #print $temp;

       $RawData.=$Bit." ";
       $DataIndex++;
   } #end for

   #this is just for the command line, we don't really need to show this
   print "Raw Data:\n";
   print $RawData."\n";

   #put the data into a hash so we can get at it later
   $FrameHash{$FrameNum}->{X}=$ImageX;
   $FrameHash{$FrameNum}->{Y}=$ImageY;
   @{$FrameHash{$FrameNum}->{DATA}}=@SpriteFramePixelArrary;
} #end frames for


#read the pallette info here
my $PaletteData=ReadFileBytes(1024); #allways the same size

#now make a nice color chart in a 16 x 16 grid
#in case you were wondering, the first color in the palette is the transparancy color for all the frames
print FHO "<h1>Palette data</h1>\n";
print FHO "Format: Palette#-RRGGBB (red green blue)<br>\n";
my $IndexLocation=0;
my $IndexNum=0;
for my $XIndex (1..16) {
   for my $YIndex (1..16) {
       #dig out the color values in 4 byte chunks
       my $RGBChunk=substr($PaletteData, $IndexLocation, 4);
       my $Red=uc(unpack("H2", substr($RGBChunk, 0, 1)));
       my $Green=uc(unpack("H2", substr($RGBChunk, 1, 1)));
       my $Blue=uc(unpack("H2", substr($RGBChunk, 2, 1)));
       my $Trans=unpack("H2", substr($RGBChunk, 3, 1)); #we don't care about this value
       print FHO "<span style=\"background-color: #$Red$Green$Blue;\"><tt>".uc(sprintf("%02x", $IndexNum))."-$Red$Green$Blue</tt></span> ";
       $IndexLocation=$IndexLocation+4;
       $IndexNum++;
       push(@PaletteArray, "$Red$Green$Blue"); #add it into an array for later
   } #end Y for
   print FHO "<br>\n";
} #end X for


#now make some nice color HTML pictures of the sprite data we worked on earlier now that we know the colors
#why HTML? because I'm too lazy to add GD module code here.
for my $FrameNum (0..$ImageCount-1) {
#@SpriteFramePixelArrary
   print FHO "<h1>Frame ".($FrameNum+1)."</h1>\n";
   print FHO "Size: ".$FrameHash{$FrameNum}->{X}." x ".$FrameHash{$FrameNum}->{Y}."<br>\n";
   my $IndexLocation=0;
   for my $YIndex (1..$FrameHash{$FrameNum}->{Y}) {
       for my $XIndex (1..$FrameHash{$FrameNum}->{X}) {
           my $ColorPaletteIndex=hex($FrameHash{$FrameNum}->{DATA}[$IndexLocation]);
           print FHO "<span style=\"background-color: #".$PaletteArray[$ColorPaletteIndex]."\"><tt>".uc($FrameHash{$FrameNum}->{DATA}[$IndexLocation])."</tt></span> ";
           $IndexLocation++;
       } #end Y for
       print FHO "<br>\n";
   } #end X for
} #end second frame for
print FHO "<br>\n";

print FHO "</body>\n";
print FHO "</html>\n";

close(FHO);
close(FHI);
print "All done.\n";
exit;


# ---------- Subs go here ----------

sub ReadFileBytes {
my $BytesToRead=shift||return 0;
my $DataRead;
sysread(FHI, $DataRead, $BytesToRead);
return $DataRead;
}

__END__

 

Aner ikke hvor mye arbeid dette vil ta, så si ifra om jeg ber om alt for mye. ;)

Lenke til kommentar
Videoannonse
Annonse

Heisann, hadde litt for mye ledig tid og såg litt på .bmp formatet. Modifiserte vedlagte script slik at det nå dumper ut .spr som .BMP.

Om du ønsker å konvertere flere .spr filer i en fei, foreslår jeg at du piper dir/ls output til "perl -ne" og således kjører en batch jobb.

 

#!/usr/bin/perl

use strict;
$| = 1;

#file to read SPR format files
#read the file name off of the command line
my $TargetFile=shift||die "No target SPR file specified.\n";

my @temp=split("\\x5C", $TargetFile);
my $TargetFileName=$temp[-1]; #pull off the file name

#see if it exists
if (!stat($TargetFile)) {die "The SPR file '$TargetFile' does not exist.\n";}

#open the input file and and output file
open(FHI, "<", $TargetFile) or die "Unable to read from target file '$TargetFile'.\n";
open(OUT, ">", $TargetFileName.".bmp") or die "Unable to create output file.\n";
binmode OUT;

my @PaletteArray;
my @FrameArray;
my %FrameHash;

#start reading the data in
my $FileHeader=ReadFileBytes(2);
my $FileMajorVersion=unpack("C1", ReadFileBytes(1));
my $FileMinorVersion=unpack("C1", ReadFileBytes(1));
my $ImageCount=unpack("C4", ReadFileBytes(4));

print "File				".$TargetFileName."\n";
print "Header			  ".$FileHeader."\n";
print "Major version	   ".$FileMajorVersion."\n";
print "Minor version	   ".$FileMinorVersion."\n";
print "Image count		 ".$ImageCount." frames\n";

#read the graphic section of the sprite
for my $FrameNum (0..$ImageCount-1) {
	#need to read the size data in backwards
	#I'm sure there's a better way to do this, but this was faster than looking for the correct method
	my $HB;
	my $LB;

	$LB=ReadFileBytes(1);
	$HB=ReadFileBytes(1);
	my $ImageX=hex(unpack("H4", $HB.$LB)); #88

	$LB=ReadFileBytes(1);
	$HB=ReadFileBytes(1);
	my $ImageY=hex(unpack("H4", $HB.$LB)); #86

	$LB=ReadFileBytes(1);
	$HB=ReadFileBytes(1);
	my $ImageLength=hex(unpack("H4", $HB.$LB)); #7568?

	my $ImageData=ReadFileBytes($ImageLength);
	#	 "--------------------"
	print "\n";
	print "Image #".$FrameNum."\n";
	print "Image X			 ".$ImageX."\n";
	print "Image Y			 ".$ImageY."\n";
	print "Data Length		 ".$ImageLength."\n";

	#compression runs from left to right in 2 char pairs
	#when palette "00" is encountered, next byte is count of pixels to repeat the "00" color unless -
	#	the next byte is also "00", then it is just a simple bit and the next byte is NOT a count
	#only the background color 00 is ever compressed (and sometimes it is not compressed)
	#compression can wrap to the next line

	my @SpriteFramePixelArrary;
	my $DataIndex=0;
	my $RawData="";

	#walk the length of the array
	while ($DataIndex<$ImageLength) {
		my $temp="";
		my $BitLength=1;
		my $Bit=unpack("H2", substr($ImageData, $DataIndex, 1));
		#check for the background bit to be set
		if ($Bit eq "00") {
			$DataIndex++;
			$BitLength=hex(unpack("H2", substr($ImageData, $DataIndex, 1)));
			#is it compressed data?
			if ($BitLength==0) {
				#nope, not compressed data, reset the bit length
				$BitLength=1;
				$DataIndex--; #Oops, uncompressed data, go backwards 1 byte since we looked ahead
			} #end uncompressed data chack if
		} #end background bit check if

		#now uncompress the data into a temp array
		for my $subindex (1..$BitLength) {
			push(@SpriteFramePixelArrary, $Bit); 
			$temp.=$Bit." ";
		}
		#print $temp;

		$RawData.=$Bit." ";
		$DataIndex++;
	} #end for

	#put the data into a hash so we can get at it later
	$FrameHash{$FrameNum}->{X}=$ImageX;
	$FrameHash{$FrameNum}->{Y}=$ImageY;
	@{$FrameHash{$FrameNum}->{DATA}}=@SpriteFramePixelArrary;

	#
} #end frames for

#read the pallette info here
my $PaletteData=ReadFileBytes(1024); #allways the same size

#now make a nice color chart in a 16 x 16 grid
#in case you were wondering, the first color in the palette is the transparancy 
#color for all the frames
my $IndexLocation=0;
my $IndexNum=0;
for my $XIndex (1..16) {
	for my $YIndex (1..16) {
		#dig out the color values in 4 byte chunks
		my $RGBChunk=substr($PaletteData, $IndexLocation, 4);
		my $Red=uc(unpack("H2", substr($RGBChunk, 0, 1)));
		my $Green=uc(unpack("H2", substr($RGBChunk, 1, 1)));
		my $Blue=uc(unpack("H2", substr($RGBChunk, 2, 1)));
		my $Trans=unpack("H2", substr($RGBChunk, 3, 1)); #we don't care about this value
		$IndexLocation=$IndexLocation+4;
		$IndexNum++;
		push(@PaletteArray, "$Red$Green$Blue"); #add it into an array for later
	} #end Y for
} #end X for


#
#
#Generate BMP header and dump in color table and image data
#
#
	#which frame to convert  
my $frameNr = 0;
	#image data  
my @imgData = @{$FrameHash{$frameNr}{DATA}};
	#width
my $sizeX = $FrameHash{$frameNr}->{X};
	#height
my $sizeY = $FrameHash{$frameNr}->{Y};
my $rowSize = $sizeX;
	#Each row of bitmap data contains multiple of 4 bytes.		
	#Find minimum row size.
while ($rowSize % 4) {
	$rowSize++;
}
	#size headers + size color table + size image data
my $totalSizeBMPFile = (14 + 40) + (256*4) + ($rowSize*$sizeY);
my $offsetToBitData = $totalSizeBMPFile - ($rowSize*$sizeY);
print "\ntotalsize:", $totalSizeBMPFile;
select OUT;

	#1.structure BITMAPFILEHEADER
	#---------------------------
print "BM";
print pack ("I", $totalSizeBMPFile);
print pack ("S", 0);
print pack ("S", 0);
print pack ("I", $offsetToBitData);	

	#2.structure BITMAPINFOHEADER
	#----------------------------
	#size of this struct
print pack ("I", 40);
	#width
print pack ("I", $sizeX);
	#height
print pack ("I", $sizeY);
	#biplanes
print pack ("S", 1);
	#color bits pr pixel. 256 colors => 1 color byte (8bits) pr pixel
print pack ("S", 8);
	#Add some padding to make header 40 bytes
print pack ("I6", 0);	

	#3.structure RGBQUAD (color table)
	#---------------------------------
for my $pal (@PaletteArray) {
	my @palBytes = ($pal)=~/(..)/g;
		#Hm, had to experiment bit here to find right order..
		#red
	print pack ("H2", $palBytes[2]);
		#green
	print pack ("H2", $palBytes[1]);
		#blue
	print pack ("H2", $palBytes[0]);
		#rgbreserved
	print pack ("H2",0);
} 

	#4.dump out image data. Last row comes first.
	#---------------------------
my $c = ($sizeX*$sizeY) - $sizeX;
for (my $row = 0; $row < $sizeY; $row++) {
	for (my $col = 0; $col < $sizeX; $col++) {
		print pack ("H2", $imgData[$c]);
		$c++;
	}
	$c = $c - ($sizeX*2);

		#Padding for each row
	for (1..($rowSize - $sizeX)) {
		print pack ("H2", 0);
	}
}
print STDOUT "\nDONE";		 

# ---------- Subs go here ----------

sub ReadFileBytes {
my $BytesToRead=shift||return 0;
my $DataRead;
sysread(FHI, $DataRead, $BytesToRead);
return $DataRead;
}

__END__

Lenke til kommentar
  • 3 uker senere...

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
  • Hvem er aktive   0 medlemmer

    • Ingen innloggede medlemmer aktive
×
×
  • Opprett ny...