static uint32_t pk_packed_num(unsigned char** pos) { register int i; uint32_t j; i = (int)getnyb(pos); if (i == 0) { do { j = (uint32_t)getnyb(pos); i++; } while (j == 0); while (i > 0) { j = j * 16 + (uint32_t)getnyb(pos); i--; }; return (j - 15 + (13 - dyn_f) * 16 + dyn_f); } else if (i <= (int)dyn_f) { return ((uint32_t)i); } else if (i < 14) { return ((i-(uint32_t)dyn_f - 1) * 16 + (uint32_t)getnyb(pos) + dyn_f + 1); } else { if (i == 14) { repeatcount = (int)pk_packed_num(pos); } else { repeatcount = 1; } return (pk_packed_num(pos)); /* tail end recursion !! */ } }
static int pk_decode_packed (pdf_obj *stream, long wd, long ht, int dyn_f, int run_color, unsigned char *dp, long pl) { unsigned char *rowptr; long rowbytes; long i, np = 0; long run_count = 0, repeat_count = 0; rowbytes = (wd + 7) / 8; rowptr = NEW(rowbytes, unsigned char); /* repeat count is applied to the *current* row. * "run" can span across rows. * If there are non-zero repeat count and if run * spans across row, first repeat and then continue. */ #ifdef DEBUG MESG("\npkfont>> wd: %ld, ht: %ld, dyn_f: %d\n", wd, ht, dyn_f); #endif for (np = 0, i = 0; i < ht; i++) { long rowbits_left, nbits; repeat_count = 0; memset(rowptr, 0xff, rowbytes); /* 1 is white */ rowbits_left = wd; /* Fill run left over from previous row */ if (run_count > 0) { nbits = MIN(rowbits_left, run_count); switch (run_color) { case 0: rowbits_left -= fill_black_run(rowptr, 0, nbits); break; case 1: rowbits_left -= fill_white_run(rowptr, 0, nbits); break; } run_count -= nbits; } /* Read nybbles until we have a full row */ while (np / 2 < pl && rowbits_left > 0) { int nyb; nyb = (np % 2) ? dp[np/2] & 0x0f : (dp[np/2] >> 4) & 0x0f; #if DEBUG == 3 MESG("\npk_nyb: %d", nyb); #endif if (nyb == 14) { /* packed number "repeat_count" follows */ if (repeat_count != 0) WARN("Second repeat count for this row!"); np++; /* Consume this nybble */ repeat_count = pk_packed_num(&np, dyn_f, dp, pl); #if DEBUG == 3 MESG(" --> rep: %ld\n", repeat_count); #endif } else if (nyb == 15) { if (repeat_count != 0) WARN("Second repeat count for this row!"); np++; /* Consume this nybble */ repeat_count = 1; #if DEBUG == 3 MESG(" --> rep: %ld\n", repeat_count); #endif } else { /* run_count */ /* Interprete current nybble as packed number */ run_count = pk_packed_num(&np, dyn_f, dp, pl); #if DEBUG == 3 MESG(" --> run: %ld (%d)\n", run_count, run_color); #endif nbits = MIN(rowbits_left, run_count); run_color = !run_color; run_count -= nbits; switch (run_color) { case 0: rowbits_left -= fill_black_run(rowptr, wd - rowbits_left, nbits); break; case 1: rowbits_left -= fill_white_run(rowptr, wd - rowbits_left, nbits); break; } } } /* We got bitmap row data. */ #if DEBUG == 2 send_out(rowptr, rowbytes, wd, stream); #else send_out(rowptr, rowbytes, stream); #endif for ( ; i < ht && repeat_count > 0; repeat_count--, i++) #if DEBUG == 2 send_out(rowptr, rowbytes, wd, stream); #else send_out(rowptr, rowbytes, stream); #endif } RELEASE(rowptr); return 0; }
void LoadPK(int32_t c, register struct char_entry * ptr) { unsigned short shrunk_width,shrunk_height; unsigned short width,height; short xoffset,yoffset; unsigned short i_offset,j_offset; int i,j,k,n; int count=0; bool paint_switch; unsigned char *pos,*buffer; DEBUG_PRINT(DEBUG_PK,("\n LOAD PK CHAR\t%d",c)); pos=ptr->pkdata; if ((ptr->flag_byte & 7) == 7) n=4; else if ((ptr->flag_byte & 4) == 4) n=2; else n=1; dyn_f = ptr->flag_byte / 16; paint_switch = ((ptr->flag_byte & 8) != 0); /* * Read character preamble */ if (n != 4) { ptr->tfmw = UNumRead(pos, 3); /* +n: vertical escapement not used */ pos+=3+n; } else { ptr->tfmw = UNumRead(pos, 4); /* +4: horizontal escapement not used */ /* +n: vertical escapement not used */ pos+=8+n; } DEBUG_PRINT(DEBUG_PK,(" %d",ptr->tfmw)); ptr->tfmw = (dviunits) ((int64_t) ptr->tfmw * currentfont->s / 0x100000 ); DEBUG_PRINT(DEBUG_PK,(" (%d)",ptr->tfmw)); width = UNumRead(pos, n); height = UNumRead(pos+=n, n); DEBUG_PRINT(DEBUG_PK,(" %dx%d",width,height)); if (width > 0x7fff || height > 0x7fff) Fatal("character %d too large in file %s", c, currentfont->name); /* * Hotspot issues: Shrinking to the topleft corner rather than the hotspot will displace glyphs a fraction of a pixel. We deal with this in as follows: The glyph is shrunk to its hotspot by offsetting the bitmap somewhat to put the hotspot in the lower left corner of a "shrink square". Shrinking to the topleft corner will then act as shrinking to the hotspot. This may enlarge the bitmap somewhat, of course. (Also remember that the below calculation of i/j_offset is in integer arithmetics.) There will still be a displacement from rounding the dvi position, but vertically it will be equal for all glyphs on a line, so we displace a whole line vertically by fractions of a pixel. This is acceptible, IMHO. Sometime there will be support for subpixel positioning, horizontally. Will do for now, I suppose. */ xoffset = SNumRead(pos+=n, n); i_offset = ( shrinkfactor - xoffset % shrinkfactor ) % shrinkfactor; width += i_offset; ptr->xOffset = xoffset+i_offset; yoffset = SNumRead(pos+=n, n); j_offset = ( shrinkfactor - (yoffset-(shrinkfactor-1)) % shrinkfactor ) % shrinkfactor; height += j_offset; ptr->yOffset = yoffset+j_offset; DEBUG_PRINT(DEBUG_PK,(" (%dx%d)",width,height)); /* Extra marginal so that we do not crop the image when shrinking. */ shrunk_width = (width + shrinkfactor - 1) / shrinkfactor; shrunk_height = (height + shrinkfactor - 1) / shrinkfactor; ptr->w = shrunk_width; ptr->h = shrunk_height; pos+=n; if ((buffer = calloc(shrunk_width*shrunk_height* shrinkfactor*shrinkfactor,sizeof(char)))==NULL) Fatal("cannot allocate space for pk buffer"); DEBUG_PRINT(DEBUG_GLYPH,("\nDRAW GLYPH %d\n", (int)c)); /* Raster char */ if (dyn_f == 14) { /* get raster by bits */ int bitweight = 0; for (j = j_offset; j < (int) height; j++) { /* get all rows */ for (i = i_offset; i < (int) width; i++) { /* get one row */ bitweight /= 2; if (bitweight == 0) { count = *pos++; bitweight = 128; } if (count & bitweight) { buffer[i+j*width]=1; #ifdef DEBUG DEBUG_PRINT(DEBUG_GLYPH,("+")); } else { DEBUG_PRINT(DEBUG_GLYPH,(" ")); #endif } } DEBUG_PRINT(DEBUG_GLYPH,("|\n")); } } else { /* get packed raster */ poshalf=0; repeatcount = 0; for(i=i_offset, j=j_offset; j<height; ) { count = pk_packed_num(&pos); while (count > 0) { if (i+count < width) { if (paint_switch) for(k=0;k<count;k++) { buffer[k+i+j*width]=1; DEBUG_PRINT(DEBUG_GLYPH,("*")); } #ifdef DEBUG else for(k=0;k<count;k++) DEBUG_PRINT(DEBUG_GLYPH,(" ")); #endif i += count; count = 0; } else { if (paint_switch) for(k=i;k<width;k++) { buffer[k+j*width]=1; DEBUG_PRINT(DEBUG_GLYPH,("#")); } #ifdef DEBUG else for(k=i;k<width;k++) DEBUG_PRINT(DEBUG_GLYPH,(" ")); #endif DEBUG_PRINT(DEBUG_GLYPH,("|\n")); j++; count -= width-i; /* Repeat row(s) */ for (;repeatcount>0; repeatcount--,j++) { for (i = i_offset; i<width; i++) { buffer[i+j*width]=buffer[i+(j-1)*width]; #ifdef DEBUG if (buffer[i+j*width]>0) { DEBUG_PRINT(DEBUG_GLYPH,("=")); } else { DEBUG_PRINT(DEBUG_GLYPH,(" ")); } #endif } DEBUG_PRINT(DEBUG_GLYPH,("|\n")); } i=i_offset; } } paint_switch = 1 - paint_switch; } if (i>i_offset) Fatal("wrong number of bits stored: char. %c, font %s", (char)c, currentfont->name); if (j>height) Fatal("bad PK file %s, too many bits", currentfont->name); } /* Shrink raster while doing antialiasing. (See above. The single-glyph output seems better than what xdvi at 300 dpi, shrinkfactor 3 produces.) */ if ((ptr->data = calloc(shrunk_width*shrunk_height,sizeof(char))) == NULL) Fatal("unable to malloc image space for char %c", (char)c); for (j = 0; j < (int) height; j++) { for (i = 0; i < (int) width; i++) { /* if (((i % shrinkfactor) == 0) && ((j % shrinkfactor) == 0)) ptr->data[i/shrinkfactor+j/shrinkfactor*shrunk_width] = buffer[i+j*width]; else */ ptr->data[i/shrinkfactor+j/shrinkfactor*shrunk_width] += buffer[i+j*width]; } } for (j = 0; j < shrunk_height; j++) { for (i = 0; i < shrunk_width; i++) { ptr->data[i+j*shrunk_width] = ptr->data[i+j*shrunk_width] *255/shrinkfactor/shrinkfactor; DEBUG_PRINT(DEBUG_GLYPH,("%3u ",ptr->data[i+j*shrunk_width])); } DEBUG_PRINT(DEBUG_GLYPH,("|\n")); } free(buffer); }