#!/usr/bin/perl

#- Build a message file for syslinux-graphic from a BMP file.
#- Copyright (C) 1999,200,2001 MandrakeSoft (pixel@mandrakesoft.com)
#-
#- This program is free software; you can redistribute it and/or modify
#- it under the terms of the GNU General Public License as published by
#- the Free Software Foundation; either version 2, or (at your option)
#- any later version.
#-
#- This program is distributed in the hope that it will be useful,
#- but WITHOUT ANY WARRANTY; without even the implied warranty of
#- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#- GNU General Public License for more details.
#-
#- You should have received a copy of the GNU General Public License
#- along with this program; if not, write to the Free Software
#- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

#- usage:
#-   bmp2mdk <picture.bmp >picture.msg
#- NB: the input image (colormap indexed) should not have more than 128 colors
#- and should not be compressed.

#- additional modification, to include some escape sequence for the picture
#- commented as follow:
#-   mode:value                   - VESA mode to use, assume graphic if > 0x100,
#-				    default is 0x101 (ie 640x480 in 256 colors).
#-   timer:y,x,bg,fg              - timer position and colors (for LILO only).
#-   entry:y,x,bg,fg,h_chr,w_chr  - entry position, colors and size in chars
#-				    (for LILO only).
#-   progress:y,x,h,w,c           - progress bar position, size (h and w in byte
#-				    only) and color (for SYSLINUX only).
#-   clear:h,w,c                  - clear before with color c, default is clear
#-				    640x480 in color 0 (black).
#- no options assume no addition initcode given.
#- colors given in the range 0x40 and 0xBF are from picture palette used (shifted).

use strict;

my $initcode_str;
my %initcode = ( #- this default are running quite nicely with first english LILO image.
		mode        => 0x101,
		timer_y     => 0,
		timer_x     => 0,
		timer_bg    => 0x00,
		timer_fg    => 0x0f,
		entry_y     => 0,
		entry_x     => 0,
		entry_bg    => 0x00,
		entry_fg    => 0x0f,
		entry_h_chr => 24,
		entry_w_chr => 22,
	        progress_y  => 0,
                progress_x  => 0,
	        progress_h  => 8,
		progress_w  => 32,
		progress_c  => 0x01,
		clear_w     => 640,
		clear_h     => 480,
		clear_color => 0,
		pos_y       => 0,
		pos_x       => 0,
	       );
