#!/usr/bin/perl
=head1 NAME
art2bmp - Converts "VGA Art Studio files" to BMP
=head1 SYNOPSIS
B<art2bmp.pl> I<file.art>
=head1 DESCRIPTION
Converts "VGA Art Studio" (1991) files to BMP files. Not to be confuse
+d with the
numerous other formats using the ".art" extension. If you have a .art
+file, it's
almost certainly a different format.
Does not handle any mask data if present.
=head1 AUTHOR
Lee Pumphret
=cut
use strict;
use warnings;
my @files = glob(shift @ARGV);
foreach my $file (@files) {
next and warn "Mismatched extension in filename [$file]... skippin
+g\n"
unless $file=~/\.art$/i;
print "processing $file...\n";
open( IN, "<$file" ) or die "Couldn't open $file :$!";
binmode(IN);
my $buffer;
my $ART_HEADER_SIZE = 8; # .art file header size
# Read the header
( read( IN, $buffer, $ART_HEADER_SIZE ) == $ART_HEADER_SIZE )
or die "Error reading header data!";
my ( $ident, $mask, $x, $y, $im_compressed, $mask_compressed, ) =
unpack( "CCssCC", $buffer );
unless ( $ident == 123 ) {
die "Doesn't look like an ART file! [$ident]";
}
# Read the palette data (rgb triplets)
my @pal;
for ( 0 .. 255 ) {
read( IN, $buffer, 3 ) == 3 or die "Error reading palette!";
my @rgb = unpack( "CCC", $buffer );
push @pal, pack( "CCC", reverse @rgb );
}
# Read image data
my @imdata;
my $pixel_count = 0;
if ($im_compressed) {
warn "Decompressing image [$x x $y]....\n";
while ( $pixel_count < $x * $y ) {
read( IN, $buffer, 1 ) == 1
or die "Couldn't read! (have $pixel_count pixels $#imdat
+a) $!";
my $byte = unpack( "C", $buffer );
if ( $byte < 128 ) {
$imdata[ $pixel_count++ ] = $pal[$byte];
}
else {
# It's RLE
my $repeat = $byte - 128;
read( IN, $buffer, 1 ) == 1 or die "Couldn't read! :$!
+";
$byte = unpack( "C", $buffer );
push @imdata, ( $pal[$byte] ) x ( $repeat + 1 );
$pixel_count += $repeat + 1;
}
}
}
else {
warn "$file is Uncompressed!";
read( IN, $buffer, $x * $y ) == $x * $y or die "Short read on
+$file";
@imdata = map { $pal[$_] } unpack( "C*", $buffer );
}
if ($mask){
warn "Image has mask data, ignoring...";
}
# Write out the bmp file
( my $outfile = $file ) =~ s/art$/bmp/i;
my $written = $#imdata;
open( OUT, ">$outfile" ) or die "Couldn't open output!";
binmode(OUT);
# BMP 3.1 Header
print OUT pack "C C l a a a a l l l l s s l l l l l l", 0x42, 0x4D
+,
54 + ( $x * 3 ) * $y, 'l', 'e', 'e', 'p', 54, 0x28, $x, $y, 1, 2
+4, 0, 0,
0, 0, 0, 0;
# Write out the image data, bottom to top
while ( $written > 0 ) {
print OUT @imdata[ $written - ( $x - 1 ) .. $written ];
$written -= $x;
}
close OUT;
}
__END__
A snippet of documentation from "VGA Art Studio"
* Note, there were some typos, errors in the doc which I have correcte
+d.
Appendix A: VGA Art Studio .ART and .PAL file formats
=========================================================
The .ART file
-------------
All VGA Art Studio picture/cutout files are stored in this format. In
+fact,
there is no distinction between a picture or a cutout - a picture can
+be pasted
in as a cutting, and a cutting can be loaded in as a file.
There are essentially two image formats - compressed and uncompressed.
+ Before
saving a file, VGA Art Studio works out which format will actually res
+ult in a
smaller file, and then saves the file in this format. Actually, it is
+not quite
as simple as that - each image may need a 'mask', and whether or not
+they the
mask is compressed is independent of whether or not the picture itself
+ is
compressed. However, the file format is still relatively easy to use,
+and is as
follows :
+----------+-----------------------------------------------------+----
+---+
| Offset | Description | Byt
+es |
+----------+-----------------------------------------------------+----
+---+
| 0 | 123 dec. (acts as a file identifier) | 1
+ |
| 1 | Mask included? (1=yes, 0=no) | 1
+ |
| 2 | Size (x) in pixels of the image - INTEL format | 2
+ |
| 4 | Size (y) in pixels of the image - INTEL format | 2
+ |
| 6 | Image data compressed? (1=yes, 0=no) | 1
+ |
| 7 | Mask data compressed ? (1=yes, 0=no) | 1
+ |
| 8 | Palette data - 256 x (R,G,B) triplets, with | 76
+8 |
| | individual intensities from 0..255 |
+ |
| 776 | Image data (may be compressed) | ??
+? |
| ??? | (optional) Mask data (may be compressed) | ??
+? |
+----------------------------------------------------------------+----
+---+
As mentioned, both the image data and the mask data may be compressed
+depending
on the values in bytes 6 and 7 of the header. The two formats are the
+same for
both the mask and the image, and work as follows:
The data in its uncompressed form consists of 64000 bytes, in a straig
+ht
forward raster format - with 1 byte per pixel - (acting as an index in
+to the
palette in the case of image data - in the case of mask data, a non-ze
+ro value
indicates that the corresponding image pixel IS to be displayed). The
+bytes are
stored row by row, with each row running from left to right, in standa
+rd raster
format.
In the compressed format, the algorithm for uncompressing the data run
+s as
follows :
+-----------------------------+
| Read the next byte of data |
| from the file, (unless we |<--------------------------------------
+-----+
| now have data for 64000 |
+ |
| pixels, in which case stop).|
+ |
+-----------------------------+
+ |
| |
\ / |
+--------------------+ Y +----------------------------------
++ |
| Is the byte <128 ? |--------->| Use this byte for the next pixel
+|----+
+--------------------+ +----------------------------------
++ ^
| N |
\ / |
+--------------------------------------------------------------------+
+ |
| Subtract 128 from the value of the byte - call this C. Then read |
+ |
| the next byte - this gives you the colour of the next (C+1) |
+-----+
| pixels. |
+--------------------------------------------------------------------+
Note:
Compressed data is stored a line at a time. Compression using a byte >
+128 as a
repeat count MUST NOT wrap round from one line to the beginning of the
+ next.
The .PAL file
-------------
This is very very straightforward. Each file is 769 bytes long, and co
+nsists of
the following data:
+----------+-----------------------------------------------------+----
+---+
| Offset | Description | Byt
+es |
+----------+-----------------------------------------------------+----
+---+
| 0 | 124 dec. (acts as a file identifier) | 1
+ |
| 1 | Palette data - 256 x (R,G,B) triplets, with | 76
+8 |
| | individual intensities from 0..255 |
+ |
+----------------------------------------------------------------+----
+---+
----------------------------------------------------------------------
+------
Appendix D : About Mooose Software
==================================
"Founded" in 1990 by :
Ben Stragnell
Graham Sanderson
Samer Abdallah
\ \ / \/ ___//
+
\_ / // \] //~~~
+
\\ ]] // //
+
\__\ _]_\_ _\\ __/\//
+
__ _____\ /_\// _
+
__ _/ \/~~~~~~\/ \__ //
+
_/ ] ] \/
+
/] / \ ]
+
/ ](0 0)]
+
/ ] ]
+
____________~ ] ]
+
\ < > /
/ \______/
+
] ]
+
]
+
]
+
The moose is without doubt one of the finest animals ever invented, it
+s
majestic antlers towering skyward, as it stands proudly, one of Nature
+'s
most cunning creations. It's also got a really cool name, and you can
+put
an extra 'o' in it, to make it last just that little bit longer. Oh ye
+s.
Keep an eye out for more releases from Mooose Software, and please sup
+port
the Public Domain!
|