unifont-6.3.20131215.tar.gz
[unifont.git] / src / unihex2png
1 #!/usr/bin/perl
2
3 #  unihex2png - program to turn a GNU Unifont hex glyph page of 256 code
4 #               points into a PNG file
5 #
6 #  Synopsis: unihex2png [-i in_file.hex] [-o out_file.png]
7 #
8 #
9 #  Author: Paul Hardy, unifoundry <at> unifoundry.com, December 2007
10 #
11 #  Perl conversion: Andrew Miller, August 2013
12 #
13 #
14 #   Copyright (C) 2007-2008 Paul Hardy
15 #
16 #   This program is free software: you can redistribute it and/or modify
17 #   it under the terms of the GNU General Public License as published by
18 #   the Free Software Foundation, either version 2 of the License, or
19 #   (at your option) any later version.
20 #
21 #   This program is distributed in the hope that it will be useful,
22 #   but WITHOUT ANY WARRANTY; without even the implied warranty of
23 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24 #   GNU General Public License for more details.
25 #
26 #   You should have received a copy of the GNU General Public License
27 #   along with this program.  If not, see <http://www.gnu.org/licenses/>.
28
29 use Getopt::Long;
30 use GD;
31
32 $result = GetOptions (
33         "help|?",
34         "input|i=s" => \$input,
35         "output|o=s" => \$output,
36         "page|p=s" => \$page,
37         "rows|r=i" => \$charheight
38 );
39
40 if ($opt_help) {
41         print << "END";
42
43 Turn a GNU Unifont hex glyph page of 256 code points into a PNG file
44
45 Syntax:
46
47    unihex2png -i <Input_File> [-o <Output_File>] [-p <Page>] [-r <Rows>]
48
49    -i, --input      the input hex file (read from STDIN if not specified)
50    -o, --output     the output PNG file
51    -p, --page       the Unicode page to convert - valid values are
52                     0 to 10FF (default is 0)
53    -r, --rows       the height of the output glyphs in pixel rows -
54                     valid values are 16, 24 and 32 (default is 16)
55    -?, --help       display this help and exit
56
57
58 Example:
59
60    unihex2png -i unifont.hex -o u83.png -p 83
61
62 END
63         exit ()
64 }
65
66 #if (not $input) {
67 #       die ("No input file specified\n")
68 #}
69
70 if (not $output) {
71         die ("No output file specified\n")
72 }
73
74 if (not $page) {
75         $page = 0
76 }
77
78 $pagenum = hex ($page);
79
80 if ($pagenum > 0x10FF) {
81         die ("Invalid page\n");
82 }
83
84 $charxoffset = 4;
85 $gridxoffset = 48;
86 $gridyoffset = 32;
87
88 if (not $charheight) {
89         $charheight = 16;
90 }
91
92 if ($charheight == 16) {
93         $charyoffset = 7;
94         $boxsize = 32;
95         $xmax = 2;
96         $ymax = 1;
97         $charmaxwidth = 6;
98 } elsif ($charheight == 24) {
99         $charyoffset = 4;
100         $boxsize = 32;
101         $xmax = 2;
102         $ymax = 2;
103         $charmaxwidth = 6;
104 } elsif ($charheight == 32) {
105         $charyoffset = 4;
106         $boxsize = 40;
107         $xmax = 3;
108         $ymax = 3;
109         $charmaxwidth = 8;
110 } else {
111         die ("Invalid height\n");
112 }
113
114 # Create box and set as tile pattern
115
116 $box = new GD::Image ($boxsize, $boxsize);
117
118 $black = $box->colorAllocate (0, 0, 0);
119 $white = $box->colorAllocate (255, 255, 255);
120
121 $box->filledRectangle (1, 1, $boxsize - 1, $boxsize - 1, $white);
122
123 # Draw dots at 8 pixel boundaries
124  for ($count = 0; $count <= $xmax; $count++) {
125         $box->setPixel (($count * 8) + $charxoffset + 1, 0, $white);
126         $box->setPixel (($count * 8) + $charxoffset + 8, 0, $white);
127 }
128
129 for ($count = 0; $count <= $ymax; $count++) {
130         $box->setPixel (0, ($count * 8) + $charyoffset + 1, $white);
131         $box->setPixel (0, ($count * 8) + $charyoffset + 8, $white);
132 }
133
134 # Draw grid
135
136 $im = new GD::Image ($boxsize * 16 + $gridxoffset, $boxsize * 16 + $gridyoffset);
137
138 $black = $im->colorAllocate (0, 0, 0);
139 $white = $im->colorAllocate (255, 255, 255);
140
141 $im->fill (0, 0, $white);
142
143 for ($xcount = 0; $xcount <= 16; $xcount++) {
144         for ($ycount = 0; $ycount <= 16; $ycount++) {
145                 $im->copy ($box, $xcount * $boxsize + $gridxoffset - 1, $ycount * $boxsize + $gridyoffset - 1, 0, 0, $boxsize, $boxsize);
146         }
147 }
148
149 # Print plane
150 $im->string (gdLargeFont, 8, 9, sprintf ('U+%02X', $pagenum >> 8), $black);
151
152 # Print row headers
153 for ($count = 0; $count <= 15; $count++) {
154         $im->string (gdLargeFont, 32, ($count * $boxsize) + (($boxsize - 16) / 2) + $gridyoffset, sprintf ('%X', $count), $black);
155 }
156
157 # Print column headers
158 for ($count = 0; $count <= 15; $count++) {
159         $im->string (gdLargeFont, ($count * $boxsize) + (($boxsize - 24) / 2) + $gridxoffset, 9, sprintf ('%03X', (($pagenum & 0xFF) << 4) + $count), $black);
160 }
161
162 if ($input) {
163         open (HEXFILE, "$input") or die ('Cannot open file\n');
164 } else {
165    *HEXFILE = *STDIN;
166 }
167
168 while (<HEXFILE>) {
169         chomp;
170         @data = split (':', $_);
171         $codepoint = hex ($data[0]);
172
173         # Calculate if codepoint is within page
174         if ($codepoint >> 8 == $pagenum) {
175                 $char = $data[1];
176
177                 # Calculate character width, column and row
178                 $charwidth = length ($char) / $charheight;
179                 
180                 if ($charwidth <= $charmaxwidth) {
181                         $col = ($codepoint >> 4) & 0xF;
182                         $row = $codepoint & 0xF;
183
184                         for ($j = 0; $j < $charheight; $j++) {
185                                 # Get character row
186                                 $r = hex (substr ($char, $j * $charwidth, $charwidth));
187
188                                 # Draw character
189                                 for ($i = 0; $i < $charwidth * 4; $i++) {
190                                         if ($r & 1 << $i) {
191                                                 $im->setPixel (($col * $boxsize) + ($charwidth * 4 - $i) + $charxoffset + $gridxoffset - 1, ($row * $boxsize) + $j + $charyoffset + $gridyoffset, $black);
192                                         }
193                                 }
194                         }
195                 }
196         }
197 }
198 # Only close input file handler if it isn't STDIN.
199 if ($input) {
200         close HEXFILE;
201 }
202
203 # Save image
204 open (PICTURE, ">$output") or die ("Cannot save image\n");
205 binmode PICTURE;
206 print PICTURE $im->png;
207 close PICTURE;