my $file;
foreach (@ARGV) {
    /^file:(.*)/  and do {
        $file = $1;
	if (-e "$file.parameters") {
	    $initcode{$1} = $2 while `cat $file.parameters` =~ /(.*)=(.*)/mg;
	}
        next;
    };
    /^mode:(.*)/  and do { @initcode{qw(mode)} = map { eval "$_" } split /,/, $1; next };
    /^timer:(.*)/ and do { @initcode{qw(timer_y timer_x timer_bg timer_fg)} = map { eval "$_" } split /,/, $1; next };
    /^entry:(.*)/ and do { @initcode{qw(entry_y entry_x entry_bg entry_fg entry_h_chr entry_w_chr)} = map { eval "$_" } split /,/, $1; next };
    /^progress:(.*)/ and do { @initcode{qw(progress_y progress_x progress_h progress_w progress_c)} = map { eval "$_" } split /,/, $1; next };
    /^clear:(.*)/ and do { @initcode{qw(clear_h clear_w clear_color)} = map { eval "$_" } split /,/, $1; next };
    /^pos:(.*)/   and do { @initcode{qw(pos_y pos_x)} = map { eval "$_" } split /,/, $1; next };
    /^initcode$/  and next;
    die "usage: bmp2mdk [options]
where [options] are taken from the following list:
   mode:value                   - VESA mode to use, assume graphic if > 0x100,
                                  default is 0x101 (ie 640x480 in 256 colors).
   timer:y,x,bg,fg              - timer position and colors (for LILO only).
   entry:y,x,bg,fg,h_chr,w_chr  - entry position, colors and size in chars
                                  (for LILO only).
   progress:y,x,h,w,c           - progress bar position, size (h and w in byte
                                  only) and color (for SYSLINUX only).
   clear:h,w,c                  - clear before with color c, default is clear
                                  640x480 in color 0 (black).
   pos:y,x                      - set x,y for next pixmap, default is to (0,0).
   file:file_name.bmp           - set the filename instead of using stdin
                                  (if file_name.bmp.parameters exists, it is used)
no options assume no addition initcode given.
colors given in the range 0x40 and 0xBF are from picture palette used (shifted).
input image should be a 128 colors uncompressed BMP file.

unknown option [$_]\n";
}
if (@ARGV) {
    my ($ext_code, $ext_data) = (0x00, '');

    if ($initcode{mode}) {
	$ext_code |= 0x80;
	$ext_data .= pack "v", $initcode{mode};
    }
    if ($initcode{progress_y} || $initcode{progress_x}) {
	$ext_code |= 0x20;
	$ext_data .= pack "v2C3", @initcode{qw(progress_y progress_x progress_h progress_w progress_c)};
    }
    if ($initcode{timer_y} || $initcode{timer_x} || $initcode{entry_y} || $initcode{entry_x}) {
	$ext_code |= 0x08;
	$ext_data .= pack "v2C2 v2C4", @initcode{qw(timer_y timer_x timer_bg timer_fg
						    entry_y entry_x entry_bg entry_fg entry_h_chr entry_w_chr)};
    }
    #- always set up clear.
    $ext_code |= 0x02;
    $ext_data .= pack "v2C", @initcode{qw(clear_w clear_h clear_color)};

    print "\x0e";
    print pack "C", $ext_code;
    print $ext_data;

    #- always set up pos too but in separate coded.
    print "\x0e\x10";
    print pack "v2", @initcode{qw(pos_y pos_x)};
}

undef $/;
my $f = $file ? do {
    open(my $F, $file) or die "can't open $file: $!\n";
    <$F>;
} : <STDIN>;

my ($width, $height, $nbcolors) = unpack "x18 V V x20 V", $f;

my $s = $nbcolors * 4;
my ($palette, $image) = unpack "x54 a$s a*", $f;
my @palette = unpack("C3x" x $nbcolors, $palette);

for (my $i = 0; $i < 3 * $nbcolors; $i += 3) {
    ($palette[$i], $palette[$i + 2]) = ($palette[$i + 2], $palette[$i]);
}

# we don't want more than 128 colors.
# if the image contains indices above 128, it will be catched when scanning the image
# so for now, accept $nbcolors > 128, just adjust it
$nbcolors = 128 if $nbcolors > 128;

print "\x0e\x04";
print pack "v v C C" . "C3" x $nbcolors, $width, $height, $nbcolors, 0, @palette;

my $width_ = 4 * int (($width + 3) / 4);
my ($oldv, $nb) = (-1024, 0);

for (my $i = 0; $i < $height; $i++) {
    for (my $j = 0; $j < $width; $j++) {
	my $v = vec $image, ($height - $i - 1) * $width_+ $j, 8;
	$v >= 128 and die "cannot use more than 128 colors in input file\n";

	if ($v == $oldv) {
	    $nb++;
	} else {
	    while ($nb > 129) {
		print pack "C", 0xFF;
		$nb -= 129;
	    }
	    if ($nb > 1) { #- necessary <= 129 here
		print pack "C", (0x80 | ($nb - 2));
	    } elsif ($nb == 1) {
		print pack "C", $oldv;
	    }
	    print pack "C", $v;
	    $oldv = $v;
	    $nb = 0;
	}
    }
}
while ($nb > 129) {
    print pack "C", 0xFF;
    $nb -= 129;
}
if ($nb > 1) { #- necessary <= 129 here
    print pack "C", (0x80 | ($nb - 2));
} elsif ($nb == 1) {
    print pack "C", $oldv;
}

1;
