#!/usr/bin/perl # @(#) Usage : bdf2bmp.pl bdf_file bmp_file [code_start] [code_end] [fill_gap] # @(#) Example : bdf2bmp.pl uni16m.bdf uni16m.bmp 4e00 4e10 # @(#) Copyright (C) 2002, Web Sailor Production, All Rights Reserved. # @(#) 06Jan02 - sailor, Initial creation. # @(#) This utility generates a windows bitmap file to show the # @(#) font specified by a BDF file. # @(#) code_start = the encoding of the first character to be displayed in hex. # @(#) end_start = the encoding of the last character to be displayed in hex. $| = 1; $argv_code_start = 0x00; $arg_code_end = 0x7f; $argv_code_start = hex($ARGV[2]) if ($#ARGV >= 2); $arg_code_end = hex($ARGV[3]) if ($#ARGV >= 3); $argv_fill_gap = 1; $argv_fill_gap = $ARGV[4] if ($#ARGV >= 4); @file_lines = (); open(FPTR,$ARGV[0]) || die("Error opening BDF file"); @file_lines = ; close(FPTR); map(s/\s+$//mg,@lines); map(s/^\s+//mg,@lines); $file_lines = join("",@file_lines); # Extract the char width and height. # Set both the char width and height to the maximum of the two. # This is to make sure all characters can be rendered correctly. ($char_width,$char_height) = $file_lines =~ m/^FONTBOUNDINGBOX\s+(\d+)\s+(\d+)/m; $char_width = $char_height if ($char_width < $char_height); $char_height = $char_width if ($char_height < $char_width); $char_width += 8 - ($char_width % 8) if (($char_width % 8) != 0); $char_height = $char_width; if ($char_width < 16) { $char_width = 16; $char_height = 16; } # Extract all the bitmap data associated with each character. # Store the bitmap data into an associative array @tbl_bitmap_data. @tbl_bitmap_ix = (); %tbl_bitmap_data = (); @bitmap_data_tmp = $file_lines =~ m/(STARTCHAR.+?ENDCHAR)/sg; # Need to sort the characters in ascending orders. # First put them into an associative array. # then sort them according to their keys. %bitmap_data_output = (); foreach $ix (@bitmap_data_tmp) { $code = $ix; $code =~ s/.+ENCODING\s+(\d+).+/$1/s; next if ($code < $argv_code_start || $code > $arg_code_end); $bitmap_data_output{$code} = $ix; } printf("Number of characters = %d\n",scalar(@bitmap_data_tmp)); # Now the sorted the character bitmap are in array bitmap_data_tmp. foreach $code (sort {hex($a) <=> hex($b)} keys %bitmap_data_output) { $data = $bitmap_data_output{$code}; $data =~ s/.+BITMAP(.+)ENDCHAR/\1/s; @tmp = $data =~ m/([0-9a-fA-F]+)/g; foreach $iy (@tmp) { # make sure the horizontal bitmap data has the same width. $iy .= "0" x (($char_width / 8) * 2 - length($iy)) if (($char_width / 8) * 2 > length($iy)); } $data = join("",@tmp); # make sure the vertical bitmap data has the same height. $data .= "0" x (($char_width / 8) * 2 * $char_height - length($data)) if (($char_width / 8) * 2 * $char_height > length($data)); if ($argv_fill_gap != 0) { if (scalar(@tbl_bitmap_ix) == 0) { if (($code & 0xf) > 0) { foreach $iy (($code - ($code & 0xf)) .. ($code - 1)) { push(@tbl_bitmap_ix,$iy); } } } elsif (($tbl_bitmap_ix[$#tbl_bitmap_ix] + 1) < $code) { # Fill the row with some entries so that every line has 16 characters. # This is so that the later portion of the codes that displaying the # characters does not need to worry about starting with 0. $start = $tbl_bitmap_ix[$#tbl_bitmap_ix] + 1; $end = $code - 1; if (($start - ($start & 0xf)) == ($end - ($end & 0xf))) { # On the same line. if ((($start & 0x0f) != 0) || (($end & 0x0f) != 0x0f)) { foreach $iy ($start .. $end) { # Fill the line with trailing blanks. push(@tbl_bitmap_ix,$iy); } } } else { if (($start & 0xf) > 0) { foreach $iy ($start .. ($start | 0x0f)) { # Fill the line with trailing blanks. push(@tbl_bitmap_ix,$iy); } } if (($end & 0xf) < 0x0f) { foreach $iy (($end - ($end & 0x0f)) .. $end) { # Fill the line with trailing blanks. push(@tbl_bitmap_ix,$iy); } } } } } $tbl_bitmap_data{$code} = $data; push(@tbl_bitmap_ix,$code); } ($bitmap_width,@bitmaps_lines) = &ConstructBitmap($char_width,$char_height,\@tbl_bitmap_ix,\%tbl_bitmap_data); &OutputBitmapFile($ARGV[1],$bitmap_width,@bitmaps_lines); sub ConstructBitmap() { my($char_width,$char_height,$arr1,$arr2) = @_; my @tbl_bitmap_ix = @{$arr1}; my %tbl_bitmap_data = %{$arr2}; # # Bitmap for every character is stored in %tbl_bitmap_data. # Code of every character is stored in @tbl_bitmap_ix. # Both %tbl_bitmap_data and @tbl_bitmap_ix are having the same size. # $tbl_bitmap_ix[0] contains the code of the first character. # $tbl_bitmap_data[tbl_bitmap_ix[0]] contains the bitmap of the first character. # # # $char_width and $char_height specifies the width and height of the character. # # # Local variables. my (%table_num,%tbl_bitmap_num) = (); my ($bitmap_width,@bitmaps_lines,@tmp) = (); my ($flag_warning,$ix,$jx,$data,$char_num) = (); print("Constructing the bitmap image ...\n"); # Make sure the character width is multiple of 8. if (($char_width % 8) > 0) { $char_width = $char_width + (8 - ($char_width % 8)); } %table_num = ( 0 => "00\n00\n00\n00\n18\n24\n42\n42\n42\n42\n42\n42\n24\n18\n00\nFF", 1 => "00\n00\n00\n00\n08\n18\n28\n08\n08\n08\n08\n08\n08\n3E\n00\nFF", 2 => "00\n00\n00\n00\n3C\n42\n42\n02\n0C\n10\n20\n40\n40\n7E\n00\nFF", 3 => "00\n00\n00\n00\n3C\n42\n42\n02\n1C\n02\n02\n42\n42\n3C\n00\nFF", 4 => "00\n00\n00\n00\n04\n0C\n14\n24\n44\n44\n7E\n04\n04\n04\n00\nFF", 5 => "00\n00\n00\n00\n7E\n40\n40\n40\n7C\n02\n02\n02\n42\n3C\n00\nFF", 6 => "00\n00\n00\n00\n1C\n20\n40\n40\n7C\n42\n42\n42\n42\n3C\n00\nFF", 7 => "00\n00\n00\n00\n7E\n02\n02\n04\n04\n04\n08\n08\n08\n08\n00\nFF", 8 => "00\n00\n00\n00\n3C\n42\n42\n42\n3C\n42\n42\n42\n42\n3C\n00\nFF", 9 => "00\n00\n00\n00\n3C\n42\n42\n42\n3E\n02\n02\n02\n04\n38\n00\nFF", 10 => "00\n00\n00\n00\n18\n24\n24\n42\n42\n7E\n42\n42\n42\n42\n00\nFF", 11 => "00\n00\n00\n00\n7C\n42\n42\n42\n7C\n42\n42\n42\n42\n7C\n00\nFF", 12 => "00\n00\n00\n00\n3C\n42\n42\n40\n40\n40\n40\n42\n42\n3C\n00\nFF", 13 => "00\n00\n00\n00\n78\n44\n42\n42\n42\n42\n42\n42\n44\n78\n00\nFF", 14 => "00\n00\n00\n00\n7E\n40\n40\n40\n7C\n40\n40\n40\n40\n7E\n00\nFF", 15 => "00\n00\n00\n00\n7E\n40\n40\n40\n7C\n40\n40\n40\n40\n40\n00\nFF", ); @bitmaps_lines = (); $flag_warning = 0; for($ix=0; $ix<$#tbl_bitmap_ix; $ix+=16) { for ($jx=0; $jx<16; $jx++) { if (!exists($tbl_bitmap_data{$tbl_bitmap_ix[$ix+$jx]})) { # The character does not exists, fill it with blank. $tbl_bitmap_data{$tbl_bitmap_ix[$ix+$jx]} = 0 x (($char_width / 8) * 2 * $char_height); } #printf("%04x : = $tbl_bitmap_data{$ix+$jx}=\n",($ix+$jx)); } %tbl_bitmap_num = (); foreach $jx (0 .. 3) { $tmp = ($tbl_bitmap_ix[$ix] >> (12 - $jx * 4)) & 0xf; $tmp = $table_num{$tmp}; @tmp = $tmp =~ m/([0-9a-fA-F]+)/g; $tmp = join("",@tmp); # make sure the vertical bitmap data has the same height. $tmp .= "0" x (($char_width / 8) * 2 * $char_height - length($tmp)) if (($char_width / 8) * 2 * $char_height > length($tmp)); $tbl_bitmap_num{$jx} = $tmp; } $char_num = ($char_width / 8) * 2; @num_0 = $tbl_bitmap_num{0} =~ m/(.{2})/g; @num_1 = $tbl_bitmap_num{1} =~ m/(.{2})/g; @num_2 = $tbl_bitmap_num{2} =~ m/(.{2})/g; @num_3 = $tbl_bitmap_num{3} =~ m/(.{2})/g; @tmp_0 = $tbl_bitmap_data{$tbl_bitmap_ix[$ix+0]} =~ m/(.{$char_num})/g; @tmp_1 = $tbl_bitmap_data{$tbl_bitmap_ix[$ix+1]} =~ m/(.{$char_num})/g; @tmp_2 = $tbl_bitmap_data{$tbl_bitmap_ix[$ix+2]} =~ m/(.{$char_num})/g; @tmp_3 = $tbl_bitmap_data{$tbl_bitmap_ix[$ix+3]} =~ m/(.{$char_num})/g; @tmp_4 = $tbl_bitmap_data{$tbl_bitmap_ix[$ix+4]} =~ m/(.{$char_num})/g; @tmp_5 = $tbl_bitmap_data{$tbl_bitmap_ix[$ix+5]} =~ m/(.{$char_num})/g; @tmp_6 = $tbl_bitmap_data{$tbl_bitmap_ix[$ix+6]} =~ m/(.{$char_num})/g; @tmp_7 = $tbl_bitmap_data{$tbl_bitmap_ix[$ix+7]} =~ m/(.{$char_num})/g; @tmp_8 = $tbl_bitmap_data{$tbl_bitmap_ix[$ix+8]} =~ m/(.{$char_num})/g; @tmp_9 = $tbl_bitmap_data{$tbl_bitmap_ix[$ix+9]} =~ m/(.{$char_num})/g; @tmp_10 = $tbl_bitmap_data{$tbl_bitmap_ix[$ix+10]} =~ m/(.{$char_num})/g; @tmp_11 = $tbl_bitmap_data{$tbl_bitmap_ix[$ix+11]} =~ m/(.{$char_num})/g; @tmp_12 = $tbl_bitmap_data{$tbl_bitmap_ix[$ix+12]} =~ m/(.{$char_num})/g; @tmp_13 = $tbl_bitmap_data{$tbl_bitmap_ix[$ix+13]} =~ m/(.{$char_num})/g; @tmp_14 = $tbl_bitmap_data{$tbl_bitmap_ix[$ix+14]} =~ m/(.{$char_num})/g; @tmp_15 = $tbl_bitmap_data{$tbl_bitmap_ix[$ix+15]} =~ m/(.{$char_num})/g; for ($jx=0; $jx<$char_height; $jx++) { $data = ""; $data .= $num_0[$jx]; $data .= $num_1[$jx]; $data .= $num_2[$jx]; $data .= $num_3[$jx]; $data .= "00"; $data .= $tmp_0[$jx]; $data .= $tmp_1[$jx]; $data .= $tmp_2[$jx]; $data .= $tmp_3[$jx]; $data .= $tmp_4[$jx]; $data .= $tmp_5[$jx]; $data .= $tmp_6[$jx]; $data .= $tmp_7[$jx]; $data .= $tmp_8[$jx]; $data .= $tmp_9[$jx]; $data .= $tmp_10[$jx]; $data .= $tmp_11[$jx]; $data .= $tmp_12[$jx]; $data .= $tmp_13[$jx]; $data .= $tmp_14[$jx]; $data .= $tmp_15[$jx]; push(@bitmaps_lines,$data); } if ($flag_warning == 0 && scalar(@bitmaps_lines) >= 0x7fff) { $flag_warning = 1; printf("Warning: at code $tbl_bitmap_ix[$ix], 0x%x, big size is hit\n",$tbl_bitmap_ix[$ix]); } } $bitmap_width = $char_width * 16 + 40; return($bitmap_width,@bitmaps_lines); } sub OutputBitmapFile() { # @bitmap_lines contains the bitmap data for every line. # $bitmap_width is the width of the bitmap. my ($output_file,$bitmap_width,@bitmaps_lines) = @_; # Local variables. my ($bitmap_height,$bytes_per_line,$image_size,$ix,$iy,@bmp_hdr,@tmp) = (); print("Displaying the bitmap image ...\n"); $bitmap_height = scalar(@bitmaps_lines); @bitmaps_lines = reverse(@bitmaps_lines); printf("width = %d, height = %d\n",$bitmap_width,$bitmap_height); @bmp_hdr = ( 0x42, 0x4D, 0x8E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x01, 0x00, 0x00, 0x12, 0x0B, 0x00, 0x00, 0x12, 0x0B, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00 ); $bytes_per_line = int($bitmap_width / 8); $bytes_per_line++ if (($bitmap_width % 8) > 0); $bytes_per_line += 4 - ($bytes_per_line % 4) if (($bytes_per_line % 4) > 0); printf("bytes per line = $bytes_per_line\n"); $bmp_hdr[21] = ($bitmap_width >> 24) & 0xff; $bmp_hdr[20] = ($bitmap_width >> 16) & 0xff; $bmp_hdr[19] = ($bitmap_width >> 8) & 0xff; $bmp_hdr[18] = ($bitmap_width) & 0xff; $bmp_hdr[25] = ($bitmap_height >> 24) & 0xff; $bmp_hdr[24] = ($bitmap_height >> 16) & 0xff; $bmp_hdr[23] = ($bitmap_height >> 8) & 0xff; $bmp_hdr[22] = ($bitmap_height) & 0xff; # Image size. $image_size = $bytes_per_line * $bitmap_height; printf("Image size = %d, = %x\n",$image_size,$image_size); $bmp_hdr[37] = ($image_size >> 24) & 0xff; $bmp_hdr[36] = ($image_size >> 16) & 0xff; $bmp_hdr[35] = ($image_size >> 8) & 0xff; $bmp_hdr[34] = ($image_size >> 0) & 0xff; open(FOUT,">$output_file") ||die("Error opening file $output_file"); binmode(FOUT); foreach $ix (@bmp_hdr) { printf FOUT ("%c",$ix); } foreach $ix (@bitmaps_lines) { @tmp = $ix =~ m/(..)/g; foreach $iy (@tmp) { printf FOUT ("%c",(hex($iy)^0xff)); } for($iy=scalar(@tmp); $iy<$bytes_per_line; $iy++) { printf FOUT ("%c",0); } } close(FOUT); }