From 8991656ffb2d5bb68454d367c9c413a05312d338 Mon Sep 17 00:00:00 2001 From: hpa Date: Fri, 22 Aug 2003 18:27:36 +0000 Subject: [PATCH] Make ppmtolss16 fully compliant with the PNM spec. --- NEWS | 5 +-- ppmtolss16 | 120 +++++++++++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 97 insertions(+), 28 deletions(-) diff --git a/NEWS b/NEWS index cc01ca0..dc19521 100644 --- a/NEWS +++ b/NEWS @@ -8,9 +8,10 @@ Changes in 2.06: * ISOLINUX: Fix problem that would occationally cause a boot failure, depending on the length of directories. * SYSLINUX: Win32 installer now flushes buffers. - * ppmtolss16: Try to be compliant with the PPM spec; + * ppmtolss16: Be fully compliant with the PPM spec; actually process comments in the header and odd - alignments of the various parameters. + alignments of the various parameters, as well as + "plain" (not raw) files and PBM and PGM files. Changes in 2.05: * PXELINUX: Add a default query based on the hardware address diff --git a/ppmtolss16 b/ppmtolss16 index 1f4e1a9..b3925b7 100755 --- a/ppmtolss16 +++ b/ppmtolss16 @@ -2,7 +2,7 @@ ## $Id$ ## ----------------------------------------------------------------------- ## -## Copyright 2001 H. Peter Anvin - All Rights Reserved +## Copyright 2001-2003 H. Peter Anvin - All Rights Reserved ## ## 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 @@ -15,7 +15,7 @@ ## ## ppmtolss16 ## -## Convert a "raw" PPM file with max 16 colors to a simple RLE-based format: +## Convert a PNM file with max 16 colors to a simple RLE-based format: ## ## uint32 0x1413f33d ; magic (littleendian) ## uint16 xsize ; littleendian @@ -35,11 +35,9 @@ ## ## At the start of row, the "previous pixel" is assumed to be zero. ## -## BUG: This program does not handle "plain" ppm format. -## ## Usage: ## -## ppmtorle16 [#rrggbb=i ...] < input.ppm > output.rle +## ppmtolss16 [#rrggbb=i ...] < input.ppm > output.rle ## ## Command line options of the form #rrggbb=i indicate that ## the color #rrggbb (hex) should be assigned index i (decimal) @@ -88,11 +86,86 @@ sub get_token() { return $token; } -sub rgbconvert($$) { - my($rgb,$maxmult) = @_; - my($r,$g,$b); +# Get a token, and make sure it is numeric (and exists) +sub get_numeric_token() { + my($token) = get_token(); + + if ( $token !~ /^[0-9]+$/ ) { + print STDERR "Format error on input\n"; + exit 1; + } + + return $token + 0; +} + +# Must be called before each pixel row is read +sub start_new_row() { + $getrgb_leftover_bit_cnt = 0; + $getrgb_leftover_bit_val = 0; +} + +# Get a single RGB token depending on the PNM type +sub getrgb($) { + my($form) = @_; + my($rgb,$r,$g,$b); + + if ( $form eq 'P6' ) { + # Raw PPM, most common + return undef unless ( read(STDIN,$rgb,3) == 3 ); + return unpack("CCC", $rgb); + } elsif ( $form eq 'P3' ) { + # Plain PPM + $r = get_numeric_token(); + $g = get_numeric_token(); + $b = get_numeric_token(); + return ($r,$g,$b); + } elsif ( $form eq 'P5' ) { + # Raw PGM + return undef unless ( read(STDIN,$rgb,1) == 1 ); + $r = unpack("C", $rgb); + return ($r,$r,$r); + } elsif ( $form eq 'P2' ) { + # Plain PGM + $r = get_numeric_token(); + return ($r,$r,$r); + } elsif ( $form eq 'P4' ) { + # Raw PBM + if ( !$getrgb_leftover_bit_cnt ) { + return undef unless ( read(STDIN,$rgb,1) == 1 ); + $getrgb_leftover_bit_val = unpack("C", $rgb); + $getrgb_leftover_bit_cnt = 8; + } + $r = ( $getrgb_leftover_bit_val & 0x80 ) ? 0x00 : 0xff; + $getrgb_leftover_bit_val <<= 1; + $getrgb_leftover_bit_cnt--; + + return ($r,$r,$r); + } elsif ( $form eq 'P1' ) { + # Plain PBM + my($ch); + + do { + $ch = getc(STDIN); + return undef if ( !defined($ch) ); + return (255,255,255) if ( $ch eq '0' ); # White + return (0,0,0) if ( $ch eq '1'); # Black + if ( $ch eq '#' ) { + do { + $ch = getc(STDIN); + return undef if ( !defined($ch) ); + } while ( $ch ne "\n" ); + } + } while ( $ch =~ /^[ \t\n\v\f\r]$/ ); + return undef; + } else { + die "Internal error: unknown format: $form\n"; + } +} + +sub rgbconvert($$$$) { + my($r,$g,$b,$maxmult) = @_; + my($rgb); - ($r, $g, $b) = unpack("CCC", $rgb); $r = int($r*$maxmult); $g = int($g*$maxmult); $b = int($b*$maxmult); @@ -131,7 +204,7 @@ foreach $arg ( @ARGV ) { next; } - $rgb = rgbconvert(pack("CCC", $r, $g, $b), 64/256); + $rgb = rgbconvert($r, $g, $b, 64/256); if ( defined($index_forced{$i}) ) { print STDERR "$0: More than one color index $i\n"; @@ -142,31 +215,26 @@ foreach $arg ( @ARGV ) { } $form = get_token(); -die "$0: stdin is not a raw PPM file" if ( $form ne 'P6' ); - -$xsize = get_token(); -$ysize = get_token(); -if ( $xsize !~ /^([0-9]+)$/ || $ysize !~ /^([0-9]+)$/ ) { - die "$0: Input format error 1\n"; -} -$xsize += 0; $ysize += 0; # Convert to number - -$maxcol = get_token(); -chomp $maxcol; -if ( $maxcol !~ /^([0-9]+)$/ ) { - die "$0: Input format error 2\n"; +die "$0: stdin is not a PNM file" if ( $form !~ /^P[1-6]$/ ); + +$xsize = get_numeric_token(); +$ysize = get_numeric_token(); +if ( $form =~ /^P[2356]$/ ) { + $maxcol = get_numeric_token(); +} else { + $maxcol = 255; # Internal convention } -$maxcol += 0; $maxmult = 64/($maxcol+1); # Equal buckets conversion @data = (); for ( $y = 0 ; $y < $ysize ; $y++ ) { + start_new_row(); for ( $x = 0 ; $x < $xsize ; $x++ ) { die "$0: Premature EOF at ($x,$y) of ($xsize,$ysize)\n" - if ( read(STDIN, $rgb, 3) != 3 ); + if ( !defined(@pnmrgb = getrgb($form)) ); # Convert to 6-bit representation - $rgb = rgbconvert($rgb, $maxmult); + $rgb = rgbconvert($pnmrgb[0], $pnmrgb[1], $pnmrgb[2], $maxmult); $color_count{$rgb}++; push(@data, $rgb); } -- 2.7.4