#!/usr/bin/env perl $version = '$Id: bdf2gdr.pl,v 2.2 2005/02/07 23:45:50 tsumura Exp $'; # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # # This program is based on # # - any2ucs, hex2bdf, bdf2hex # (c) Copyright 2000-2001 /efont/ The Electronic Font Open Laboratory. # # - bdfmerge # by 1@2ch (public domain) # # # Copyright (c) 2005 TSUMURA,Tomoaki. # $| = 1; use FileHandle; require 5.005; sub usage { print "Usage: \n"; print "\t$0 (16|12|fontname) jis0208.bdf jis0201.bdf [ascii.bdf]\n\n"; exit; } $noascii = 0; $replace = 0; if( $ARGV[0] =~ '^(1[26])$' ){ $replace = $1 + 0; } if( $#ARGV < 2 ){ usage(); } if( $#ARGV == 2 ){ $noascii = 1; } $base = $$; print< GDR preprocessor # # (c) 2005 TSUMURA,Tomoaki # ################################################## EoH if( $replace ){ $fontname = "JapanPlain"; }else{ $fontname = $ARGV[0]; } $jis{'bdf'} = $ARGV[1]; $rk{'bdf'} = $ARGV[2]; if( !$noascii ){ $asc{'bdf'} = $ARGV[3]; }else{ $asc{'bdf'} = 'dummy'; } open(JIS, $jis{'bdf'}) || die "\n!!! Error !!! Can't open BDF file `$jis{'bdf'}'!\n\n"; open(RK, $rk{'bdf'}) || die "\n!!! Error !!! Can't open BDF file `$rk{'bdf'}'!\n\n"; if( !$noascii ){ open(ASC, $asc{'bdf'}) || die "\n!!! Error !!! Can't open BDF file `$asc{'bdf'}'!\n\n"; } ################################################## # Check input files ################################################## print "\n##################################################\n"; print " Checking input bdf files ...\n"; print "##################################################\n"; # # bdf # sub bdfp { my($bdf) = $_[0]; my($line); open(TMP, $bdf); $line = ; close(TMP); if( $line !~ /STARTFONT/i ){ die "\n!!! Error !!! File `$bdf' is not a BDF!\n\n"; } } bdfp( $jis{'bdf'} ); bdfp( $rk{'bdf'} ); bdfp( $asc{'bdf'} ) if( !$noascii ); # # parse # sub bdf_hdr { my($bdf) = $_[0]; my($line) = ''; my(%prop); $prop{'bdf'} = $bdf; open(TMP, $bdf); while( $line !~ /^CHARS\s/i ){ $line = ; $line =~ s/\r\n//g; chomp($line); if( $line =~ /^PIXEL_SIZE ([0-9]+)$/i ){ $prop{'size'} = $1 + 0; }elsif( $line =~ /^CHARSET_REGISTRY (.*)$/i ){ $prop{'cset'} = $1; $prop{'cset'} =~ s/"//g; }elsif( $line =~ /^CHARSET_ENCODING (.*)$/i ){ $prop{'enc'} = $1; $prop{'enc'} =~ s/"//g; }elsif( $line =~ /^FONTBOUNDINGBOX ([0-9]+) ([0-9]+) ([-0-9]+) ([-0-9]+)$/ ){ $prop{'fbbx_w'} = $1 + 0; $prop{'fbbx_h'} = $2 + 0; $prop{'fbbx_x'} = $3 + 0; $prop{'fbbx_y'} = $4 + 0; }elsif( $line =~ /^FONT_DESCENT ([0-9]+)$/ ){ $prop{'descent'} = $1 + 0; }elsif( $line =~ /^FONT_ASCENT ([0-9]+)$/ ){ $prop{'ascent'} = $1 + 0; } } close(TMP); return( %prop ); } %jis = bdf_hdr( $jis{'bdf'} ); %rk = bdf_hdr( $rk{'bdf'} ); if( !$noascii ){ %asc = bdf_hdr( $asc{'bdf'} ); } # # charset # sub validcode { my($bdf, $cset, $enc, $vcset, $venc) = @_; print "Checking charset registry of `$bdf'\t..."; if( $cset !~ /$vcset/i || $enc ne $venc ){ die "\n!!! Error !!! File `$bdf' does not have valid charset!\nIt should have `$vcset-$venc' charset, but it has $cset-$enc!\n\n"; }else{ print "O.K. ($vcset-$venc)\n"; } } validcode( $jis{'bdf'}, $jis{'cset'}, $jis{'enc'}, 'JISX0208', '0'); validcode( $rk{'bdf'}, $rk{'cset'}, $rk{'enc'}, 'JISX0201', '0'); if( !$noascii ){ validcode( $asc{'bdf'}, $asc{'cset'}, $asc{'enc'}, 'ISO8859', '1'); }else{ $tmp = 1; open(TMPI, $rk{'bdf'}); while(){ if( /^STARTCHAR ([a-fA-F0-9]+)$/i && $1 eq '41'){ # 0x41 = 'A' print "\n!!! Warning !!! ASCII (ISO8859-1) font will not be merged.\n\n"; $tmp = 0; last; } } close(TMPI); if( $tmp ){ die "\n!!! Error !!! ASCII (ISO8859-1) font is not specified, and $rk{'bdf'} does not seem to have ASCII characters!\n\n"; } } # # fontboudingbox # print "Checking heights of fontboundingboxes\t... "; if( ($jis{'fbbx_h'} == $rk{'fbbx_h'}) && ($rk{'fbbx_h'} == $asc{'fbbx_h'}) ){ print "O.K. ($jis{'fbbx_h'})\n"; }else{ die "\n!!! Error !!! The heights of FONTBOUNDINGBOXs are different.\n\n"; } print "\n##################################################\n"; print " Calculating Bounding Box Offsets...\n"; print "##################################################\n"; sub max{ my($a, $b, $c) = @_; my($m); $m = $a > $b ? $a : $b; $m = $m > $c ? $m : $c; return( $m ); } sub min{ my($a, $b, $c) = @_; my($m); $m = $a < $b ? $a : $b; $m = $m < $c ? $m : $c; return( $m ); } # height: glyph height $height = max( $jis{'fbbx_h'}, $rk{'fbbx_h'}, $asc{'fbbx_h'} ); $width = max( $jis{'fbbx_w'}, $rk{'fbbx_w'}, $asc{'fbbx_w'} ); $size = $height; $size = $replace if( $replace ); # size: font size # define offset $hmargin = $size - $height; # jis (bbx_y should be 0) if( $hmargin > 0 ){ $jis{'voffset'} = ( $hmargin < abs($jis{'fbbx_y'}) ) ? $hmargin : abs($jis{'fbbx_y'}) ; }else{ $jis{'voffset'} = abs($jis{'fbbx_y'}); } $jis{'hoffset'} = 0; # rk (bbx_y should be 0) if( $hmargin > 0 ){ $rk{'voffset'} = ( $hmargin < abs($rk{'fbbx_y'}) ) ? $hmargin : abs($rk{'fbbx_y'}) ; }else{ $rk{'voffset'} = abs($rk{'fbbx_y'}); } $rk{'hoffset'} = 0; # ascii (bbx_y should be same with japanese, bbx_x should > 0) $asc{'voffset'} = $jis{'voffset'}; if( $asc{'fbbx_x'} < $jis{'fbbx_x'} ){ $asc{'hoffset'} = $jis{'fbbx_x'} - $asc{'fbbx_x'}; }else{ $asc{'hoffset'} = 0; } print "Offset for JIS:\tX[$jis{'hoffset'}], Y[$jis{'voffset'}]\n"; print "Offset for RK: \tX[$rk{'hoffset'}], Y[$rk{'voffset'}]\n"; print "Offset for ASC:\tX[$asc{'hoffset'}], Y[$asc{'voffset'}]\n"; $output_fbbx_y = min( ($jis{'fbbx_y'} + $jis{'voffset'}), ($rk{'fbbx_y'} + $rk{'voffset'}), ($asc{'fbbx_y'} + $asc{'voffset'}) ); $output_fbbx_h = max( ($jis{'fbbx_y'} + $jis{'fbbx_h'} + $jis{'voffset'}), ($rk{'fbbx_y'} + $rk{'fbbx_h'} + $rk{'voffset'}), ($asc{'fbbx_y'} + $asc{'fbbx_h'} + $asc{'voffset'}) ) - $output_fbbx_y; $output_fbbx_x = min( ($jis{'fbbx_x'} + $jis{'hoffset'}), ($rk{'fbbx_x'} + $rk{'hoffset'}), ($asc{'fbbx_x'} + $asc{'hoffset'}) ); $output_fbbx_w = $width; $fontid = "${fontname}${size}"; # # UID # sub genuid { my($r) = int( rand( 251658239 ) ); return ( $r + 16777216 ); } $uid = genuid(); ################################################## # to Unicode BDF ################################################## print "\n##################################################\n"; print " Converting bdf into unicode order...\n"; print "##################################################\n"; $jis{'hex'} = "jis_${base}.hex"; $jis{'uhx'} = "jis_${base}.uhx"; $jis{'uni'} = "jis_${base}.uni"; # bdf $rk{'hex'} = "rk_${base}.hex"; $rk{'uhx'} = "rk_${base}.uhx"; $rk{'uni'} = "rk_${base}.uni"; # bdf if( !$noascii ){ $asc{'hex'} = "asc_${base}.hex"; $asc{'uhx'} = "asc_${base}.uhx"; $asc{'uni'} = "asc_${base}.uni"; # bdf } sub bdf2hex { # stolen from bdf2hex my($infile, $outfile) = @_; open(TMPI, $infile); open(TMPO, ">$outfile"); while(){ if (/^ENCODING\s+(\d+)/) { printf TMPO ("%04X:", $1); } elsif (/^BITMAP/) { $BITMAP=1; } elsif (/^ENDCHAR/) { $BITMAP=0; print TMPO "\n"; } elsif (/^FONTBOUNDINGBOX\s+(\d+)\s+(\d+)/) { print TMPO "$1 $2\n"; } elsif ($BITMAP) { y/a-f/A-F/; s/\n$//; print TMPO "$_"; } } close(TMPI); close(TMPO); } sub hex2bdf { # stolen from hex2bdf my($infile, $outfile) = @_; my(@chars, %glyph); my($character, $charname, $encoding, $len, $aspect, $width, $swidth, $dwidth); open(TMPI, $infile); # while(){ # $glyph{$1} = $2 if /(.{4,}):(.+)\n/; # } while(){ if( /(.{4,}):(.+)\n/ ){ $glyph{$1} = $2; } } @chars = sort keys %glyph; $[ = 1; open(TMPO, ">$outfile"); print TMPO "STARTFONT 2.1\n"; print TMPO "FONT dummy\n"; print TMPO "SIZE $size 75 75\n"; print TMPO "FONTBOUNDINGBOX $size $size $jis{'fbbx_x'} $jis{'fbbx_y'}\n"; print TMPO "CHARS $#chars\n"; foreach $character (@chars){ $encoding = hex($character); $glyph = $glyph{$character}; $len = int(($size - 1) / 8 + 1); $aspect = length($glyph) < $len * $height * 2 ? .5 : 1; $width = length($glyph) / $height / 2; $swidth = 1000 * $aspect; $dwidth = int( $height * $aspect + 0.5 ); # modified $glyph =~ s/((..){$width})/\n$1/g; $character = "$character $charname" if $charname = $charname{pack("n",hex($character))}; print TMPO "STARTCHAR U+$character\n"; print TMPO "ENCODING $encoding\n"; print TMPO "SWIDTH $swidth 0\n"; print TMPO "DWIDTH $dwidth 0\n"; print TMPO "BBX $dwidth $height $jis{'fbbx_x'} $jis{'fbbx_y'}\n"; print TMPO "BITMAP $glyph\n"; print TMPO "ENDCHAR\n"; } close(TMPI); close(TMPO); } sub any2ucs { # stolen from any2ucs my($infile, $table, $outfile) = @_; my($handle_table) = FileHandle->new(); if( !$handle_table->open("$table", 'r')){ unlink( $jis{'hex'} ); unlink( $rk{'hex'} ); die "\n!!! Error !!! Failed to open the table file: $table\n\n"; } my(%table) = (); while( $_ = $handle_table->getline ){ if (/^0x([0-9A-F]{4,})\t+0x([0-9A-F]{4,})/) { $table{uc($1)} = uc($2); } } close( $handle_table ); open(TMPI, $infile); open(TMPO, ">$outfile"); $_ = ; if (/^(\d+)\s+(\d+)/) { print TMPO "$1 $2\n"; } else { die; } while () { if (/^(.{4,}):(.+)$/) { if ($table{$1}) { print TMPO "$table{$1}:$2\n"; } } } close(TMPI); close(TMPO); } print "Converting `$jis{'bdf'}' \t... "; bdf2hex( $jis{'bdf'}, $jis{'hex'} ); any2ucs( $jis{'hex'}, "JIS0208.TXT", $jis{'uhx'} ); unlink( $jis{'hex'} ); hex2bdf( $jis{'uhx'}, $jis{'uni'} ); unlink( $jis{'uhx'} ); print "done.\n"; print "Converting `$rk{'bdf'}' \t... "; bdf2hex( $rk{'bdf'}, $rk{'hex'} ); any2ucs( $rk{'hex'}, "JIS0201.TXT", $rk{'uhx'} ); unlink( $rk{'hex'} ); hex2bdf( $rk{'uhx'}, $rk{'uni'} ); unlink( $rk{'uhx'} ); print "done.\n"; $symbol = 0; if( -r "SYMBOL${height}.HEX" ){ print "Symbol table is found. (SYMBOL${height}.HEX)\n"; $symbol = 1; hex2bdf( "SYMBOL${height}.HEX", "symbol.bdf" ); } ################################################## # Merge BDFs ################################################## print "\n##################################################\n"; print " Merging bdf files ...\n"; print "##################################################\n"; %chars = (); sub bdfmerge_sub { my($bdf, $hoffset, $voffset) = @_; my($char1, $inchar, $inheader, $enc); $inchar = 0; open(TMPI, $bdf); while(){ if (/^startchar\b/i) { $inchar = 1; $char1 = ''; } if ($inchar && /^encoding\s+([-0-9]+)\b/i) { $enc = $1; } if ($inchar && /^(bbx\s+[-0-9]+\s+[-0-9]+)\s+([-0-9]+)\s+([-0-9]+)\b/i ){ $_ = sprintf("$1 %d %d\n", $2+$hoffset, $3+$voffset); } if ($inchar) { $char1 .= $_; } if (/^endchar/i) { $inchar = 0; $chars{$enc} = $char1 if (0 < $enc); } } } sub bdfmerge { my($jis, $rk, $asc, $outfile) = @_; my($char1, $i); if( $symbol ){ bdfmerge_sub("symbol.bdf", $jis{'hoffset'}, $jis{'voffset'}); } bdfmerge_sub($rk, $rk{'hoffset'}, $rk{'voffset'}); if( !$noascii ){ bdfmerge_sub($asc, $asc{'hoffset'}, $asc{'voffset'}); } bdfmerge_sub($jis, $rk{'hoffset'}, $rk{'voffset'}); # # emoji # if( $replace ){ # for( $i = 0xE001; $i <= 0xE539; $i++ ){ # J-Phone for( $i = 0xE001; $i <= 0xE53E; $i++ ){ # Vodafone $char1 = sprintf("STARTCHAR U+%X\nENCODING %d\n", $i, $i); $char1 .= "SWIDTH 1000 0\nDWIDTH ${size} 0\n"; $char1 .= "BBX $jis{'fbbx_w'} $jis{'fbbx_h'} $jis{'fbbx_x'} $jis{'fbbx_y'}\nBITMAP\n"; for( 1..$jis{'fbbx_h'} ){ $char1 .= "00\n"; } $char1 .= "ENDCHAR\n"; $chars{ int($i) } = $char1; } } # end of emoji open(TMPO, ">$outfile"); print TMPO "STARTFONT 2.1\n"; print TMPO "FONT ${fontid}\n"; print TMPO "SIZE $size 75 75\n"; printf TMPO "FONTBOUNDINGBOX %d %d %d %d\n", # $output_fbbx_w, $output_fbbx_h, $output_fbbx_x, $output_fbbx_y; $output_fbbx_w, $size, $output_fbbx_x, $output_fbbx_y; print TMPO "STARTPROPERTIES 4\n"; print TMPO "UID ${uid}\n"; print TMPO "MaxNormalCharWidth $width\n"; print TMPO "Bold 0\n"; print TMPO "Italic 0\n"; print TMPO "ENDPROPERTIES\n"; print TMPO "CHARS ", 0+keys(%chars), "\n"; foreach $i (sort {$a<=>$b} keys(%chars)) { print TMPO $chars{$i}; } print TMPO "ENDFONT\n"; close(TMPO); } $merge_uni = "${base}.bdf"; print "Merging bdfs \t... "; bdfmerge( $jis{'uni'}, $rk{'uni'}, $asc{'bdf'}, $merge_uni ); unlink( $jis{'uni'} ); unlink( $rk{'uni'} ); unlink( "symbol.bdf" ); print "O.K. ($merge_uni)\n"; ################################################## # GD ################################################## print "\n##################################################\n"; print " Generating .gd font definition file ...\n"; print "##################################################\n"; $gd = "${base}.gd"; print "Generating GD file \t... "; open(GD, ">$gd"); print GD <