main(int argc, char **argv) { char *filein, *fileout, *textstr; l_int32 i, d, size, width, wtext, overflow; l_uint32 val; L_BMF *bmf; PIX *pixs, *pix; static char mainName[] = "renderfonts"; if (argc != 4) exit(ERROR_INT("Syntax: renderfonts filein size fileout", mainName, 1)); filein = argv[1]; size = atoi(argv[2]); fileout = argv[3]; if ((pixs = pixRead(filein)) == NULL) exit(ERROR_INT("pixs not made", mainName, 1)); d = pixGetDepth(pixs); if (d == 8) val = 128; else if (d == 16) val = 0x8000; else if (d == 32) composeRGBPixel(128, 0, 255, &val); else exit(ERROR_INT("pixs not 8, 16 or 32 bpp", mainName, 1)); bmf = bmfCreate(DIRECTORY, size); #if 0 /* render a character of text */ pix = pixaGetPix(bmf->pixa, 45, L_CLONE); startTimer(); for (i = 0; i < 10000; i++) pixSetMaskedGeneral(pixs, pix, val, 150, 150); fprintf(stderr, "time: %7.3f sec\n", stopTimer()); pixWrite(fileout, pixs, IFF_JFIF_JPEG); pixDestroy(&pix); #endif #if 0 /* render a line of text; use marge.jpg with size 14 */ bmfGetStringWidth(bmf, "This is a funny cat!", &width); fprintf(stderr, "String width: %d pixels\n", width); pixSetTextline(pixs, bmf, "This is a funny cat!", 0x8000ff00, 50, 250, &width, &overflow); pixWrite(fileout, pixs, IFF_JFIF_JPEG); fprintf(stderr, "Text width = %d\n", width); if (overflow) fprintf(stderr, "Text overflow beyond image boundary\n"); #endif #if 1 /* render a block of text; use marge.jpg with size 14 */ textstr = stringNew("This is a cat! This is a funny cat! This is a funny funny cat! This is a funny funny funny cat!"); wtext = pixGetWidth(pixs) - 70; pixSetTextblock(pixs, bmf, textstr, 0x4040ff00, 50, 50, wtext, 1, &overflow); pixWrite(fileout, pixs, IFF_JFIF_JPEG); if (overflow) fprintf(stderr, "Text overflow beyond image boundary\n"); lept_free(textstr); #endif pixDestroy(&pixs); bmfDestroy(&bmf); return 0; }
/*! * kernelDisplayInPix() * * Input: kernel * size (of grid interiors; odd; either 1 or a minimum size * of 17 is enforced) * gthick (grid thickness; either 0 or a minimum size of 2 * is enforced) * Return: pix (display of kernel), or null on error * * Notes: * (1) This gives a visual representation of a kernel. * (2) There are two modes of display: * (a) Grid lines of minimum width 2, surrounding regions * representing kernel elements of minimum size 17, * with a "plus" mark at the kernel origin, or * (b) A pix without grid lines and using 1 pixel per kernel element. * (3) For both cases, the kernel absolute value is displayed, * normalized such that the maximum absolute value is 255. * (4) Large 2D separable kernels should be used for convolution * with two 1D kernels. However, for the bilateral filter, * the computation time is independent of the size of the * 2D content kernel. */ PIX * kernelDisplayInPix(L_KERNEL *kel, l_int32 size, l_int32 gthick) { l_int32 i, j, w, h, sx, sy, cx, cy, width, x0, y0; l_int32 normval; l_float32 minval, maxval, max, val, norm; PIX *pixd, *pixt0, *pixt1; PROCNAME("kernelDisplayInPix"); if (!kel) return (PIX *)ERROR_PTR("kernel not defined", procName, NULL); /* Normalize the max value to be 255 for display */ kernelGetParameters(kel, &sy, &sx, &cy, &cx); kernelGetMinMax(kel, &minval, &maxval); max = L_MAX(maxval, -minval); if (max == 0.0) return (PIX *)ERROR_PTR("kernel elements all 0.0", procName, NULL); norm = 255. / (l_float32)max; /* Handle the 1 element/pixel case; typically with large kernels */ if (size == 1 && gthick == 0) { pixd = pixCreate(sx, sy, 8); for (i = 0; i < sy; i++) { for (j = 0; j < sx; j++) { kernelGetElement(kel, i, j, &val); normval = (l_int32)(norm * L_ABS(val)); pixSetPixel(pixd, j, i, normval); } } return pixd; } /* Enforce the constraints for the grid line version */ if (size < 17) { L_WARNING("size < 17; setting to 17\n", procName); size = 17; } if (size % 2 == 0) size++; if (gthick < 2) { L_WARNING("grid thickness < 2; setting to 2\n", procName); gthick = 2; } w = size * sx + gthick * (sx + 1); h = size * sy + gthick * (sy + 1); pixd = pixCreate(w, h, 8); /* Generate grid lines */ for (i = 0; i <= sy; i++) pixRenderLine(pixd, 0, gthick / 2 + i * (size + gthick), w - 1, gthick / 2 + i * (size + gthick), gthick, L_SET_PIXELS); for (j = 0; j <= sx; j++) pixRenderLine(pixd, gthick / 2 + j * (size + gthick), 0, gthick / 2 + j * (size + gthick), h - 1, gthick, L_SET_PIXELS); /* Generate mask for each element */ pixt0 = pixCreate(size, size, 1); pixSetAll(pixt0); /* Generate crossed lines for origin pattern */ pixt1 = pixCreate(size, size, 1); width = size / 8; pixRenderLine(pixt1, size / 2, (l_int32)(0.12 * size), size / 2, (l_int32)(0.88 * size), width, L_SET_PIXELS); pixRenderLine(pixt1, (l_int32)(0.15 * size), size / 2, (l_int32)(0.85 * size), size / 2, width, L_FLIP_PIXELS); pixRasterop(pixt1, size / 2 - width, size / 2 - width, 2 * width, 2 * width, PIX_NOT(PIX_DST), NULL, 0, 0); /* Paste the patterns in */ y0 = gthick; for (i = 0; i < sy; i++) { x0 = gthick; for (j = 0; j < sx; j++) { kernelGetElement(kel, i, j, &val); normval = (l_int32)(norm * L_ABS(val)); pixSetMaskedGeneral(pixd, pixt0, normval, x0, y0); if (i == cy && j == cx) pixPaintThroughMask(pixd, pixt1, x0, y0, 255 - normval); x0 += size + gthick; } y0 += size + gthick; } pixDestroy(&pixt0); pixDestroy(&pixt1); return pixd; }
l_int32 main(int argc, char **argv) { l_int32 bx, by, bw, bh; l_uint32 pixval; BOX *box1, *box2; BOXA *boxa; PIX *pixs, *pixm, *pixd; PIX *pix0, *pix1, *pix2, *pix3, *pix4, *pix5, *pix6; L_REGPARAMS *rp; if (regTestSetup(argc, argv, &rp)) return 1; /* Find a mask for repainting pixels */ pixs = pixRead("amoris.2.150.jpg"); pix1 = MakeReplacementMask(pixs); boxa = pixConnCompBB(pix1, 8); box1 = boxaGetBox(boxa, 0, L_COPY); boxaDestroy(&boxa); /*--------------------------------------------------------* * Show the individual steps * *--------------------------------------------------------*/ /* Locate a good tile to use */ pixFindRepCloseTile(pixs, box1, L_VERT, 20, 30, 7, &box2, 1); pix0 = pixCopy(NULL, pix1); pixRenderBox(pix0, box2, 2, L_SET_PIXELS); /* Make a patch using this tile */ boxGetGeometry(box1, &bx, &by, &bw, &bh); pix2 = pixClipRectangle(pixs, box2, NULL); regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 0 */ pixDisplayWithTitle(pix2, 400, 100, NULL, rp->display); pix3 = pixMirroredTiling(pix2, bw, bh); regTestWritePixAndCheck(rp, pix3, IFF_PNG); /* 1 */ pixDisplayWithTitle(pix3, 1000, 0, NULL, rp->display); /* Paint the patch through the mask */ pixd = pixCopy(NULL, pixs); pixm = pixClipRectangle(pix1, box1, NULL); pixCombineMaskedGeneral(pixd, pix3, pixm, bx, by); regTestWritePixAndCheck(rp, pixd, IFF_PNG); /* 2 */ pixDisplayWithTitle(pixd, 0, 0, NULL, rp->display); boxDestroy(&box2); pixDestroy(&pixm); pixDestroy(&pixd); pixDestroy(&pix2); /* Blend two patches and then overlay. Use the previous * tile found vertically and a new one found horizontally. */ pixFindRepCloseTile(pixs, box1, L_HORIZ, 20, 30, 7, &box2, 1); pixRenderBox(pix0, box2, 2, L_SET_PIXELS); regTestWritePixAndCheck(rp, pix0, IFF_TIFF_G4); /* 3 */ pixDisplayWithTitle(pix0, 100, 100, NULL, rp->display); pix2 = pixClipRectangle(pixs, box2, NULL); pix4 = pixMirroredTiling(pix2, bw, bh); regTestWritePixAndCheck(rp, pix4, IFF_PNG); /* 4 */ pixDisplayWithTitle(pix4, 1100, 0, NULL, rp->display); pix5 = pixBlend(pix3, pix4, 0, 0, 0.5); regTestWritePixAndCheck(rp, pix5, IFF_PNG); /* 5 */ pixDisplayWithTitle(pix5, 1200, 0, NULL, rp->display); pix6 = pixClipRectangle(pix1, box1, NULL); pixd = pixCopy(NULL, pixs); pixCombineMaskedGeneral(pixd, pix5, pix6, bx, by); regTestWritePixAndCheck(rp, pixd, IFF_PNG); /* 6 */ pixDisplayWithTitle(pixd, 700, 200, NULL, rp->display); boxDestroy(&box2); pixDestroy(&pixd); pixDestroy(&pix0); pixDestroy(&pix2); pixDestroy(&pix3); pixDestroy(&pix4); pixDestroy(&pix5); pixDestroy(&pix6); /*--------------------------------------------------------* * Show painting from a color near region * *--------------------------------------------------------*/ pix2 = pixCopy(NULL, pixs); pixGetColorNearMaskBoundary(pix2, pix1, box1, 20, &pixval, 0); pix3 = pixClipRectangle(pix1, box1, NULL); boxGetGeometry(box1, &bx, &by, NULL, NULL); pixSetMaskedGeneral(pix2, pix3, pixval, bx, by); regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 7 */ pixDisplayWithTitle(pix2, 0, 0, NULL, rp->display); boxDestroy(&box1); pixDestroy(&pix2); pixDestroy(&pix3); /*--------------------------------------------------------* * Use the higher-level function * *--------------------------------------------------------*/ /* Use various tile selections and tile blending with one component */ pix2 = pixCopy(NULL, pixs); pix3 = pixCopy(NULL, pixs); pix4 = pixCopy(NULL, pixs); pixPaintSelfThroughMask(pix2, pix1, 0, 0, L_HORIZ, 30, 50, 5, 10); pixPaintSelfThroughMask(pix3, pix1, 0, 0, L_VERT, 30, 50, 5, 0); pixPaintSelfThroughMask(pixs, pix1, 0, 0, L_BOTH_DIRECTIONS, 30, 50, 5, 20); regTestWritePixAndCheck(rp, pix2, IFF_PNG); /* 8 */ regTestWritePixAndCheck(rp, pix3, IFF_PNG); /* 9 */ regTestWritePixAndCheck(rp, pixs, IFF_PNG); /* 10 */ pixDisplayWithTitle(pix2, 300, 0, NULL, rp->display); pixDisplayWithTitle(pix3, 500, 0, NULL, rp->display); pixDisplayWithTitle(pixs, 700, 0, NULL, rp->display); /* Test with two components; */ pix5 = pixFlipLR(NULL, pix1); pixOr(pix5, pix5, pix1); pixPaintSelfThroughMask(pix4, pix5, 0, 0, L_BOTH_DIRECTIONS, 50, 100, 5, 9); regTestWritePixAndCheck(rp, pix4, IFF_PNG); /* 11 */ pixDisplayWithTitle(pix4, 900, 0, NULL, rp->display); pixDestroy(&pixs); pixDestroy(&pix1); pixDestroy(&pix2); pixDestroy(&pix3); pixDestroy(&pix4); pixDestroy(&pix5); return regTestCleanup(rp); }