package Image::Xbm2bmp; use 5.006; use strict; use warnings; use Carp; our $VERSION = '0.02'; sub new { my $class = shift; my $xbmfilepath = shift; my($width,$height,@data); eval{ if(defined($xbmfilepath)){ ($width,$height,@data) = _LoadXbmFile($xbmfilepath); } else{ $width = 0; $height = 0; @data = (); } }; if($@){ die "$@"; } my $self = bless { _WIDTH=>$width, _HEIGHT=>$height, _DATA=>[@data] }, $class; return $self; } sub load_xbm_data($$$){ my($self,$data_ref,$width,$height) = @_; eval{ $self->{_WIDTH} = $width; $self->{_HEIGHT} = $height; $self->{_DATA} = [@$data_ref]; }; if($@){ die "load_xbm_data failed!:$@"; } } sub to_bmp_file($$){ my($self,$bmpfilepath) = @_; my $BMP_PACK = to_bmp_pack($self); open(OUT,">$bmpfilepath") or die "save failed!$!"; binmode(OUT); print OUT $BMP_PACK; close(OUT); } sub to_bmp_pack($){ my($self) = shift; my($data_ref,$width,$height,@xbm_data,@source_xbm_data); $width = $self->{_WIDTH}; $height = $self->{_HEIGHT}; $data_ref = $self->{_DATA}; @source_xbm_data = @$data_ref; my($old_row_bytes,$row_bytes); if(($width%32)>0){ $row_bytes = ($width/32)*4+4; } else{ $row_bytes = $width/8; } $old_row_bytes = $width/8; if($old_row_bytes==$row_bytes){ @xbm_data = @source_xbm_data; } else{ @xbm_data = _init_array($row_bytes,0x00); for(my $c1=0; $c1<$height; $c1++){ for(my $c2=0; $c2<$old_row_bytes; $c2++){ $xbm_data[$c1*$old_row_bytes+$c2] = $source_xbm_data[$c1*$old_row_bytes+$c2]; } } } my @Bitmap_File_size = unpack("C4",pack("C4",(0x3e+$row_bytes*$height))); my @Bitmap_Data_Offset = (0x3e,0x00,0x00,0x00); my @Bitmap_Header_Size = (0x28,0x00,0x00,0x00); my @Bitmap_Width = unpack("C4",pack("C4",$width)); my @Bitmap_Height = unpack("C4",pack("C4",$height));; my @Planes = (0x01,0x00); my @Bits_Per_Pixel = (0x01,0x00); my @Bitmap_Data_Size = unpack("C4",pack("C4",($row_bytes*$height))); my @data = (); #xbm数据的每个字节需要进行反序和NOT处理 foreach my $d(@xbm_data){ my $rd = _reverse_byte($d); $rd = _NOT_byte($rd); push @data,$rd; } #xbm数据行需要进行反序处理 @data = _reverse_ex(\@data,$row_bytes); my @BITMAPFILE = ( 0x42,0x4d, (@Bitmap_File_size), 0x00,0x00,0x00,0x00, (@Bitmap_Data_Offset), (@Bitmap_Header_Size), (@Bitmap_Width), (@Bitmap_Height), (@Planes), (@Bits_Per_Pixel), 0x00,0x00,0x00,0x00, (@Bitmap_Data_Size), 0xc4,0x0e,0x00,0x00, 0xc4,0x0e,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0x00, (@data) ); return pack('C*',@BITMAPFILE); } sub _reverse_byte($){ my $in = shift; my $out = 0x00; if($in & 0b10000000){ $out = $out | 0b00000001; } if($in & 0b01000000){ $out = $out | 0b00000010; } if($in & 0b00100000){ $out = $out | 0b00000100; } if($in & 0b00010000){ $out = $out | 0b00001000; } if($in & 0b00001000){ $out = $out | 0b00010000; } if($in & 0b00000100){ $out = $out | 0b00100000; } if($in & 0b00000010){ $out = $out | 0b01000000; } if($in & 0b00000001){ $out = $out | 0b10000000; } return $out; } sub _NOT_byte($){ my $in = shift; my $out = ~$in; $out = $out & 0b11111111; return $out; } sub _reverse_ex($$){ my($data_ref,$m) = @_; if(!defined($data_ref)||!defined $m){ die "method[_reverse_ex] died!"; } my @sdata = @$data_ref; my $len = scalar(@sdata); my @tdata= (); for(my $n = 0; $n<$len/$m; $n++){ my $k = $len-$n*$m-$m; $tdata[$k] = $sdata[$n*$m]; $tdata[$k+1] = $sdata[$n*$m+1]; $tdata[$k+2] = $sdata[$n*$m+2]; $tdata[$k+3] = $sdata[$n*$m+3]; } return @tdata; } sub _hex_value($){ my($list) = @_; my $value; my $h = substr($list,0,1); my $l = substr($list,1,1); my($h_value,$l_value); $h = lc($h); $l = lc($l); if($h=~/[abcdef]/){ $h_value = ord($h)-ord('a')+10; } if($h=~/[0123456789]/){ $h_value = ord($h)-ord('0'); } if($l=~/[abcdef]/){ $l_value = ord($l)-ord('a')+10; } if($l=~/[0123456789]/){ $l_value = ord($l)-ord('0'); } $value = $h_value*16+$l_value; return $value; } sub _LoadXbmFile($){ my $file = shift; open(INPUT,$file) or die "Can't load xbm file: $!\n"; my $buf; while(){ $buf.= $_; } close(INPUT); my @data = (); my($height,$width); if($buf=~/#define .*width (\d*)/){ $width=$1; } if($buf=~/#define .*height (\d*)/){ $height=$1; } if($buf=~/{\s*(.*)\s*}/s){ my $eval_str = qq~\@data=($1);~; eval $eval_str; } return $width,$height,@data; } sub _init_array($$){ my($length,$value) = @_; my @array; if($length=~/\d/){ for(my $count=0;$count<$length;$count++){ $array[$count] = $value; } } else{ @array = undef; } return @array; } 1; __END__ =head1 NAME Image::Xbm2bmp - for converting image file from XBM to BMP. =head1 SYNOPSIS use Image::Xbm2bmp; #Create a object from a xbm file my $obj = Image::Xbm2bmp->new("/tmp/test.xbm"); #Create a object from array data my $xbm_width = 32; my $xbm_height = 24; my @xbm_data = ( 0x7c,0x3c,0x7c,0x3c, 0xfe,0x7c,0xfe,0x7c, 0xee,0xee,0xee,0xee, 0xe0,0xee,0x60,0xee, 0x70,0xfe,0x30,0xfe, 0x38,0xec,0xe0,0xec, 0x1c,0xe0,0xee,0xe0, 0xfe,0x7e,0xfe,0x7e, 0xfe,0x3c,0x7c,0x3c ); my $obj = Image::Xbm2bmp->new(); $obj->load_xbm_data(\@xbm_data,$xbm_width,$xbm_height); #Save as a BMP file $obj->to_bmp_file("/tmp/test.bmp"); #Or get a packed data my $packed_data = $obj->to_bmp_pack(); open(FILE,">/tmp/test.bmp"); print FILE $packed_data; close(FILE); #In CGI script print "Content-type: image/bmp\n\n"; print $obj->to_bmp_pack(); =head1 DESCRIPTION XBM is a simple image format,we can show a dynamic picture easily via it,so some CGI use xbm file,but it can't be used in browser at WindowsXP(sp2),so we need a module to converting it. =head2 EXPORT None by default. =head1 AUTHOR huang xin hx1978@hotmail.com =head1 SEE ALSO L. =cut