#!/usr/bin/env perl # # BDF -> CJKOS font converter # # Copyright (c) 2003,2006 TSUMURA,Tomoaki. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. Neither the name of TSUMURA Tomoaki nor the names of its contributors # may be used to endorse or promote products derived from this software # without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. $| = 1; $version = '$Id: bdf2cjkos.pl,v 1.11 2006/01/25 09:27:47 tsumura Exp $'; sub usage{ print "Usage: \n"; print "\t$0 bdffile\n\n"; print "\tEx.) $0 jiskan24.bdf\n\n"; exit; } if( $#ARGV < 0 ){ usage(); } print< CJKOS font converter # # (c) 2003,2006 TSUMURA,Tomoaki # ################################################## EoH $bdffile = $ARGV[0]; open(BDF, $bdffile) || die "Can't open BDF file `$bdffile'!\n"; $line = ; if( $line !~ /STARTFONT/i ){ die "File `$bdffile' is not a BDF!\n"; } while( $line !~ /^CHARS /i ){ $line = ; $line =~ s/\r\n//g; chomp($line); if( $line =~ /^PIXEL_SIZE ([0-9]+)$/i ){ $fsize = $1 + 0; }elsif( $line =~ /^FONT (.*)$/i ){ $fontlongname = $1; }elsif( $line =~ /^FOUNDRY (.*)$/i ){ $foundry = $1; $foundry =~ s/\"//g; $foundry =~ s/_//g; }elsif( $line =~ /^CHARSET_REGISTRY (.*)$/i ){ $registry = $1; $registry =~ s/\"//g; }elsif( $line =~ /^FAMILY_NAME (.*)$/i ){ $familyname = $1; $familyname =~ s/\"//g; $familyname =~ s/ //g; }elsif( $line =~ /^WEIGHT_NAME (.*)$/i ){ $weight = $1; $weight =~ s/\"//g; if( $weight =~ /medium/i ){ $weight = ""; }else{ $weight = substr($weight, 0, 1); $weight =~ tr/a-z/A-Z/; } }elsif( $line =~ /^FONTBOUNDINGBOX ([0-9-]+) ([0-9-]+) ([0-9-]+) ([0-9-]+)/i ){ $fbbx_w = $1 + 0; $fbbx_h = $2 + 0; $fbbx_x = $3 + 0; $fbbx_y = $4 + 0; } } print "Font Size check .......... "; if( !defined($fsize) && ($fbbx_w == $fbbx_h) ){ $fsize = $fbbx_w; } if( $fsize != 10 && $fsize != 12 && $fsize != 16 && $fsize != 24 ){ die " ($fsize px)\nFont Size must be 10/12/16/24 !!\nBye.\n"; }else{ printf "O.K. (%d px)\n", $fsize; } print "Charset Registry check ... "; if( !defined($registry) && $fontlongname ){ $fontlongname =~ /-([^-]+)-[0-9]?$/; $registry = $1; } if( $registry !~ /^jisx02/i ){ die " only JIS fonts are supported by this script.\nSorry.\n"; }else{ printf "O.K. (%s)\n", $registry; } if( $foundry eq '' ){ $foundry = 'unknown'; } $pdbfile = "${foundry}${familyname}_${fsize}${weight}.pdb"; open(PDB, ">$pdbfile"); binmode(PDB); ################################################## # PDB Header ################################################## print PDB pack("a32", "CJK Font ${fsize}x${fsize} JapaneseJIS"); # DB name print PDB pack("H*", '0001'); # Flag print PDB pack("H*", '0001'); # Version $time = time() + (66*365+17)*24*60*60; print PDB pack("L", $time); # Create Time print PDB pack("L", $time); # Modified Time print PDB pack("L", $time); # Backup Time print PDB pack("H*", '00000000'); # Modified Num print PDB pack("H*", '00000000'); # App.Info Size print PDB pack("H*", '00000000'); # Sort Info Size print PDB pack("a4",'dFnt'); # Type print PDB pack("a4",'dCJK'); # Creator ID print PDB pack("H*", '00000000'); # Unique ID print PDB pack("H*", '00000000'); # Next Record List ################################################## # Resource Header ################################################## if( $fsize == 10 ){ $resnum = 4; $offset = 120; }elsif( $fsize == 12 ){ $resnum = 4; $offset = 120; $chunkchars = 256; # 256 chars in 1 FBLK }else{ $resnum = 16; $offset = 240; $chunkchars = 64; # 64 chars in 1 FBLK } print PDB pack("H*", sprintf("%04x", $resnum)); # num. of Records # Resource index if( $fsize == 10 ){ $charsize = 13 * 8; $chunksize = 26624; # I don't know why. }else{ $charsize = $fsize * $fsize; $chunksize = $charsize * $chunkchars; } for( $i = 0; $i < $resnum; $i++ ){ # Resource index entry print PDB pack("a4",'FBLK'); print PDB pack("H*", sprintf("%04x", $i)); print PDB pack("H*", sprintf("%08x", ($offset + $i * $chunksize))); } # delimiter print PDB pack("H*", '0000'); ################################################## # Resources ################################################## $nextchar = 8481; # 0x2121 $line = ; while( $line !~ /^ENCODING 8481$/ ){ # search first char (wide space) $line = ; } print "Converting .. |-----------|\b\b\b\b\b\b\b\b\b\b\b\b"; for( $ub = 0x21; $ub <= 0x74; $ub++ ){ printf "%s\b", substr('/-\|', ($ub % 4), 1); if( ! ($ub % 0x8) ){ print '*'; } for( $lb = 0x21; $lb <= 0x7e; $lb++ ){ $char = $ub * 256 + $lb; if( $nextchar > $char ){ # pad EMPTY character print PDB pack("b${charsize}", 0); }else{ while( $line && $line !~ /^BBX/i ){ # search BBX $line = ; $line =~ s/\r\n//g; } $line =~ /^BBX ([0-9-]+) ([0-9-]+) ([0-9-]+) ([0-9-]+)$/i; $bbx_w = $1 + 0; $bbx_h = $2 + 0; $bbx_x = $3 + 0; $bbx_y = $4 + 0; while( $line !~ /^[0-9A-F]+$/i ){ # search BITMAP glyph data $line = ; $line =~ s/\r\n//g; } parsechar( $line ); while( $line && $line !~ /^ENCODING/i ){ # scan next ENCODING $line = ; $line =~ s/\r\n//g; } if( $line ){ # next ENCODING is found $line =~ /^ENCODING ([0-9]+)$/i; $nextchar = $1 + 0; }else{ # not found (EOF of bdf) $nextchar = hex('747f'); } } } } sub parsechar { my($line) = $_[0]; my($marginl) = $bbx_x - $fbbx_x; my($marginr) = $fsize - $marginl - $bbx_w; my($marginb) = $bbx_y - $fbbx_y; my($margint) = $fsize - $bbx_h - $marginb; my(@bitmap, $i); my($dataw, $dec); for( $i = 0; $i < $margint; $i++ ){ $bitmap[$i] = 0; } while( $line !~ /^ENDCHAR/i ){ chomp($line); $dataw = 4 * length($line); $dec = hex($line); if( $dataw < $fsize ){ $dec <<= ($fsize - $dataw); }elsif( $dataw > $fsize ){ $dec >>= ($dataw - $fsize); } if( $marginl > 0 ){ $dec >>= $marginl; } $bitmap[$i] = $dec; # $line = ; $line =~ s/\r\n//g; $i++; } while( $i < $fsize ){ $bitmap[$i] = 0; $i++; } if( $fsize == 10 ){ genchar10( @bitmap ); }else{ genchar( @bitmap ); } } # 10dot font sub genchar10 { my(@bitmap) = @_; my(@L, @R, $i); my($data) = ''; for( $i = 0; $i < $fsize; $i++ ){ $L[$i] = ( $bitmap[$i] >> 2 ); $R[$i] = ( $bitmap[$i] % 4 ); } for( $i = 0; $i < $fsize; $i++ ){ $data .= sprintf("%02x", $L[$i]); } for( $i = 0; $i < 5; $i++ ){ $data .= sprintf("%01x", $R[$i*2]*4+$R[$i*2+1]); } print PDB pack("H*", "${data}0"); } # other size font sub genchar { my(@bitmap) = @_; my($data) = ''; my($i, $fmt); $fmt = sprintf( "%%0%dx", $fsize/4 ); for( $i = 0; $i < $fsize; $i++ ){ $data .= sprintf($fmt, $bitmap[$i]); } print PDB pack("H*", $data); } ################################################## # End ################################################## print "| done.\n"; print "Font file `${pdbfile}' is generated.\n"; close(BDF); close(PDB); # End