static void do_glyphs(deark *c, lctx *d) { struct de_bitmap_font *font = NULL; de_byte *font_data = NULL; de_int64 i; de_int64 glyph_rowspan; font = de_create_bitmap_font(c); font->has_nonunicode_codepoints = 1; font->nominal_width = (int)d->glyph_width; font->nominal_height = (int)d->glyph_height; font->num_chars = d->num_glyphs; // This may increase later glyph_rowspan = (d->glyph_width+7)/8; d->num_chars_alloc = d->num_glyphs; if(d->read_extra_codepoints) d->num_chars_alloc += MAX_EXTRA_CODEPOINTS; d->index_of_first_extra_codepoint = d->num_glyphs; d->num_extra_codepoints = 0; font->char_array = de_malloc(c, d->num_chars_alloc * sizeof(struct de_bitmap_font_char)); font_data = de_malloc(c, d->font_data_size); de_read(font_data, d->headersize, d->font_data_size); for(i=0; i<d->num_chars_alloc; i++) { font->char_array[i].width = font->nominal_width; font->char_array[i].height = font->nominal_height; font->char_array[i].rowspan = glyph_rowspan; if(i<d->num_glyphs) font->char_array[i].codepoint_nonunicode = (de_int32)i; else font->char_array[i].codepoint_nonunicode = DE_INVALID_CODEPOINT; font->char_array[i].codepoint_unicode = DE_INVALID_CODEPOINT; if(i<d->num_glyphs) font->char_array[i].bitmap = &font_data[i*d->bytes_per_glyph]; } if(d->has_unicode_table) { if(d->version==2) do_psf2_unicode_table(c, d, font); else do_psf1_unicode_table(c, d, font); } if(d->num_extra_codepoints>0) { font->num_chars = d->index_of_first_extra_codepoint + d->num_extra_codepoints; de_dbg(c, "codepoints aliases: %d\n", (int)d->num_extra_codepoints); de_dbg(c, "total characters: %d\n", (int)font->num_chars); } de_font_bitmap_font_to_image(c, font, NULL, 0); if(font) { de_free(c, font->char_array); de_destroy_bitmap_font(c, font); } de_free(c, font_data); }
static void de_run_unifont_hex(deark *c, de_module_params *mparams) { struct de_bitmap_font *font = NULL; i64 char_array_numalloc = 0; char linebuf[256]; struct de_linereader *lr = NULL; int ok = 0; font = de_create_bitmap_font(c); font->has_unicode_codepoints = 1; font->prefer_unicode = 1; font->nominal_height = 16; char_array_numalloc = 1024; font->char_array = de_mallocarray(c, char_array_numalloc, sizeof(struct de_bitmap_font_char)); lr = de_linereader_create(c, c->infile); while(de_linereader_readnextline(c, lr, linebuf, sizeof(linebuf), 0)) { i64 idx; struct de_bitmap_font_char *ch; i64 fdata_len; char *dptr; // Pointer into linebuf, to the char after the ":" if(font->num_chars>=17*65536) goto done; idx = font->num_chars; if(idx >= char_array_numalloc) { i64 new_numalloc = char_array_numalloc*2; font->char_array = de_reallocarray(c, font->char_array, char_array_numalloc, sizeof(struct de_bitmap_font_char), new_numalloc); char_array_numalloc = new_numalloc; } ch = &font->char_array[idx]; dptr = de_strchr(linebuf, ':'); if(!dptr) goto done; *dptr = '\0'; dptr++; fdata_len = (i64)de_strlen(dptr); ch->codepoint_unicode = (i32)de_strtoll(linebuf, NULL, 16); if(ch->codepoint_unicode<0 || ch->codepoint_unicode>=17*65536) goto done; ch->width = (int)((fdata_len/32)*8); ch->height = 16; de_dbg2(c, "char[%d] U+%04X %d"DE_CHAR_TIMES"%d", (int)font->num_chars, (unsigned int)ch->codepoint_unicode, ch->width, ch->height); if(ch->width<8 || ch->width>32) goto done; ch->rowspan = (ch->width+7)/8; ch->bitmap = de_malloc(c, ch->rowspan * ch->height); decode_fontdata(c, dptr, ch); font->num_chars++; if(ch->width > font->nominal_width) { font->nominal_width = ch->width; } } de_dbg(c, "number of characters: %d", (int)font->num_chars); if(font->num_chars<1) goto done; if(font->nominal_width<1) goto done; de_font_bitmap_font_to_image(c, font, NULL, 0); ok = 1; done: if(!ok) { de_err(c, "Error parsing HEX font file (offset %"I64_FMT")", lr->f_pos); } de_linereader_destroy(c, lr); if(font) { if(font->char_array) { i64 k; for(k=0; k<font->num_chars; k++) { de_free(c, font->char_array[k].bitmap); } de_free(c, font->char_array); } font->char_array = NULL; de_destroy_bitmap_font(c, font); } }
void de_font_bitmap_font_to_image(deark *c, struct de_bitmap_font *font1, de_finfo *fi, unsigned int createflags) { struct font_render_ctx *fctx = NULL; i64 i, j, k; de_bitmap *img = NULL; i64 xpos, ypos; i64 img_leftmargin, img_topmargin; i64 img_rightmargin, img_bottommargin; i64 img_vpixelsperchar; i64 img_width, img_height; i64 num_table_rows_to_display; i64 num_table_rows_total; i64 last_valid_row; struct de_bitmap_font *dfont = NULL; i64 chars_per_row = 32; const char *s; struct row_info_struct *row_info = NULL; struct col_info_struct *col_info = NULL; int unicode_req = 0; i64 label_stride; i64 rownum, colnum; i64 curpos; unsigned int dnflags; fctx = de_malloc(c, sizeof(struct font_render_ctx)); fctx->font = font1; if(fctx->font->num_chars<1) goto done; if(fctx->font->num_chars>17*65536) goto done; if(fctx->font->nominal_width>512 || fctx->font->nominal_height>512) { de_err(c, "Font size too big (%d"DE_CHAR_TIMES"%d). Not supported.", (int)fctx->font->nominal_width, (int)fctx->font->nominal_height); goto done; } // -1 = "no preference" unicode_req = de_get_ext_option_bool(c, "font:tounicode", -1); if(unicode_req==0 && (fctx->font->has_nonunicode_codepoints || !fctx->font->has_unicode_codepoints)) { ; // Render as nonunicode. } else if(fctx->font->has_unicode_codepoints && (unicode_req>0 || fctx->font->prefer_unicode || !fctx->font->has_nonunicode_codepoints)) { fctx->render_as_unicode = 1; } s = de_get_ext_option(c, "font:charsperrow"); if(s) { chars_per_row = de_atoi64(s); if(chars_per_row<1) chars_per_row=1; } dfont = make_digit_font(c); fctx->codepoint_tmp = de_mallocarray(c, fctx->font->num_chars, sizeof(i32)); fixup_codepoints(c, fctx); get_min_max_codepoint(fctx); if(fctx->num_valid_chars<1) goto done; num_table_rows_total = fctx->max_codepoint/chars_per_row+1; // TODO: Clean up these margin calculations, and make it more general. if(fctx->render_as_unicode) { img_leftmargin = dfont->nominal_width * 5 + 6; } else { if(fctx->max_codepoint >= 1000) img_leftmargin = dfont->nominal_width * 5 + 6; else img_leftmargin = dfont->nominal_width * 3 + 6; } img_topmargin = dfont->nominal_height + 6; img_rightmargin = 1; img_bottommargin = 1; // Scan the characters, and record relevant information. row_info = de_mallocarray(c, num_table_rows_total, sizeof(struct row_info_struct)); col_info = de_mallocarray(c, chars_per_row, sizeof(struct col_info_struct)); for(i=0; i<chars_per_row; i++) { #define MIN_CHAR_CELL_WIDTH 5 col_info[i].display_width = MIN_CHAR_CELL_WIDTH; } for(k=0; k<fctx->font->num_chars; k++) { i64 char_display_width; if(fctx->codepoint_tmp[k] == DE_CODEPOINT_INVALID) continue; if(!is_valid_char(&fctx->font->char_array[k])) continue; rownum = fctx->codepoint_tmp[k] / chars_per_row; colnum = fctx->codepoint_tmp[k] % chars_per_row; if(rownum<0 || rownum>=num_table_rows_total) { de_err(c, "internal: bad rownum"); de_fatalerror(c); } // Remember that there is at least one valid character in this character's row. row_info[rownum].is_visible = 1; // Track the maximum width of any character in this character's column. char_display_width = (i64)(fctx->font->char_array[k].width + (int)fctx->font->char_array[k].extraspace_l + (int)fctx->font->char_array[k].extraspace_r); if(char_display_width > col_info[colnum].display_width) { col_info[colnum].display_width = char_display_width; } } img_vpixelsperchar = fctx->font->nominal_height + 1; // Figure out how many rows are used, and where to draw them. num_table_rows_to_display = 0; last_valid_row = -1; curpos = img_topmargin; for(j=0; j<num_table_rows_total; j++) { if(!row_info[j].is_visible) continue; // If we skipped one or more rows, leave some extra vertical space. if(num_table_rows_to_display>0 && !row_info[j-1].is_visible) curpos+=3; last_valid_row = j; row_info[j].display_pos = curpos; curpos += img_vpixelsperchar; num_table_rows_to_display++; } if(num_table_rows_to_display<1) goto done; // Figure out the positions of the columns. curpos = img_leftmargin; for(i=0; i<chars_per_row; i++) { col_info[i].display_pos = curpos; curpos += col_info[i].display_width + 1; } img_width = col_info[chars_per_row-1].display_pos + col_info[chars_per_row-1].display_width + img_rightmargin; img_height = row_info[last_valid_row].display_pos + img_vpixelsperchar -1 + img_bottommargin; img = de_bitmap_create(c, img_width, img_height, 1); // Clear the image for(j=0; j<img->height; j++) { for(i=0; i<img->width; i++) { de_bitmap_setpixel_gray(img, i, j, 128); } } // Draw/clear the cell backgrounds for(j=0; j<num_table_rows_total; j++) { if(!row_info[j].is_visible) continue; ypos = row_info[j].display_pos; for(i=0; i<chars_per_row; i++) { i64 ii, jj; xpos = col_info[i].display_pos; for(jj=0; jj<img_vpixelsperchar-1; jj++) { for(ii=0; ii<col_info[i].display_width; ii++) { de_bitmap_setpixel_gray(img, xpos+ii, ypos+jj, (ii/2+jj/2)%2 ? 176 : 192); } } } } // Draw the labels in the top margin. // TODO: Better label spacing logic. if(fctx->font->nominal_width <= 12) label_stride = 2; else label_stride = 1; for(i=0; i<chars_per_row; i++) { if(i%label_stride != 0) continue; xpos = col_info[i].display_pos + col_info[i].display_width/2; ypos = img_topmargin - 3; dnflags = DNFLAG_HCENTER; if(fctx->render_as_unicode) dnflags |= DNFLAG_HEX; draw_number(c, img, dfont, i, xpos, ypos, dnflags); } // Draw the labels in the left margin. for(j=0; j<num_table_rows_total; j++) { if(!row_info[j].is_visible) continue; xpos = img_leftmargin - 3; ypos = row_info[j].display_pos + (img_vpixelsperchar + dfont->nominal_height + 1)/2; dnflags = 0; if(fctx->render_as_unicode) dnflags |= DNFLAG_HEX | DNFLAG_LEADING_ZEROES; draw_number(c, img, dfont, j*chars_per_row, xpos, ypos, dnflags); } // Render the glyphs. for(k=0; k<fctx->font->num_chars; k++) { if(fctx->codepoint_tmp[k] == DE_CODEPOINT_INVALID) continue; if(!is_valid_char(&fctx->font->char_array[k])) continue; rownum = fctx->codepoint_tmp[k] / chars_per_row; colnum = fctx->codepoint_tmp[k] % chars_per_row; if(rownum<0 || rownum>=num_table_rows_total) { de_err(c, "internal: bad rownum"); de_fatalerror(c); } xpos = col_info[colnum].display_pos; ypos = row_info[rownum].display_pos; de_font_paint_character_idx(c, img, fctx->font, k, xpos, ypos, DE_STOCKCOLOR_BLACK, DE_STOCKCOLOR_WHITE, 0); } de_bitmap_write_to_file_finfo(img, fi, createflags); done: if(dfont) { de_free(c, dfont->char_array); de_destroy_bitmap_font(c, dfont); } de_bitmap_destroy(img); de_free(c, row_info); de_free(c, col_info); if(fctx) { de_free(c, fctx->codepoint_tmp); de_free(c, fctx); } }
// create bitmap_font object static void do_make_image(deark *c, lctx *d) { struct de_bitmap_font *font = NULL; de_int64 i; de_int64 pos; font = de_create_bitmap_font(c); font->has_nonunicode_codepoints = 1; if(d->encoding!=DE_ENCODING_UNKNOWN) font->has_unicode_codepoints = 1; font->prefer_unicode = 0; font->nominal_width = (int)d->nominal_char_width; font->nominal_height = (int)d->char_height; font->num_chars = d->num_chars_stored; font->char_array = de_malloc(c, font->num_chars * sizeof(struct de_bitmap_font_char)); for(i=0; i<d->num_chars_stored; i++) { de_int64 char_width; de_int64 char_offset; de_int32 char_index; de_int64 num_tiles; de_int64 tile; de_int64 row; pos = d->hdrsize + d->char_entry_size*i; char_width = de_getui16le(pos); if(d->char_entry_size==6) char_offset = de_getui32le(pos+2); else char_offset = de_getui16le(pos+2); de_dbg2(c, "char[%d] width=%d offset=%d\n", (int)(d->first_char + i), (int)char_width, (int)char_offset); num_tiles = (char_width+7)/8; if(i == d->num_chars_stored-1) { // Arbitrarily put the "absolute space" char at codepoint 256, // and U+2002 EN SPACE (best I can do). font->char_array[i].codepoint_nonunicode = 256; font->char_array[i].codepoint_unicode = 0x2002; } else { char_index = (de_int32)d->first_char + (de_int32)i; font->char_array[i].codepoint_nonunicode = char_index; if(font->has_unicode_codepoints) { if(char_index<32 && d->dfCharSet==0) { // This kind of font usually doesn't have glyphs below 32. // If it does, assume that they are VT100 line drawing characters. font->char_array[i].codepoint_unicode = de_char_to_unicode(c, 95+char_index, DE_ENCODING_DEC_SPECIAL_GRAPHICS); } else { font->char_array[i].codepoint_unicode = de_char_to_unicode(c, char_index, d->encoding); } } } font->char_array[i].width = (int)char_width; font->char_array[i].height = (int)d->char_height; font->char_array[i].rowspan = num_tiles; font->char_array[i].bitmap = de_malloc(c, d->char_height * num_tiles); for(row=0; row<d->char_height; row++) { for(tile=0; tile<num_tiles; tile++) { font->char_array[i].bitmap[row * font->char_array[i].rowspan + tile] = de_getbyte(char_offset + tile*d->char_height + row); } } } de_font_bitmap_font_to_image(c, font, d->fi, 0); if(font) { if(font->char_array) { for(i=0; i<font->num_chars; i++) { de_free(c, font->char_array[i].bitmap); } de_free(c, font->char_array); } de_destroy_bitmap_font(c, font); } }