9 use GD qw (:DEFAULT :cmp);
15 open (HEXFILE, "$input") or die ("Cannot open hex file for input\n");
19 my @data = split (':', $_);
21 my $codepoint = hex ($data[0]);
23 # my $display_width = $codepoint > 0xFFFF ? 6 : 4;
24 # Use 6-digit codepoint for all glyphs for now
25 my $display_width = 6;
27 $hexlist{sprintf ("%0*X", $display_width, $codepoint)} = $char;
34 my ($hexlist_ref, $pagenum, $charheight) = @_;
35 my %hexlist = %$hexlist_ref;
37 if ($pagenum > 0x10FF) {
38 die ("Invalid page.\n");
44 my ($charyoffset, $boxsize, $xmax, $ymax, $charmaxwidth);
46 if (not $charheight) {
50 if ($charheight == 16) {
56 } elsif ($charheight == 24) {
62 } elsif ($charheight == 32) {
69 die ("Invalid height.\n");
72 # Create box and set as tile pattern
74 my $box = new GD::Image ($boxsize, $boxsize);
76 my $black = $box->colorAllocate (0, 0, 0);
77 my $white = $box->colorAllocate (255, 255, 255);
79 $box->filledRectangle (1, 1, $boxsize - 1, $boxsize - 1, $white);
81 # Draw dots at 8 pixel boundaries
82 for (my $count = 0; $count <= $xmax; $count++) {
83 $box->setPixel (($count * 8) + $charxoffset + 1, 0, $white);
84 $box->setPixel (($count * 8) + $charxoffset + 8, 0, $white);
87 for (my $count = 0; $count <= $ymax; $count++) {
88 $box->setPixel (0, ($count * 8) + $charyoffset + 1, $white);
89 $box->setPixel (0, ($count * 8) + $charyoffset + 8, $white);
94 my $im = new GD::Image ($boxsize * 16 + $gridxoffset, $boxsize * 16 + $gridyoffset);
96 $black = $im->colorAllocate (0, 0, 0);
97 $white = $im->colorAllocate (255, 255, 255);
99 $im->fill (0, 0, $white);
101 for (my $xcount = 0; $xcount <= 16; $xcount++) {
102 for (my $ycount = 0; $ycount <= 16; $ycount++) {
103 $im->copy ($box, $xcount * $boxsize + $gridxoffset - 1, $ycount * $boxsize + $gridyoffset - 1, 0, 0, $boxsize, $boxsize);
108 $im->string (gdLargeFont, 8, 9, sprintf ('U+%02X', $pagenum >> 8), $black);
111 for (my $count = 0; $count <= 15; $count++) {
112 $im->string (gdLargeFont, 32, ($count * $boxsize) + (($boxsize - 16) / 2) + $gridyoffset, sprintf ('%X', $count), $black);
115 # Print column headers
116 for (my $count = 0; $count <= 15; $count++) {
117 $im->string (gdLargeFont, ($count * $boxsize) + (($boxsize - 24) / 2) + $gridxoffset, 9, sprintf ('%03X', (($pagenum & 0xFF) << 4) + $count), $black);
120 while ((my $codepoint, my $char) = each %hexlist) {
121 if ($codepoint and $codepoint =~ m/^[0-9A-F]{4,6}$/) {
122 my $cp = hex ($codepoint);
124 # Calculate if codepoint is within page
125 if ($cp >> 8 == $pagenum) {
126 # Calculate character width, column and row
127 my $charwidth = length ($char) / $charheight;
129 if ($charwidth <= $charmaxwidth) {
130 my $col = ($cp >> 4) & 0xF;
133 for (my $j = 0; $j < $charheight; $j++) {
135 my $r = hex (substr ($char, $j * $charwidth, $charwidth));
138 for (my $i = 0; $i < $charwidth * 4; $i++) {
140 $im->setPixel (($col * $boxsize) + ($charwidth * 4 - $i) + $charxoffset + $gridxoffset - 1, ($row * $boxsize) + $j + $charyoffset + $gridyoffset, $black);
152 package UnifontViewer;
154 use base qw (Wx::App);
155 use Wx qw (wxMINIMIZE_BOX wxSYSTEM_MENU wxCAPTION wxCLOSE_BOX wxCLIP_CHILDREN);
159 my $frame = UnifontViewerFrame->new (
165 wxMINIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLOSE_BOX | wxCLIP_CHILDREN
169 $self->SetTopWindow ($frame);
176 use base qw (Wx::Panel);
177 use fields qw (memdc);
179 use Wx::Event qw (EVT_PAINT);
183 my $self = $class->SUPER::new (@_);
185 $self->{memdc} = Wx::MemoryDC->new ();
187 EVT_PAINT($self, \&OnPaint);
195 $self->{memdc}->Clear ();
200 my ($self, $filename) = @_;
202 my $file = IO::File->new ($filename, 'r');
204 my $handler = Wx::PNGHandler->new ();
205 my $image = Wx::Image->new ();
207 $handler->LoadFile ($image, $file);
208 $bitmap = Wx::Bitmap->new ($image);
210 if ($bitmap->Ok ()) {
211 $self->{memdc}->SelectObject ($bitmap);
217 my ($self, $gd) = @_;
220 open my $fh, '<', \$png or die ("Cannot create PNG file for viewing.\n");
221 my $handler = Wx::PNGHandler->new ();
222 my $image = Wx::Image->new ();
224 $handler->LoadFile ($image, $fh);
225 close $fh or die ("Cannot properly close output file.\n");
226 $bitmap = Wx::Bitmap->new ($image);
228 if ($bitmap->Ok ()) {
229 $self->{memdc}->SelectObject ($bitmap);
235 my ($self, $event) = @_;
236 my $size = $self->GetClientSize ();
238 my $dcPaint = Wx::PaintDC->new ($self);
239 $dcPaint->Blit (0, 0, $size->x, $size->y, $self->{memdc}, 0, 0, wxCOPY, 0);
242 package UnifontViewerFrame;
244 use base qw (Wx::Frame);
245 use fields qw (filename hexlist charheight listbox imagepanel);
246 use Wx::Event qw (EVT_MENU EVT_LISTBOX);
247 use Wx qw (wxBORDER_SIMPLE wxID_OPEN wxID_SAVE wxID_EXIT wxID_OK wxHORIZONTAL wxEXPAND wxALL wxLB_SORT wxFD_OPEN wxFD_SAVE wxFD_FILE_MUST_EXIST wxFD_CHANGE_DIR);
249 our @id = (0 .. 100);
253 my $self = $class->SUPER::new (@_);
254 $self->{filename} = '';
255 $self->{charheight} = 16;
257 my $boxsizer = Wx::BoxSizer->new (wxHORIZONTAL);
259 $self->{listbox} = Wx::ListBox->new (
268 $self->{imagepanel} = ImagePanel->new (
276 SetCharHeight ($self, $self->{charheight});
292 EVT_LISTBOX ($self->{listbox}, -1, sub {
293 my $selection = $self->{listbox}->GetStringSelection ();
294 SetPage ($self, $selection);
297 my $menubar = Wx::MenuBar->new ();
298 my $menu = Wx::Menu->new ();
300 $menu->Append (wxID_OPEN, "O&pen...\tCtrl+O");
301 $menu->Append (wxID_SAVE, "S&ave As...\tCtrl+S");
302 $menu->AppendSeparator ();
303 $menu->AppendRadioItem ($id[0], "Glyph Height 16");
304 $menu->AppendRadioItem ($id[1], "Glyph Height 24");
305 $menu->AppendRadioItem ($id[2], "Glyph Height 32");
306 $menu->AppendSeparator ();
307 $menu->Append (wxID_EXIT, "E&xit\tCtrl+X");
308 $menubar->Append ($menu, 'File');
310 $self->SetMenuBar ($menubar);
312 EVT_MENU ($self, wxID_OPEN, \&OpenFile);
313 EVT_MENU ($self, wxID_SAVE, \&SaveFile);
314 EVT_MENU ($self, $id[0], sub {SetCharHeight ($self, 16)});
315 EVT_MENU ($self, $id[1], sub {SetCharHeight ($self, 24)});
316 EVT_MENU ($self, $id[2], sub {SetCharHeight ($self, 32)});
317 EVT_MENU ($self, wxID_EXIT, sub {$_[0]->Close (1)});
319 $self->SetSizerAndFit ($boxsizer);
325 my ($self, $event) = @_;
327 my $dlg = Wx::FileDialog->new (
332 'Hex files (*.hex)|*.hex',
333 wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_CHANGE_DIR
336 if ($dlg->ShowModal == wxID_OK) {
337 $self->{imagepanel}->clear ();
341 $self->{filename} = $dlg->GetPath ();
342 $self->SetTitle ("Unifont Viewer - " . $dlg->GetFilename ());
344 open HEXFILE, "<$self->{filename}" || die "Cannot open $self->{filename}.\n";
348 my ($codepoint, $char) = (split (':', $_));
349 # For now, list page numbers as 4 digits even for Plane 0 for sorting
350 if (length ($codepoint) == 4) {
351 $codepoint = "00" . $codepoint;
354 if ($codepoint and $codepoint =~ m/^[0-9A-F]{4,6}$/) {
355 if (!($char eq '00542A542A542A542A542A542A542A00' || $char eq 'FFB9C5EDD5D5D5D5D5D5D5D5EDB991FF')) {
356 my $page = substr ($codepoint, 0, -2);
362 $self->{listbox}->Clear ();
364 $self->{listbox}->Append ($_, hex ($_));
367 my %hexlist = Unifont::LoadHexFile ($self->{filename});
368 $self->{hexlist} = \%hexlist;
370 $self->{listbox}->Select (0);
371 my $selection = $self->{listbox}->GetStringSelection ();
372 SetPage ($self, $selection);
377 my ($self, $event) = @_;
379 my $selection = $self->{listbox}->GetStringSelection ();
382 my $dlg = Wx::FileDialog->new (
387 'PNG files (*.png)|*.png',
391 if ($dlg->ShowModal == wxID_OK) {
392 my $im = Unifont::Hex2PNG ($self->{hexlist}, hex ($selection), $self->{charheight});
394 my $filename = $dlg->GetPath ();
396 $self->{imagepanel}->load_gd ($im);
398 open (PICTURE, ">$filename") or die ("Cannot save image.\n");
400 print PICTURE $im->png or die;
401 close PICTURE or die ("Cannot properly close output file.\n");
407 my ($self, $selection) = @_;
410 my $im = Unifont::Hex2PNG ($self->{hexlist}, hex ($selection), $self->{charheight});
411 $self->{imagepanel}->load_gd ($im);
413 $self->{imagepanel}->clear ();
418 my ($self, $charheight) = @_;
420 my $selection = $self->{listbox}->GetStringSelection ();
422 $self->{charheight} = $charheight;
424 if ($charheight == 16 || $charheight == 24) {
427 } elsif ($charheight == 32) {
432 $self->{imagepanel}->SetMinSize ([-1, -1]);
433 $self->{imagepanel}->SetClientSize ($x, $y);
434 $self->{imagepanel}->SetMinSize ($self->{imagepanel}->GetSize ());
437 SetPage ($self, $selection);
442 my ($app) = UnifontViewer->new ();