Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask

Re: BMP file manipulation

by tachyon (Chancellor)
on Dec 17, 2003 at 07:10 UTC ( #315232=note: print w/replies, xml ) Need Help??

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;



Replies are listed 'Best First'.
Re^2: BMP file manipulation
by MadraghRua (Vicar) on Aug 25, 2008 at 23:43 UTC
    Dear Tachyon
    Thank you for your very helpful example. I am trying to adapt it my own needs and I am struggling with parts 4 and 5 in your example.

    I am working with images that are 1024 high x 1280 wide using 8 bit grey scale to represent each color. So for instance I have used the following to get the color table:
    <c> my @rgbQuad = wq ( rgbBlue rgbGreen rgbRed rgbReserved ); my @rgb_dat = unpack "LLLL", $data; my %rgbQuadList; @rgbQuadList{@rgbQuad} = @rgb_dat; print "$_\t$rgbQuad{$_}\n" for @rgbQuad; <\c>
    to retrieve the rgb color table data. This returns one line of data for the Blue, Green, Red and Reserved colors. What I am not understanding is how to get every instance of this color table by reiterating through $data. I have also tried assigning < BMP > to an array but that does not seem to behave like the standard file handles I am more typically used to.

    Secondly I don't understand how to extract the data lines for the image. So my offset is 1078 bits. According to your calculation, and using an 8 bit pixel assignment, I need to capture 10242 bytes per line for my bit maps. How do I set this for unpack?

    Thank you for taking the time to answer my questions.

    yet another biologist hacking perl....

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://315232]
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others about the Monastery: (4)
As of 2021-03-04 10:06 GMT
Find Nodes?
    Voting Booth?
    My favorite kind of desktop background is:

    Results (102 votes). Check out past polls.