#!/usr/bin/perl -w
# ---------------------------------------------------------
# parse bmp file to get RGB information
# by Tao Yuliang
# 28/03/2009
# ---------------------------------------------------------
#
#use strict;
# prepare
my @bmp_tag = qw( bfType bfSize bfReserved1 bfReserved2 bfOffBits biSize biWidth biHeight biPlanes biBitCount biCompression biSizeImage biXPelsPerMeter biYPelsPerMeter biClrUsed biClrImportant );
binmode STDIN; binmode STDOUT;
my $data_format = "H";
#------------------------------------------#
# read the bmp file and parse the data #
#------------------------------------------#
# get the file name
die "No input file!\n" if not $filename = shift @ARGV; # open the file
open RGBFILE, $filename or die "Can't open $filename: $!"; binmode RGBFILE;
# read the bmp file
my $data = <RGBFILE> ;
# convert the data into a certain format
# to get the information of bmp file
#my @hdr_dat = unpack "SLSSLLLLSSLLLLLLC*", $data;
my @hdr_dat = unpack "SLSSLLLLSSLLLLLL$data_format*", $data; $hdr_dat[0] = join '', unpack "aa", $data; #print "@hdr_dat\n";
# get the image data form $hdr_dat[-1]
my @rgb_data; for ( 1..($#hdr_dat-$#bmp_tag) ) {
unshift @rgb_data, pop @hdr_dat; } #print "@hdr_dat\n";
#print "@rgb_data\n";
# if there is '0A' data in image data, perl will treate it as a '\n'
# so we must read the remaining data
while ( <RGBFILE> ) { # don't chomp, else it will discards '0A'
#chomp ;
push @rgb_data, unpack "$data_format*", $_; } close RGBFILE;
# store the info of file structure into a hash
my %header; @header{@bmp_tag}=@hdr_dat; print "$_\t$header{$_}\n" for @bmp_tag;
#------------------------------------------#
# get the RGB info and write into txt file #
#------------------------------------------#
my @table_R; my @table_G; my @table_B;
if ( $data_format eq 'H' ) { &process_H_format ; } else { &process_C_format ; }
open INFOTXT, "> $filename.txt" or die "Can't open $filename.txt: $!";
print INFOTXT "R\n"; print INFOTXT "@table_R\n"; print INFOTXT "G\n"; print INFOTXT "@table_G\n"; print INFOTXT "B\n"; print INFOTXT "@table_B\n";
#------------------------------------------#
# convert RGB to YCbCr #
#------------------------------------------#
my ( @YR_LUT, @CbR_LUT, @CrR_LUT ); my ( @YG_LUT, @CbG_LUT, @CrG_LUT ); my ( @YB_LUT, @CbB_LUT, @CrB_LUT ); # call subroutine
&prepare_Y_LUT ; &prepare_Cb_LUT ; &prepare_Cr_LUT ;
# get the YCbCr data according to LUT
my ( @table_Y, @table_Cb, @table_Cr ); for ( 0..$#table_R ) {
my $R = ( $data_format eq "H" ) ? hex( $table_R[$_] ) : $table_R[$_]; my $G = ( $data_format eq "H" ) ? hex( $table_G[$_] ) : $table_G[$_]; my $B = ( $data_format eq "H" ) ? hex( $table_B[$_] ) : $table_B[$_]; push @table_Y, int( ($YR_LUT[$R]+$YG_LUT[$G]+$YB_LUT[$B]) / 2**16 ); push @table_Cb, ( int(($CbR_LUT[$R]+$CbG_LUT[$G]+$CbB_LUT[$B]) / 2**16) + 128 ); push @table_Cr, ( int(($CrR_LUT[$R]+$CrG_LUT[$G]+$CrB_LUT[$B]) / 2**16) + 128 ); }
# write into file
print INFOTXT "Y\n"; print INFOTXT "@table_Y\n"; print INFOTXT "Cb\n"; print INFOTXT "@table_Cb\n"; print INFOTXT "Cr\n"; print INFOTXT "@table_Cr\n";
close INFOTXT;
############################################################################
#-----------------------------------------#
# subrountine definition #
#-----------------------------------------#
sub process_H_format { my $data = join '', @rgb_data; # reorder the image data
my $offset = $header{ 'biWidth' } * 3 * 2; my @lines = reverse ($data =~ /([\w\d]{$offset})/ig ); #print "@lines\n";
my $reorder_data = join '', @lines;
#
while ( $reorder_data =~ /([\w\d]{2})([\w\d]{2})([\w\d]{2})/ig ) { push @table_R, $3; push @table_G, $2; push @table_B, $1; #print "R=>$3 : G=>$2 : B=>$1\n";
} }
sub process_C_format { # reorder the image data
my @reorder_data; for( my $y=0; $y < $header{ 'biHeight' }; $y++ ) { my @lines; my $x_count = $header{ 'biWidth' } * 3; while( $x_count-- ) { push @lines, pop @rgb_data; } #print "@lines\n";
unshift @reorder_data, @lines; } #print "@reorder_data\n";
my $size = $header{ 'biWidth' } * $header{ 'biHeight' }; while ( $size-- ) { #print $size, "\n";
push @table_B, pop @reorder_data; push @table_G, pop @reorder_data; push @table_R, pop @reorder_data; } }
# prepare the YCbCr data
sub prepare_Y_LUT { for ( 0..255 ) { $YR_LUT[$_] = int(65536*0.299+0.5) * $_; $YG_LUT[$_] = int(65536*0.587+0.5) * $_; $YB_LUT[$_] = int(65536*0.114+0.5) * $_; } }
sub prepare_Cb_LUT { for ( 0..255 ) { $CbR_LUT[$_] = int(65536*-0.16874+0.5) * $_; $CbG_LUT[$_] = int(65536*-0.33126+0.5) * $_; $CbB_LUT[$_] = 32768 * $_; } }
sub prepare_Cr_LUT { for ( 0..255 ) { $CrR_LUT[$_] = 32768 * $_; $CrG_LUT[$_] = int(65536*-0.41869+0.5) * $_; $CrB_LUT[$_] = int(65536*-0.08131+0.5) * $_; } }
|