📄 bitscale.c
字号:
pf->fontPrivate = (pointer) bitmapFont; bitmapFont->version_num = obitmapFont->version_num; bitmapFont->num_chars = nchars; bitmapFont->num_tables = obitmapFont->num_tables; bitmapFont->metrics = 0; bitmapFont->ink_metrics = 0; bitmapFont->bitmaps = 0; bitmapFont->encoding = 0; bitmapFont->bitmapExtra = 0; bitmapFont->pDefault = 0; bitmapFont->metrics = (CharInfoPtr) xalloc(nchars * sizeof(CharInfoRec)); if (!bitmapFont->metrics) goto bail; bitmapFont->encoding = (CharInfoPtr *) xalloc(nchars * sizeof(CharInfoPtr)); if (!bitmapFont->encoding) goto bail;#undef MAXSHORT#define MAXSHORT 32767#undef MINSHORT#define MINSHORT -32768 pfi->anamorphic = FALSE; if (heightMult != widthMult) pfi->anamorphic = TRUE; pfi->cachable = TRUE; if (!compute_xform_matrix(vals, widthMult, heightMult, xform, inv_xform, &xmult, &ymult)) goto bail; pfi->fontAscent = opfi->fontAscent * ymult; pfi->fontDescent = opfi->fontDescent * ymult; pfi->minbounds.leftSideBearing = MAXSHORT; pfi->minbounds.rightSideBearing = MAXSHORT; pfi->minbounds.ascent = MAXSHORT; pfi->minbounds.descent = MAXSHORT; pfi->minbounds.characterWidth = MAXSHORT; pfi->minbounds.attributes = MAXSHORT; pfi->maxbounds.leftSideBearing = MINSHORT; pfi->maxbounds.rightSideBearing = MINSHORT; pfi->maxbounds.ascent = MINSHORT; pfi->maxbounds.descent = MINSHORT; pfi->maxbounds.characterWidth = MINSHORT; pfi->maxbounds.attributes = MINSHORT; /* Compute the transformation and inverse transformation matrices. Can fail if the determinant is zero. */ inkindex1 = 0; pci = bitmapFont->metrics; for (i = 0; i < nchars; i++) { if (opci = obitmapFont->encoding[inkindex2 = OLDINDEX(i)]) { double newlsb, newrsb, newdesc, newasc, point[2];#define minchar(p) ((p).min_char_low + ((p).min_char_high << 8))#define maxchar(p) ((p).max_char_low + ((p).max_char_high << 8)) if (vals->nranges) { int row = i / (lastCol - firstCol + 1) + firstRow; int col = i % (lastCol - firstCol + 1) + firstCol; int ch = (row << 8) + col; int j; for (j = 0; j < vals->nranges; j++) if (ch >= minchar(vals->ranges[j]) && ch <= maxchar(vals->ranges[j])) break; if (j == vals->nranges) { bitmapFont->encoding[i] = 0; continue; } } if (opci->metrics.leftSideBearing == 0 && opci->metrics.rightSideBearing == 0 && opci->metrics.ascent == 0 && opci->metrics.descent == 0 && opci->metrics.characterWidth == 0) { bitmapFont->encoding[i] = 0; continue; } bitmapFont->encoding[i] = pci; /* Compute new extents for this glyph */ TRANSFORM_POINT(xform, opci->metrics.leftSideBearing, -opci->metrics.descent, point); newlsb = point[0]; newrsb = newlsb; newdesc = -point[1]; newasc = -newdesc; TRANSFORM_POINT(xform, opci->metrics.leftSideBearing, opci->metrics.ascent, point); CHECK_EXTENT(newlsb, newrsb, newdesc, newasc, point); TRANSFORM_POINT(xform, opci->metrics.rightSideBearing, -opci->metrics.descent, point); CHECK_EXTENT(newlsb, newrsb, newdesc, newasc, point); TRANSFORM_POINT(xform, opci->metrics.rightSideBearing, opci->metrics.ascent, point); CHECK_EXTENT(newlsb, newrsb, newdesc, newasc, point); pci->metrics.leftSideBearing = (int)floor(newlsb); pci->metrics.rightSideBearing = (int)floor(newrsb + .5); pci->metrics.descent = (int)ceil(newdesc); pci->metrics.ascent = (int)floor(newasc + .5); /* Accumulate total width of characters before transformation, to ascertain predominant direction of font. */ totalwidth += opci->metrics.characterWidth; pci->metrics.characterWidth = doround((double)opci->metrics.characterWidth * xmult); pci->metrics.attributes = doround((double)opci->metrics.characterWidth * sWidthMult); if (!pci->metrics.characterWidth) { /* Since transformation may shrink width, height, and escapement to zero, make sure existing characters are not mistaken for undefined characters. */ if (pci->metrics.rightSideBearing == pci->metrics.leftSideBearing) pci->metrics.rightSideBearing++; if (pci->metrics.ascent == -pci->metrics.descent) pci->metrics.ascent++; } pci++; } else bitmapFont->encoding[i] = 0; } /* * For each character, set the per-character metrics, scale the glyph, and * check per-font minbounds and maxbounds character information. */ pci = bitmapFont->metrics; for (i = 0; i < nchars; i++) { CharInfoRec temppci; if ((pci = bitmapFont->encoding[i]) && (opci = obitmapFont->encoding[OLDINDEX(i)])) { pci = bitmapFont->encoding[i]; totalchars++; *sWidth += abs((int)(INT16)pci->metrics.attributes);#define MINMAX(field) \ if (pfi->minbounds.field > pci->metrics.field) \ pfi->minbounds.field = pci->metrics.field; \ if (pfi->maxbounds.field < pci->metrics.field) \ pfi->maxbounds.field = pci->metrics.field MINMAX(leftSideBearing); MINMAX(rightSideBearing); MINMAX(ascent); MINMAX(descent); MINMAX(characterWidth); /* Hack: Cast attributes into a signed quantity. Tread lightly for now and don't go changing the global Xproto.h file */ if ((INT16)pfi->minbounds.attributes > (INT16)pci->metrics.attributes) pfi->minbounds.attributes = pci->metrics.attributes; if ((INT16)pfi->maxbounds.attributes < (INT16)pci->metrics.attributes) pfi->maxbounds.attributes = pci->metrics.attributes;#undef MINMAX } } pfi->ink_minbounds = pfi->minbounds; pfi->ink_maxbounds = pfi->maxbounds; if (totalchars) { *sWidth = (*sWidth * 10 + totalchars / 2) / totalchars; if (totalwidth < 0) { /* Dominant direction is R->L */ *sWidth = -*sWidth; } if (pfi->minbounds.characterWidth == pfi->maxbounds.characterWidth) vals->width = pfi->minbounds.characterWidth * 10; else vals->width = doround((double)*sWidth * vals->pixel_matrix[0] / 1000.0); } else { vals->width = 0; *sWidth = 0; } FontComputeInfoAccelerators (pfi); if (pfi->defaultCh != (unsigned short) NO_SUCH_CHAR) { unsigned int r, c, cols; r = pfi->defaultCh >> 8; c = pfi->defaultCh & 0xFF; if (pfi->firstRow <= r && r <= pfi->lastRow && pfi->firstCol <= c && c <= pfi->lastCol) { cols = pfi->lastCol - pfi->firstCol + 1; r = r - pfi->firstRow; c = c - pfi->firstCol; bitmapFont->pDefault = bitmapFont->encoding[r * cols + c]; } } *newWidthMult = xmult; *newHeightMult = ymult; return pf;bail: if (pf) xfree(pf); if (bitmapFont) { xfree(bitmapFont->metrics); xfree(bitmapFont->ink_metrics); xfree(bitmapFont->bitmaps); xfree(bitmapFont->encoding); } return NULL;}static intlcm(a, b) /* least common multiple */ int a, b;{ register int m; register int larger, smaller; if (a > b) { m = larger = a; smaller = b; } else { m = larger = b; smaller = a; } while (m % smaller) m += larger; return m;}static voidScaleBitmap(pFont, opci, pci, inv_xform, widthMult, heightMult) FontPtr pFont; CharInfoPtr opci; CharInfoPtr pci; double *inv_xform; double widthMult; double heightMult;{ register char *bitmap, /* The bits */ *newBitmap; register int bpr, /* Padding information */ newBpr; int width, /* Extents information */ height, newWidth, newHeight; register int row, /* Loop variables */ col; INT32 deltaX, /* Increments for resampling loop */ deltaY; INT32 xValue, /* Subscripts for resampling loop */ yValue; double point[2]; unsigned char *char_grayscale = 0; INT32 *diffusion_workspace, *thisrow, *nextrow, pixmult; int box_x, box_y; static unsigned char masklsb[] = { 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80 }; static unsigned char maskmsb[] = { 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1 }; unsigned char *mask = (pFont->bit == LSBFirst ? masklsb : maskmsb); bitmap = opci->bits; newBitmap = pci->bits; width = GLYPHWIDTHPIXELS(opci); height = GLYPHHEIGHTPIXELS(opci); newWidth = GLYPHWIDTHPIXELS(pci); newHeight = GLYPHHEIGHTPIXELS(pci); if (!newWidth || !newHeight || !width || !height) return; bpr = BYTES_PER_ROW(width, pFont->glyph); newBpr = BYTES_PER_ROW(newWidth, pFont->glyph); if (widthMult > 0.0 && heightMult > 0.0 && (widthMult < 1.0 || heightMult < 1.0)) { /* We are reducing in one or both dimensions. In an attempt to reduce aliasing, we'll antialias by passing the original glyph through a low-pass box filter (which results in a grayscale image), then use error diffusion to create bitonal output in the resampling loop. */ /* First compute the sizes of the box filter */ widthMult = ceil(1.0 / widthMult); heightMult = ceil(1.0 / heightMult); box_x = width / 2; box_y = height / 2; if (widthMult < (double)box_x) box_x = (int)widthMult; if (heightMult < (double)box_y) box_y = (int)heightMult; /* The pixmult value (below) is used to darken the image before we perform error diffusion: a necessary concession to the fact that it's very difficult to generate readable halftoned glyphs. The degree of darkening is proportional to the size of the blurring filter, hence inversely proportional to the darkness of the lightest gray that results from antialiasing. The result is that characters that exercise this logic (those generated by reducing from a larger source font) tend to err on the side of being too bold instead of being too light to be readable. */ pixmult = box_x * box_y * 192; if (box_x > 1 || box_y > 1) { /* Looks like we need to anti-alias. Create a workspace to contain the grayscale character plus an additional row and column for scratch */ char_grayscale = (unsigned char *)xalloc((width + 1) * (height + 1)); if (char_grayscale) { diffusion_workspace = (INT32 *)xalloc((newWidth + 2) * 2 * sizeof(int)); if (!diffusion_workspace) { xfree(char_grayscale); char_grayscale = (unsigned char *)0; } /* Initialize our error diffusion workspace for later use */ bzero((char *)diffusion_workspace + sizeof(INT32), (newWidth + 3) * sizeof(int)); thisrow = diffusion_workspace + 1; nextrow = diffusion_workspace + newWidth + 3; } } } if (char_grayscale) { /* We will be doing antialiasing. First copy the bitmap into our buffer, mapping input range [0,1] to output range [0,255]. */ register unsigned char *srcptr, *dstptr; srcptr = (unsigned char *)bitmap; dstptr = char_grayscale; for (row = 0; row < height; row++) { for (col = 0; col < width; col++) *dstptr++ = (srcptr[col >> 3] & mask[col & 0x7]) ? 255 : 0; srcptr += bpr; /* On to next row of source */ dstptr++; /* Skip scratch column in dest */ } if (box_x > 1) { /* Our box filter has a width > 1... let's filter the rows */ int right_width = box_x / 2; int left_width = box_x - right_width - 1; for (row = 0; row < height; row++) { int sum = 0; int left_size = 0, right_size = 0; srcptr = char_grayscale + (width + 1) * row; dstptr = char_grayscale + (width + 1) * height; /* scratch */ /* We've computed the shape of our full box filter. Now compute the right-hand part of the moving sum */ for (right_size = 0; right_size < right_width; right_size++) sum += srcptr[right_size]; /* Now start moving the sum, growing the box filter, and dropping averages into our scratch buffer */ for (left_size = 0; left_size < left_width; left_size++) { sum += srcptr[right_width]; *dstptr++ = sum / (left_size + right_width + 1); srcptr++; } /* The box filter has reached full width... continue computation of moving average until the right side hits the wall. */ for (col = left_size; col + right_size < width; col++) { sum += srcptr[right_width]; *dstptr++ = sum / box_x; sum -= srcptr[-left_width]; srcptr++; } /* Collapse the right side of the box filter */ for (; right_size > 0; right_size--) { *dstptr++ = sum / (left_width + right_size); sum -= srcptr[-left_width]; srcptr++; } /* Done with the row... copy dest back over source */ memmove(char_grayscale + (width + 1) * row, char_grayscale + (width + 1) * height, width); } } if (box_y > 1) { /* Our box filter has a height > 1... let's filter the columns */ int bottom_height = box_y / 2; int top_height = box_y - bottom_height - 1; for (col = 0; col < width; col++) { int sum = 0; int top_size = 0, bottom_size = 0; srcptr = char_grayscale + col; dstptr = char_grayscale + width; /* scratch */ /* We've computed the shape of our full box filter. Now compute the bottom part of the moving sum */ for (bottom_size = 0; bottom_size < bottom_height; bottom_size++) sum += srcptr[bottom_size * (width + 1)]; /* Now start moving the sum, growing the box filter, and dropping averages into our scratch buffer */ for (top_size = 0; top_size < top_height; top_size++) { sum += srcptr[bottom_height * (width + 1)]; *dstptr = sum / (top_size + bottom_height + 1); dstptr += width + 1; srcptr += width + 1; } /* The box filter has reached full height... continue computation of moving average until the bottom hits the wall. */ for (row = top_size; row + bottom_size < height; row++) { sum += srcptr[bottom_height * (width + 1)]; *dstptr = sum / box_y; dstptr += width + 1; sum -= srcptr[-top_height * (width + 1)]; srcptr += width + 1; } /* Collapse the bottom of the box filter */ for (; bottom_size > 0; bottom_size--) { *dstptr = sum / (top_height + bottom_size);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -