http://qs321.pair.com?node_id=315232


in reply to BMP file manipulation

Do it with a C program if you want some good advice, even if you have to write to disk.

However you can of course do it in Perl, but it is not for the faint of heart. Essentially you need to:

  1. Read the heder info
  2. Modify the width and height attributes
  3. Modify the file size attr
  4. Get the bitmap data starting at the offset and modify it pixel linewise to get what you want, remebering that you need to pack with nulls to a multiple of 4 - so if the image is 10pix wide at 24 bits each line will be 10+*24/8 = 30 bytes + 2 = 32 bytes to make it divisible by 4.
  5. Repack all the data into a scalar and write to a file.

Here is some code to get you started. This gets the header, modifies just the height (easy :-) modifies the header and writes the file out again. I leave the data alone but as you can see you just see half the bitmap now so the rest of the pixel data could have been thrown away. Modifying the width is where it gets harder.

#!/usr/bin/perl -w use strict; my @hdr = qw( bfType bfSize bfReserved1 bfReserved2 bfOffBits biSize biWidth biHeight biPlanes biBitCount biCompression biSizeImage biXPelsPerMeter biYPelsPerMeter biClrUsed biClrImportant ); binmode STDIN; binmode STDOUT; my $BMP = 'c:/df.bmp'; open BMP, $BMP or die $!; binmode BMP; my $data = <BMP>; close BMP; my @hdr_dat = unpack "SLSSLLLLSSLLLLLL", $data; my %header; @header{@hdr}=@hdr_dat; print "$_\t$header{$_}\n" for @hdr; # chop in half! $header{biHeight} = int($header{biHeight}/2); my $new_hdr = pack "SLSSLLLLSSLLLLLL", @header{@hdr}; $data =~ s/^.{54}/$new_hdr/; open OUT, ">$BMP.munge.bmp" or die $!; binmode OUT; print OUT $data; close OUT;

cheers

tachyon