#!/usr/bin/perl -w
# ---------------------------------------------------------
# parse bmp file to get RGB information
# by Tao Yuliang <[email protected]>
# 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) * $_;
}
}
|