| /*====================================================================* |
| - Copyright (C) 2001 Leptonica. All rights reserved. |
| - This software is distributed in the hope that it will be |
| - useful, but with NO WARRANTY OF ANY KIND. |
| - No author or distributor accepts responsibility to anyone for the |
| - consequences of using this software, or for whether it serves any |
| - particular purpose or works at all, unless he or she says so in |
| - writing. Everyone is granted permission to copy, modify and |
| - redistribute this source code, for commercial or non-commercial |
| - purposes, with the following restrictions: (1) the origin of this |
| - source code must not be misrepresented; (2) modified versions must |
| - be plainly marked as such; and (3) this notice may not be removed |
| - or altered from any source or modified source distribution. |
| *====================================================================*/ |
| |
| /* |
| * graphics.c |
| * |
| * Pta generation for arbitrary shapes built with lines |
| * |
| * PTA *generatePtaLine() |
| * PTA *generatePtaWideLine() |
| * PTA *generatePtaBox() |
| * PTA *generatePtaHashBox() |
| * PTA *generatePtaBoxa() |
| * PTAA *generatePtaaBoxa() |
| * PTAA *generatePtaaHashBoxa() |
| * PTA *generatePtaPolyline() |
| * PTA *generatePtaFilledCircle() |
| * PTA *generatePtaLineFromPt() |
| * l_int32 locatePtRadially() |
| * |
| * Pta rendering |
| * |
| * l_int32 pixRenderPta() |
| * l_int32 pixRenderPtaArb() |
| * l_int32 pixRenderPtaBlend() |
| * |
| * Rendering of arbitrary shapes built with lines |
| * |
| * l_int32 pixRenderLine() |
| * l_int32 pixRenderLineArb() |
| * l_int32 pixRenderLineBlend() |
| * |
| * l_int32 pixRenderBox() |
| * l_int32 pixRenderBoxArb() |
| * l_int32 pixRenderBoxBlend() |
| * |
| * l_int32 pixRenderHashBox() |
| * l_int32 pixRenderHashBoxArb() |
| * l_int32 pixRenderHashBoxBlend() |
| * |
| * l_int32 pixRenderBoxa() |
| * l_int32 pixRenderBoxaArb() |
| * l_int32 pixRenderBoxaBlend() |
| * |
| * l_int32 pixRenderPolyline() |
| * l_int32 pixRenderPolylineArb() |
| * l_int32 pixRenderPolylineBlend() |
| * |
| * l_int32 pixRenderRandomCmapPtaa() |
| * |
| * Contour rendering on grayscale images |
| * |
| * PIX *pixRenderContours() |
| * |
| * The line rendering functions are relatively crude, but they |
| * get the job done for most simple situations. We use the pta |
| * as an intermediate data structure. A pta is generated |
| * for a line. One of two rendering functions are used to |
| * render this onto a Pix. |
| */ |
| |
| #include <stdio.h> |
| #include <string.h> |
| #include <math.h> |
| #include "allheaders.h" |
| |
| |
| |
| /*------------------------------------------------------------------* |
| * Pta generation for arbitrary shapes built with lines * |
| *------------------------------------------------------------------*/ |
| /*! |
| * generatePtaLine() |
| * |
| * Input: x1, y1 (end point 1) |
| * x2, y2 (end point 2) |
| * Return: pta, or null on error |
| */ |
| PTA * |
| generatePtaLine(l_int32 x1, |
| l_int32 y1, |
| l_int32 x2, |
| l_int32 y2) |
| { |
| l_int32 npts, diff, getyofx, sign, i, x, y; |
| l_float32 slope; |
| PTA *pta; |
| |
| PROCNAME("generatePtaLine"); |
| |
| /* Generate line parameters */ |
| if (L_ABS(x2 - x1) >= L_ABS(y2 - y1)) { |
| getyofx = TRUE; |
| npts = L_ABS(x2 - x1) + 1; |
| diff = x2 - x1; |
| sign = L_SIGN(x2 - x1); |
| slope = (l_float32)(sign * (y2 - y1)) / (l_float32)diff; |
| } |
| else { |
| getyofx = FALSE; |
| npts = L_ABS(y2 - y1) + 1; |
| diff = y2 - y1; |
| sign = L_SIGN(y2 - y1); |
| slope = (l_float32)(sign * (x2 - x1)) / (l_float32)diff; |
| } |
| |
| if ((pta = ptaCreate(npts)) == NULL) |
| return (PTA *)ERROR_PTR("pta not made", procName, NULL); |
| |
| if (npts == 1) { /* degenerate case */ |
| ptaAddPt(pta, x1, y1); |
| return pta; |
| } |
| |
| /* Generate the set of points */ |
| if (getyofx) { /* y = y(x) */ |
| for (i = 0; i < npts; i++) { |
| x = x1 + sign * i; |
| y = (l_int32)(y1 + (l_float32)i * slope + 0.5); |
| ptaAddPt(pta, x, y); |
| } |
| } |
| else { /* x = x(y) */ |
| for (i = 0; i < npts; i++) { |
| x = (l_int32)(x1 + (l_float32)i * slope + 0.5); |
| y = y1 + sign * i; |
| ptaAddPt(pta, x, y); |
| } |
| } |
| |
| return pta; |
| } |
| |
| |
| /*! |
| * generatePtaWideLine() |
| * |
| * Input: x1, y1 (end point 1) |
| * x2, y2 (end point 2) |
| * width |
| * Return: ptaj, or null on error |
| */ |
| PTA * |
| generatePtaWideLine(l_int32 x1, |
| l_int32 y1, |
| l_int32 x2, |
| l_int32 y2, |
| l_int32 width) |
| { |
| l_int32 i, x1a, x2a, y1a, y2a; |
| PTA *pta, *ptaj; |
| |
| PROCNAME("generatePtaWideLine"); |
| |
| if (width < 1) { |
| L_WARNING("width < 1; setting to 1", procName); |
| width = 1; |
| } |
| |
| if ((ptaj = generatePtaLine(x1, y1, x2, y2)) == NULL) |
| return (PTA *)ERROR_PTR("ptaj not made", procName, NULL); |
| if (width == 1) |
| return ptaj; |
| |
| /* width > 1; estimate line direction & join */ |
| if (L_ABS(x1 - x2) > L_ABS(y1 - y2)) { /* "horizontal" line */ |
| for (i = 1; i < width; i++) { |
| if ((i & 1) == 1) { /* place above */ |
| y1a = y1 - (i + 1) / 2; |
| y2a = y2 - (i + 1) / 2; |
| } |
| else { /* place below */ |
| y1a = y1 + (i + 1) / 2; |
| y2a = y2 + (i + 1) / 2; |
| } |
| if ((pta = generatePtaLine(x1, y1a, x2, y2a)) == NULL) |
| return (PTA *)ERROR_PTR("pta not made", procName, NULL); |
| ptaJoin(ptaj, pta, 0, 0); |
| ptaDestroy(&pta); |
| } |
| } |
| else { /* "vertical" line */ |
| for (i = 1; i < width; i++) { |
| if ((i & 1) == 1) { /* place to left */ |
| x1a = x1 - (i + 1) / 2; |
| x2a = x2 - (i + 1) / 2; |
| } |
| else { /* place to right */ |
| x1a = x1 + (i + 1) / 2; |
| x2a = x2 + (i + 1) / 2; |
| } |
| if ((pta = generatePtaLine(x1a, y1, x2a, y2)) == NULL) |
| return (PTA *)ERROR_PTR("pta not made", procName, NULL); |
| ptaJoin(ptaj, pta, 0, 0); |
| ptaDestroy(&pta); |
| } |
| } |
| |
| return ptaj; |
| } |
| |
| |
| /*! |
| * generatePtaBox() |
| * |
| * Input: box |
| * width |
| * Return: ptad, or null on error |
| * |
| * Notes: |
| * (1) Because the box is constructed so that we don't have any |
| * overlapping lines, there is no need to remove duplicates. |
| */ |
| PTA * |
| generatePtaBox(BOX *box, |
| l_int32 width) |
| { |
| l_int32 x, y, w, h; |
| PTA *ptad, *pta; |
| |
| PROCNAME("generatePtaBox"); |
| |
| if (!box) |
| return (PTA *)ERROR_PTR("box not defined", procName, NULL); |
| |
| /* Generate line points and add them to the pta. */ |
| boxGetGeometry(box, &x, &y, &w, &h); |
| ptad = ptaCreate(0); |
| if ((width & 1) == 1) { /* odd width */ |
| pta = generatePtaWideLine(x - width / 2, y, |
| x + w - 1 + width / 2, y, width); |
| ptaJoin(ptad, pta, 0, 0); |
| ptaDestroy(&pta); |
| pta = generatePtaWideLine(x + w - 1, y + 1 + width / 2, |
| x + w - 1, y + h - 2 - width / 2, width); |
| ptaJoin(ptad, pta, 0, 0); |
| ptaDestroy(&pta); |
| pta = generatePtaWideLine(x + w - 1 + width / 2, y + h - 1, |
| x - width / 2, y + h - 1, width); |
| ptaJoin(ptad, pta, 0, 0); |
| ptaDestroy(&pta); |
| pta = generatePtaWideLine(x, y + h - 2 - width / 2, |
| x, y + 1 + width / 2, width); |
| ptaJoin(ptad, pta, 0, 0); |
| ptaDestroy(&pta); |
| } |
| else { /* even width */ |
| pta = generatePtaWideLine(x - width / 2, y, |
| x + w - 2 + width / 2, y, width); |
| ptaJoin(ptad, pta, 0, 0); |
| ptaDestroy(&pta); |
| pta = generatePtaWideLine(x + w - 1, y + 0 + width / 2, |
| x + w - 1, y + h - 2 - width / 2, width); |
| ptaJoin(ptad, pta, 0, 0); |
| ptaDestroy(&pta); |
| pta = generatePtaWideLine(x + w - 2 + width / 2, y + h - 1, |
| x - width / 2, y + h - 1, width); |
| ptaJoin(ptad, pta, 0, 0); |
| ptaDestroy(&pta); |
| pta = generatePtaWideLine(x, y + h - 2 - width / 2, |
| x, y + 0 + width / 2, width); |
| ptaJoin(ptad, pta, 0, 0); |
| ptaDestroy(&pta); |
| } |
| |
| return ptad; |
| } |
| |
| |
| /*! |
| * generatePtaHashBox() |
| * |
| * Input: box |
| * spacing (spacing between lines; must be > 1) |
| * width (line width) |
| * orient (orientation of lines: L_HORIZONTAL_LINE, ...) |
| * outline (0 to skip drawing box outline) |
| * Return: ptad, or null on error |
| * |
| * Notes: |
| * (1) The orientation takes on one of 4 orientations (horiz, vertical, |
| * slope +1, slope -1). |
| * (2) The full outline is also drawn if @outline = 1. |
| */ |
| PTA * |
| generatePtaHashBox(BOX *box, |
| l_int32 spacing, |
| l_int32 width, |
| l_int32 orient, |
| l_int32 outline) |
| { |
| l_int32 bx, by, bh, bw, x, y, x1, y1, x2, y2, i, n, npts; |
| PTA *ptad, *pta; |
| |
| PROCNAME("generatePtaHashBox"); |
| |
| if (!box) |
| return (PTA *)ERROR_PTR("box not defined", procName, NULL); |
| if (spacing <= 1) |
| return (PTA *)ERROR_PTR("spacing not > 1", procName, NULL); |
| if (orient != L_HORIZONTAL_LINE && orient != L_POS_SLOPE_LINE && |
| orient != L_VERTICAL_LINE && orient != L_NEG_SLOPE_LINE) |
| return (PTA *)ERROR_PTR("invalid line orientation", procName, NULL); |
| |
| /* Generate line points and add them to the pta. */ |
| boxGetGeometry(box, &bx, &by, &bw, &bh); |
| ptad = ptaCreate(0); |
| if (outline) { |
| pta = generatePtaBox(box, width); |
| ptaJoin(ptad, pta, 0, 0); |
| ptaDestroy(&pta); |
| } |
| if (orient == L_HORIZONTAL_LINE) { |
| n = 1 + bh / spacing; |
| for (i = 0; i < n; i++) { |
| y = by + (i * (bh - 1)) / (n - 1); |
| pta = generatePtaWideLine(bx, y, bx + bw - 1, y, width); |
| ptaJoin(ptad, pta, 0, 0); |
| ptaDestroy(&pta); |
| } |
| } |
| else if (orient == L_VERTICAL_LINE) { |
| n = 1 + bw / spacing; |
| for (i = 0; i < n; i++) { |
| x = bx + (i * (bw - 1)) / (n - 1); |
| pta = generatePtaWideLine(x, by, x, by + bh - 1, width); |
| ptaJoin(ptad, pta, 0, 0); |
| ptaDestroy(&pta); |
| } |
| } |
| else if (orient == L_POS_SLOPE_LINE) { |
| n = 2 + (l_int32)((bw + bh) / (1.4 * spacing)); |
| for (i = 0; i < n; i++) { |
| x = (l_int32)(bx + (i + 0.5) * 1.4 * spacing); |
| boxIntersectByLine(box, x, by - 1, 1.0, &x1, &y1, &x2, &y2, &npts); |
| if (npts == 2) { |
| pta = generatePtaWideLine(x1, y1, x2, y2, width); |
| ptaJoin(ptad, pta, 0, 0); |
| ptaDestroy(&pta); |
| } |
| } |
| } |
| else { /* orient == L_NEG_SLOPE_LINE */ |
| n = 2 + (l_int32)((bw + bh) / (1.4 * spacing)); |
| for (i = 0; i < n; i++) { |
| x = (l_int32)(bx - bh + (i + 0.5) * 1.4 * spacing); |
| boxIntersectByLine(box, x, by - 1, -1.0, &x1, &y1, &x2, &y2, &npts); |
| if (npts == 2) { |
| pta = generatePtaWideLine(x1, y1, x2, y2, width); |
| ptaJoin(ptad, pta, 0, 0); |
| ptaDestroy(&pta); |
| } |
| } |
| } |
| |
| return ptad; |
| } |
| |
| |
| /*! |
| * generatePtaBoxa() |
| * |
| * Input: boxa |
| * width |
| * removedups (1 to remove, 0 to leave) |
| * Return: ptad, or null on error |
| * |
| * Notes: |
| * (1) If the boxa has overlapping boxes, and if blending will |
| * be used to give a transparent effect, transparency |
| * artifacts at line intersections can be removed using |
| * removedups = 1. |
| */ |
| PTA * |
| generatePtaBoxa(BOXA *boxa, |
| l_int32 width, |
| l_int32 removedups) |
| { |
| l_int32 i, n; |
| BOX *box; |
| PTA *ptad, *ptat, *pta; |
| |
| PROCNAME("generatePtaBoxa"); |
| |
| if (!boxa) |
| return (PTA *)ERROR_PTR("boxa not defined", procName, NULL); |
| |
| n = boxaGetCount(boxa); |
| ptat = ptaCreate(0); |
| for (i = 0; i < n; i++) { |
| box = boxaGetBox(boxa, i, L_CLONE); |
| pta = generatePtaBox(box, width); |
| ptaJoin(ptat, pta, 0, 0); |
| ptaDestroy(&pta); |
| boxDestroy(&box); |
| } |
| |
| if (removedups) |
| ptad = ptaRemoveDuplicates(ptat, 0); |
| else |
| ptad = ptaClone(ptat); |
| |
| ptaDestroy(&ptat); |
| return ptad; |
| } |
| |
| |
| /*! |
| * generatePtaaBoxa() |
| * |
| * Input: boxa |
| * Return: ptaa, or null on error |
| * |
| * Notes: |
| * (1) This generates a pta of the four corners for each box in |
| * the boxa. |
| * (2) Each of these pta can be rendered onto a pix with random colors, |
| * by using pixRenderRandomCmapPtaa() with closeflag = 1. |
| */ |
| PTAA * |
| generatePtaaBoxa(BOXA *boxa) |
| { |
| l_int32 i, n, x, y, w, h; |
| BOX *box; |
| PTA *pta; |
| PTAA *ptaa; |
| |
| PROCNAME("generatePtaaBoxa"); |
| |
| if (!boxa) |
| return (PTAA *)ERROR_PTR("boxa not defined", procName, NULL); |
| |
| n = boxaGetCount(boxa); |
| ptaa = ptaaCreate(n); |
| for (i = 0; i < n; i++) { |
| box = boxaGetBox(boxa, i, L_CLONE); |
| boxGetGeometry(box, &x, &y, &w, &h); |
| pta = ptaCreate(4); |
| ptaAddPt(pta, x, y); |
| ptaAddPt(pta, x + w - 1, y); |
| ptaAddPt(pta, x + w - 1, y + h - 1); |
| ptaAddPt(pta, x, y + h - 1); |
| ptaaAddPta(ptaa, pta, L_INSERT); |
| boxDestroy(&box); |
| } |
| |
| return ptaa; |
| } |
| |
| |
| /*! |
| * generatePtaaHashBoxa() |
| * |
| * Input: boxa |
| * spacing (spacing between hash lines; must be > 1) |
| * width (hash line width) |
| * orient (orientation of lines: L_HORIZONTAL_LINE, ...) |
| * outline (0 to skip drawing box outline) |
| * Return: ptaa, or null on error |
| * |
| * Notes: |
| * (1) The orientation takes on one of 4 orientations (horiz, vertical, |
| * slope +1, slope -1). |
| * (2) The full outline is also drawn if @outline = 1. |
| * (3) Each of these pta can be rendered onto a pix with random colors, |
| * by using pixRenderRandomCmapPtaa() with closeflag = 1. |
| * |
| */ |
| PTAA * |
| generatePtaaHashBoxa(BOXA *boxa, |
| l_int32 spacing, |
| l_int32 width, |
| l_int32 orient, |
| l_int32 outline) |
| { |
| l_int32 i, n; |
| BOX *box; |
| PTA *pta; |
| PTAA *ptaa; |
| |
| PROCNAME("generatePtaaHashBoxa"); |
| |
| if (!boxa) |
| return (PTAA *)ERROR_PTR("boxa not defined", procName, NULL); |
| if (spacing <= 1) |
| return (PTAA *)ERROR_PTR("spacing not > 1", procName, NULL); |
| if (orient != L_HORIZONTAL_LINE && orient != L_POS_SLOPE_LINE && |
| orient != L_VERTICAL_LINE && orient != L_NEG_SLOPE_LINE) |
| return (PTAA *)ERROR_PTR("invalid line orientation", procName, NULL); |
| |
| n = boxaGetCount(boxa); |
| ptaa = ptaaCreate(n); |
| for (i = 0; i < n; i++) { |
| box = boxaGetBox(boxa, i, L_CLONE); |
| pta = generatePtaHashBox(box, spacing, width, orient, outline); |
| ptaaAddPta(ptaa, pta, L_INSERT); |
| boxDestroy(&box); |
| } |
| |
| return ptaa; |
| } |
| |
| |
| /*! |
| * generatePtaPolyline() |
| * |
| * Input: pta (vertices of polyline) |
| * width |
| * closeflag (1 to close the contour; 0 otherwise) |
| * removedups (1 to remove, 0 to leave) |
| * Return: ptad, or null on error |
| * |
| * Notes: |
| * (1) If the boxa has overlapping boxes, and if blending will |
| * be used to give a transparent effect, transparency |
| * artifacts at line intersections can be removed using |
| * removedups = 1. |
| */ |
| PTA * |
| generatePtaPolyline(PTA *ptas, |
| l_int32 width, |
| l_int32 closeflag, |
| l_int32 removedups) |
| { |
| l_int32 i, n, x1, y1, x2, y2; |
| PTA *ptad, *ptat, *pta; |
| |
| PROCNAME("generatePtaPolyline"); |
| |
| if (!ptas) |
| return (PTA *)ERROR_PTR("ptas not defined", procName, NULL); |
| |
| n = ptaGetCount(ptas); |
| ptat = ptaCreate(0); |
| if (n < 2) /* nothing to do */ |
| return ptat; |
| |
| ptaGetIPt(ptas, 0, &x1, &y1); |
| for (i = 1; i < n; i++) { |
| ptaGetIPt(ptas, i, &x2, &y2); |
| pta = generatePtaWideLine(x1, y1, x2, y2, width); |
| ptaJoin(ptat, pta, 0, 0); |
| ptaDestroy(&pta); |
| x1 = x2; |
| y1 = y2; |
| } |
| |
| if (closeflag) { |
| ptaGetIPt(ptas, 0, &x2, &y2); |
| pta = generatePtaWideLine(x1, y1, x2, y2, width); |
| ptaJoin(ptat, pta, 0, 0); |
| ptaDestroy(&pta); |
| } |
| |
| if (removedups) |
| ptad = ptaRemoveDuplicates(ptat, 0); |
| else |
| ptad = ptaClone(ptat); |
| |
| ptaDestroy(&ptat); |
| return ptad; |
| } |
| |
| |
| /*! |
| * generatePtaFilledCircle() |
| * |
| * Input: radius |
| * Return: pta, or null on error |
| * |
| * Notes: |
| * (1) The circle is has diameter = 2 * radius + 1. |
| * (2) It is located with the center of the circle at the |
| * point (radius, radius). |
| * (3) Consequently, it typically must be translated if |
| * it is to represent a set of pixels in an image. |
| */ |
| PTA * |
| generatePtaFilledCircle(l_int32 radius) |
| { |
| l_int32 x, y; |
| l_float32 radthresh, sqdist; |
| PTA *pta; |
| |
| PROCNAME("generatePtaFilledCircle"); |
| |
| if (radius < 1) |
| return (PTA *)ERROR_PTR("radius must be >= 1", procName, NULL); |
| |
| pta = ptaCreate(0); |
| radthresh = (radius + 0.5) * (radius + 0.5); |
| for (y = 0; y <= 2 * radius; y++) { |
| for (x = 0; x <= 2 * radius; x++) { |
| sqdist = (l_float32)((y - radius) * (y - radius) + |
| (x - radius) * (x - radius)); |
| if (sqdist <= radthresh) |
| ptaAddPt(pta, x, y); |
| } |
| } |
| |
| return pta; |
| } |
| |
| |
| /*! |
| * generatePtaLineFromPt() |
| * |
| * Input: x, y (point of origination) |
| * length (of line, including starting point) |
| * radang (angle in radians, CW from horizontal) |
| * Return: pta, or null on error |
| * |
| * Notes: |
| * (1) The @length of the line is 1 greater than the distance |
| * used in locatePtRadially(). Example: a distance of 1 |
| * gives rise to a length of 2. |
| */ |
| PTA * |
| generatePtaLineFromPt(l_int32 x, |
| l_int32 y, |
| l_float64 length, |
| l_float64 radang) |
| { |
| l_int32 x2, y2; /* the point at the other end of the line */ |
| |
| x2 = x + (l_int32)((length - 1.0) * cos(radang)); |
| y2 = y + (l_int32)((length - 1.0) * sin(radang)); |
| return generatePtaLine(x, y, x2, y2); |
| } |
| |
| |
| /*! |
| * locatePtRadially() |
| * |
| * Input: xr, yr (reference point) |
| * radang (angle in radians, CW from horizontal) |
| * dist (distance of point from reference point along line |
| * given by the specified angle) |
| * &x, &y (<return> location of point) |
| * Return: 0 if OK, 1 on error |
| */ |
| l_int32 |
| locatePtRadially(l_int32 xr, |
| l_int32 yr, |
| l_float64 dist, |
| l_float64 radang, |
| l_float64 *px, |
| l_float64 *py) |
| { |
| PROCNAME("locatePtRadially"); |
| |
| if (!px || !py) |
| return ERROR_INT("&x and &y not both defined", procName, 1); |
| |
| *px = xr + dist * cos(radang); |
| *py = yr + dist * sin(radang); |
| return 0; |
| } |
| |
| |
| /*------------------------------------------------------------------* |
| * Pta generation for arbitrary shapes built with lines * |
| *------------------------------------------------------------------*/ |
| /*! |
| * pixRenderPta() |
| * |
| * Input: pix |
| * pta (arbitrary set of points) |
| * op (one of L_SET_PIXELS, L_CLEAR_PIXELS, L_FLIP_PIXELS) |
| * Return: 0 if OK, 1 on error |
| * |
| * Notes: |
| * (1) L_SET_PIXELS puts all image bits in each pixel to 1 |
| * (black for 1 bpp; white for depth > 1) |
| * (2) L_CLEAR_PIXELS puts all image bits in each pixel to 0 |
| * (white for 1 bpp; black for depth > 1) |
| * (3) L_FLIP_PIXELS reverses all image bits in each pixel |
| * (4) This function clips the rendering to the pix. It performs |
| * clipping for functions such as pixRenderLine(), |
| * pixRenderBox() and pixRenderBoxa(), that call pixRenderPta(). |
| */ |
| l_int32 |
| pixRenderPta(PIX *pix, |
| PTA *pta, |
| l_int32 op) |
| { |
| l_int32 i, n, x, y, w, h, d, maxval; |
| |
| PROCNAME("pixRenderPta"); |
| |
| if (!pix) |
| return ERROR_INT("pix not defined", procName, 1); |
| if (!pta) |
| return ERROR_INT("pta not defined", procName, 1); |
| if (op != L_SET_PIXELS && op != L_CLEAR_PIXELS && op != L_FLIP_PIXELS) |
| return ERROR_INT("invalid op", procName, 1); |
| |
| pixGetDimensions(pix, &w, &h, &d); |
| maxval = 1; |
| if (op == L_SET_PIXELS) { |
| switch (d) |
| { |
| case 2: |
| maxval = 0x3; |
| break; |
| case 4: |
| maxval = 0xf; |
| break; |
| case 8: |
| maxval = 0xff; |
| break; |
| case 16: |
| maxval = 0xffff; |
| break; |
| case 32: |
| maxval = 0xffffffff; |
| break; |
| } |
| } |
| |
| n = ptaGetCount(pta); |
| for (i = 0; i < n; i++) { |
| ptaGetIPt(pta, i, &x, &y); |
| if (x < 0 || x >= w) |
| continue; |
| if (y < 0 || y >= h) |
| continue; |
| switch (op) |
| { |
| case L_SET_PIXELS: |
| pixSetPixel(pix, x, y, maxval); |
| break; |
| case L_CLEAR_PIXELS: |
| pixClearPixel(pix, x, y); |
| break; |
| case L_FLIP_PIXELS: |
| pixFlipPixel(pix, x, y); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| return 0; |
| } |
| |
| |
| /*! |
| * pixRenderPtaArb() |
| * |
| * Input: pix |
| * pta (arbitrary set of points) |
| * rval, gval, bval |
| * Return: 0 if OK, 1 on error |
| * |
| * Notes: |
| * (1) If pix is colormapped, render this color on each pixel. |
| * (2) If pix is not colormapped, do the best job you can using |
| * the input colors: |
| * - d = 1: set the pixels |
| * - d = 2, 4, 8: average the input rgb value |
| * - d = 32: use the input rgb value |
| * (3) This function clips the rendering to the pix. |
| */ |
| l_int32 |
| pixRenderPtaArb(PIX *pix, |
| PTA *pta, |
| l_uint8 rval, |
| l_uint8 gval, |
| l_uint8 bval) |
| { |
| l_int32 i, n, x, y, w, h, d, index; |
| l_uint8 val; |
| l_uint32 val32; |
| PIXCMAP *cmap; |
| |
| PROCNAME("pixRenderPtaArb"); |
| |
| if (!pix) |
| return ERROR_INT("pix not defined", procName, 1); |
| if (!pta) |
| return ERROR_INT("pta not defined", procName, 1); |
| d = pixGetDepth(pix); |
| if (d != 1 && d != 2 && d != 4 && d != 8 && d != 32) |
| return ERROR_INT("depth not in {1,2,4,8,32}", procName, 1); |
| |
| if (d == 1) { |
| pixRenderPta(pix, pta, L_SET_PIXELS); |
| return 0; |
| } |
| |
| cmap = pixGetColormap(pix); |
| pixGetDimensions(pix, &w, &h, &d); |
| if (cmap) { |
| if (pixcmapAddNewColor(cmap, rval, gval, bval, &index)) |
| return ERROR_INT("colormap is full", procName, 1); |
| } |
| else { |
| if (d == 2) |
| val = (rval + gval + bval) / (3 * 64); |
| else if (d == 4) |
| val = (rval + gval + bval) / (3 * 16); |
| else if (d == 8) |
| val = (rval + gval + bval) / 3; |
| else /* d == 32 */ |
| composeRGBPixel(rval, gval, bval, &val32); |
| } |
| |
| n = ptaGetCount(pta); |
| for (i = 0; i < n; i++) { |
| ptaGetIPt(pta, i, &x, &y); |
| if (x < 0 || x >= w) |
| continue; |
| if (y < 0 || y >= h) |
| continue; |
| if (cmap) |
| pixSetPixel(pix, x, y, index); |
| else if (d == 32) |
| pixSetPixel(pix, x, y, val32); |
| else |
| pixSetPixel(pix, x, y, val); |
| } |
| |
| return 0; |
| } |
| |
| |
| /*! |
| * pixRenderPtaBlend() |
| * |
| * Input: pix (32 bpp rgb) |
| * pta (arbitrary set of points) |
| * rval, gval, bval |
| * Return: 0 if OK, 1 on error |
| * |
| * Notes: |
| * (1) This function clips the rendering to the pix. |
| */ |
| l_int32 |
| pixRenderPtaBlend(PIX *pix, |
| PTA *pta, |
| l_uint8 rval, |
| l_uint8 gval, |
| l_uint8 bval, |
| l_float32 fract) |
| { |
| l_int32 i, n, x, y, w, h; |
| l_uint8 nrval, ngval, nbval; |
| l_uint32 val32; |
| l_float32 frval, fgval, fbval; |
| |
| PROCNAME("pixRenderPtaBlend"); |
| |
| if (!pix) |
| return ERROR_INT("pix not defined", procName, 1); |
| if (!pta) |
| return ERROR_INT("pta not defined", procName, 1); |
| if (pixGetDepth(pix) != 32) |
| return ERROR_INT("depth not 32 bpp", procName, 1); |
| if (fract < 0.0 || fract > 1.0) { |
| L_WARNING("fract must be in [0.0, 1.0]; setting to 0.5", procName); |
| fract = 0.5; |
| } |
| |
| pixGetDimensions(pix, &w, &h, NULL); |
| n = ptaGetCount(pta); |
| frval = fract * rval; |
| fgval = fract * gval; |
| fbval = fract * bval; |
| for (i = 0; i < n; i++) { |
| ptaGetIPt(pta, i, &x, &y); |
| if (x < 0 || x >= w) |
| continue; |
| if (y < 0 || y >= h) |
| continue; |
| pixGetPixel(pix, x, y, &val32); |
| nrval = GET_DATA_BYTE(&val32, COLOR_RED); |
| nrval = (l_uint8)((1. - fract) * nrval + frval); |
| ngval = GET_DATA_BYTE(&val32, COLOR_GREEN); |
| ngval = (l_uint8)((1. - fract) * ngval + fgval); |
| nbval = GET_DATA_BYTE(&val32, COLOR_BLUE); |
| nbval = (l_uint8)((1. - fract) * nbval + fbval); |
| composeRGBPixel(nrval, ngval, nbval, &val32); |
| pixSetPixel(pix, x, y, val32); |
| } |
| |
| return 0; |
| } |
| |
| |
| /*------------------------------------------------------------------* |
| * Rendering of arbitrary shapes built with lines * |
| *------------------------------------------------------------------*/ |
| /*! |
| * pixRenderLine() |
| * |
| * Input: pix |
| * x1, y1 |
| * x2, y2 |
| * width (thickness of line) |
| * op (one of L_SET_PIXELS, L_CLEAR_PIXELS, L_FLIP_PIXELS) |
| * Return: 0 if OK, 1 on error |
| */ |
| l_int32 |
| pixRenderLine(PIX *pix, |
| l_int32 x1, |
| l_int32 y1, |
| l_int32 x2, |
| l_int32 y2, |
| l_int32 width, |
| l_int32 op) |
| { |
| PTA *pta; |
| |
| PROCNAME("pixRenderLine"); |
| |
| if (!pix) |
| return ERROR_INT("pix not defined", procName, 1); |
| if (width < 1) { |
| L_WARNING("width must be > 0; setting to 1", procName); |
| width = 1; |
| } |
| if (op != L_SET_PIXELS && op != L_CLEAR_PIXELS && op != L_FLIP_PIXELS) |
| return ERROR_INT("invalid op", procName, 1); |
| |
| if ((pta = generatePtaWideLine(x1, y1, x2, y2, width)) == NULL) |
| return ERROR_INT("pta not made", procName, 1); |
| pixRenderPta(pix, pta, op); |
| ptaDestroy(&pta); |
| return 0; |
| } |
| |
| |
| /*! |
| * pixRenderLineArb() |
| * |
| * Input: pix |
| * x1, y1 |
| * x2, y2 |
| * width (thickness of line) |
| * rval, gval, bval |
| * Return: 0 if OK, 1 on error |
| */ |
| l_int32 |
| pixRenderLineArb(PIX *pix, |
| l_int32 x1, |
| l_int32 y1, |
| l_int32 x2, |
| l_int32 y2, |
| l_int32 width, |
| l_uint8 rval, |
| l_uint8 gval, |
| l_uint8 bval) |
| { |
| PTA *pta; |
| |
| PROCNAME("pixRenderLineArb"); |
| |
| if (!pix) |
| return ERROR_INT("pix not defined", procName, 1); |
| if (width < 1) { |
| L_WARNING("width must be > 0; setting to 1", procName); |
| width = 1; |
| } |
| |
| if ((pta = generatePtaWideLine(x1, y1, x2, y2, width)) == NULL) |
| return ERROR_INT("pta not made", procName, 1); |
| pixRenderPtaArb(pix, pta, rval, gval, bval); |
| ptaDestroy(&pta); |
| return 0; |
| } |
| |
| |
| /*! |
| * pixRenderLineBlend() |
| * |
| * Input: pix |
| * x1, y1 |
| * x2, y2 |
| * width (thickness of line) |
| * rval, gval, bval |
| * fract |
| * Return: 0 if OK, 1 on error |
| */ |
| l_int32 |
| pixRenderLineBlend(PIX *pix, |
| l_int32 x1, |
| l_int32 y1, |
| l_int32 x2, |
| l_int32 y2, |
| l_int32 width, |
| l_uint8 rval, |
| l_uint8 gval, |
| l_uint8 bval, |
| l_float32 fract) |
| { |
| PTA *pta; |
| |
| PROCNAME("pixRenderLineBlend"); |
| |
| if (!pix) |
| return ERROR_INT("pix not defined", procName, 1); |
| if (width < 1) { |
| L_WARNING("width must be > 0; setting to 1", procName); |
| width = 1; |
| } |
| |
| if ((pta = generatePtaWideLine(x1, y1, x2, y2, width)) == NULL) |
| return ERROR_INT("pta not made", procName, 1); |
| pixRenderPtaBlend(pix, pta, rval, gval, bval, fract); |
| ptaDestroy(&pta); |
| return 0; |
| } |
| |
| |
| /*! |
| * pixRenderBox() |
| * |
| * Input: pix |
| * box |
| * width (thickness of box lines) |
| * op (one of L_SET_PIXELS, L_CLEAR_PIXELS, L_FLIP_PIXELS) |
| * Return: 0 if OK, 1 on error |
| */ |
| l_int32 |
| pixRenderBox(PIX *pix, |
| BOX *box, |
| l_int32 width, |
| l_int32 op) |
| { |
| PTA *pta; |
| |
| PROCNAME("pixRenderBox"); |
| |
| if (!pix) |
| return ERROR_INT("pix not defined", procName, 1); |
| if (!box) |
| return ERROR_INT("box not defined", procName, 1); |
| if (op != L_SET_PIXELS && op != L_CLEAR_PIXELS && op != L_FLIP_PIXELS) |
| return ERROR_INT("invalid op", procName, 1); |
| |
| if ((pta = generatePtaBox(box, width)) == NULL) |
| return ERROR_INT("pta not made", procName, 1); |
| pixRenderPta(pix, pta, op); |
| ptaDestroy(&pta); |
| return 0; |
| } |
| |
| |
| /*! |
| * pixRenderBoxArb() |
| * |
| * Input: pix |
| * box |
| * width (thickness of box lines) |
| * rval, gval, bval |
| * Return: 0 if OK, 1 on error |
| */ |
| l_int32 |
| pixRenderBoxArb(PIX *pix, |
| BOX *box, |
| l_int32 width, |
| l_uint8 rval, |
| l_uint8 gval, |
| l_uint8 bval) |
| { |
| PTA *pta; |
| |
| PROCNAME("pixRenderBoxArb"); |
| |
| if (!pix) |
| return ERROR_INT("pix not defined", procName, 1); |
| if (!box) |
| return ERROR_INT("box not defined", procName, 1); |
| |
| if ((pta = generatePtaBox(box, width)) == NULL) |
| return ERROR_INT("pta not made", procName, 1); |
| pixRenderPtaArb(pix, pta, rval, gval, bval); |
| ptaDestroy(&pta); |
| return 0; |
| } |
| |
| |
| /*! |
| * pixRenderBoxBlend() |
| * |
| * Input: pix |
| * box |
| * width (thickness of box lines) |
| * rval, gval, bval |
| * fract (in [0.0 - 1.0]; complete transparency (no effect) |
| * if 0.0; no transparency if 1.0) |
| * Return: 0 if OK, 1 on error |
| */ |
| l_int32 |
| pixRenderBoxBlend(PIX *pix, |
| BOX *box, |
| l_int32 width, |
| l_uint8 rval, |
| l_uint8 gval, |
| l_uint8 bval, |
| l_float32 fract) |
| { |
| PTA *pta; |
| |
| PROCNAME("pixRenderBoxBlend"); |
| |
| if (!pix) |
| return ERROR_INT("pix not defined", procName, 1); |
| if (!box) |
| return ERROR_INT("box not defined", procName, 1); |
| |
| if ((pta = generatePtaBox(box, width)) == NULL) |
| return ERROR_INT("pta not made", procName, 1); |
| pixRenderPtaBlend(pix, pta, rval, gval, bval, fract); |
| ptaDestroy(&pta); |
| return 0; |
| } |
| |
| |
| /*! |
| * pixRenderHashBox() |
| * |
| * Input: pix |
| * box |
| * spacing (spacing between lines; must be > 1) |
| * width (thickness of box and hash lines) |
| * orient (orientation of lines: L_HORIZONTAL_LINE, ...) |
| * outline (0 to skip drawing box outline) |
| * op (one of L_SET_PIXELS, L_CLEAR_PIXELS, L_FLIP_PIXELS) |
| * Return: 0 if OK, 1 on error |
| */ |
| l_int32 |
| pixRenderHashBox(PIX *pix, |
| BOX *box, |
| l_int32 spacing, |
| l_int32 width, |
| l_int32 orient, |
| l_int32 outline, |
| l_int32 op) |
| { |
| PTA *pta; |
| |
| PROCNAME("pixRenderHashBox"); |
| |
| if (!pix) |
| return ERROR_INT("pix not defined", procName, 1); |
| if (!box) |
| return ERROR_INT("box not defined", procName, 1); |
| if (spacing <= 1) |
| return ERROR_INT("spacing not > 1", procName, 1); |
| if (orient != L_HORIZONTAL_LINE && orient != L_POS_SLOPE_LINE && |
| orient != L_VERTICAL_LINE && orient != L_NEG_SLOPE_LINE) |
| return ERROR_INT("invalid line orientation", procName, 1); |
| if (op != L_SET_PIXELS && op != L_CLEAR_PIXELS && op != L_FLIP_PIXELS) |
| return ERROR_INT("invalid op", procName, 1); |
| |
| pta = generatePtaHashBox(box, spacing, width, orient, outline); |
| if (!pta) |
| return ERROR_INT("pta not made", procName, 1); |
| pixRenderPta(pix, pta, op); |
| ptaDestroy(&pta); |
| return 0; |
| } |
| |
| |
| /*! |
| * pixRenderBoxArb() |
| * |
| * Input: pix |
| * box |
| * spacing (spacing between lines; must be > 1) |
| * width (thickness of box and hash lines) |
| * orient (orientation of lines: L_HORIZONTAL_LINE, ...) |
| * outline (0 to skip drawing box outline) |
| * rval, gval, bval |
| * Return: 0 if OK, 1 on error |
| */ |
| l_int32 |
| pixRenderHashBoxArb(PIX *pix, |
| BOX *box, |
| l_int32 spacing, |
| l_int32 width, |
| l_int32 orient, |
| l_int32 outline, |
| l_int32 rval, |
| l_int32 gval, |
| l_int32 bval) |
| { |
| PTA *pta; |
| |
| PROCNAME("pixRenderHashBoxArb"); |
| |
| if (!pix) |
| return ERROR_INT("pix not defined", procName, 1); |
| if (!box) |
| return ERROR_INT("box not defined", procName, 1); |
| if (spacing <= 1) |
| return ERROR_INT("spacing not > 1", procName, 1); |
| if (orient != L_HORIZONTAL_LINE && orient != L_POS_SLOPE_LINE && |
| orient != L_VERTICAL_LINE && orient != L_NEG_SLOPE_LINE) |
| return ERROR_INT("invalid line orientation", procName, 1); |
| |
| pta = generatePtaHashBox(box, spacing, width, orient, outline); |
| if (!pta) |
| return ERROR_INT("pta not made", procName, 1); |
| pixRenderPtaArb(pix, pta, rval, gval, bval); |
| ptaDestroy(&pta); |
| return 0; |
| } |
| |
| |
| /*! |
| * pixRenderHashBoxBlend() |
| * |
| * Input: pix |
| * box |
| * spacing (spacing between lines; must be > 1) |
| * width (thickness of box and hash lines) |
| * orient (orientation of lines: L_HORIZONTAL_LINE, ...) |
| * outline (0 to skip drawing box outline) |
| * rval, gval, bval |
| * fract (in [0.0 - 1.0]; complete transparency (no effect) |
| * if 0.0; no transparency if 1.0) |
| * Return: 0 if OK, 1 on error |
| */ |
| l_int32 |
| pixRenderHashBoxBlend(PIX *pix, |
| BOX *box, |
| l_int32 spacing, |
| l_int32 width, |
| l_int32 orient, |
| l_int32 outline, |
| l_int32 rval, |
| l_int32 gval, |
| l_int32 bval, |
| l_float32 fract) |
| { |
| PTA *pta; |
| |
| PROCNAME("pixRenderHashBoxBlend"); |
| |
| if (!pix) |
| return ERROR_INT("pix not defined", procName, 1); |
| if (!box) |
| return ERROR_INT("box not defined", procName, 1); |
| if (spacing <= 1) |
| return ERROR_INT("spacing not > 1", procName, 1); |
| if (orient != L_HORIZONTAL_LINE && orient != L_POS_SLOPE_LINE && |
| orient != L_VERTICAL_LINE && orient != L_NEG_SLOPE_LINE) |
| return ERROR_INT("invalid line orientation", procName, 1); |
| |
| pta = generatePtaHashBox(box, spacing, width, orient, outline); |
| if (!pta) |
| return ERROR_INT("pta not made", procName, 1); |
| pixRenderPtaBlend(pix, pta, rval, gval, bval, fract); |
| ptaDestroy(&pta); |
| return 0; |
| } |
| |
| |
| /*! |
| * pixRenderBoxa() |
| * |
| * Input: pix |
| * boxa |
| * width (thickness of line) |
| * op (one of L_SET_PIXELS, L_CLEAR_PIXELS, L_FLIP_PIXELS) |
| * Return: 0 if OK, 1 on error |
| */ |
| l_int32 |
| pixRenderBoxa(PIX *pix, |
| BOXA *boxa, |
| l_int32 width, |
| l_int32 op) |
| { |
| PTA *pta; |
| |
| PROCNAME("pixRenderBoxa"); |
| |
| if (!pix) |
| return ERROR_INT("pix not defined", procName, 1); |
| if (!boxa) |
| return ERROR_INT("boxa not defined", procName, 1); |
| if (op != L_SET_PIXELS && op != L_CLEAR_PIXELS && op != L_FLIP_PIXELS) |
| return ERROR_INT("invalid op", procName, 1); |
| |
| if ((pta = generatePtaBoxa(boxa, width, 0)) == NULL) |
| return ERROR_INT("pta not made", procName, 1); |
| pixRenderPta(pix, pta, op); |
| ptaDestroy(&pta); |
| return 0; |
| } |
| |
| |
| /*! |
| * pixRenderBoxaArb() |
| * |
| * Input: pix |
| * boxa |
| * width (thickness of line) |
| * rval, gval, bval |
| * Return: 0 if OK, 1 on error |
| */ |
| l_int32 |
| pixRenderBoxaArb(PIX *pix, |
| BOXA *boxa, |
| l_int32 width, |
| l_uint8 rval, |
| l_uint8 gval, |
| l_uint8 bval) |
| { |
| PTA *pta; |
| |
| PROCNAME("pixRenderBoxaArb"); |
| |
| if (!pix) |
| return ERROR_INT("pix not defined", procName, 1); |
| if (!boxa) |
| return ERROR_INT("boxa not defined", procName, 1); |
| |
| if ((pta = generatePtaBoxa(boxa, width, 0)) == NULL) |
| return ERROR_INT("pta not made", procName, 1); |
| pixRenderPtaArb(pix, pta, rval, gval, bval); |
| ptaDestroy(&pta); |
| return 0; |
| } |
| |
| |
| /*! |
| * pixRenderBoxaBlend() |
| * |
| * Input: pix |
| * boxa |
| * width (thickness of line) |
| * rval, gval, bval |
| * fract (in [0.0 - 1.0]; complete transparency (no effect) |
| * if 0.0; no transparency if 1.0) |
| * removedups (1 to remove; 0 otherwise) |
| * Return: 0 if OK, 1 on error |
| */ |
| l_int32 |
| pixRenderBoxaBlend(PIX *pix, |
| BOXA *boxa, |
| l_int32 width, |
| l_uint8 rval, |
| l_uint8 gval, |
| l_uint8 bval, |
| l_float32 fract, |
| l_int32 removedups) |
| { |
| PTA *pta; |
| |
| PROCNAME("pixRenderBoxaBlend"); |
| |
| if (!pix) |
| return ERROR_INT("pix not defined", procName, 1); |
| if (!boxa) |
| return ERROR_INT("boxa not defined", procName, 1); |
| |
| if ((pta = generatePtaBoxa(boxa, width, removedups)) == NULL) |
| return ERROR_INT("pta not made", procName, 1); |
| pixRenderPtaBlend(pix, pta, rval, gval, bval, fract); |
| ptaDestroy(&pta); |
| return 0; |
| } |
| |
| |
| /*! |
| * pixRenderPolyline() |
| * |
| * Input: pix |
| * ptas |
| * width (thickness of line) |
| * op (one of L_SET_PIXELS, L_CLEAR_PIXELS, L_FLIP_PIXELS) |
| * closeflag (1 to close the contour; 0 otherwise) |
| * Return: 0 if OK, 1 on error |
| * |
| * Note: this renders a closed contour. |
| */ |
| l_int32 |
| pixRenderPolyline(PIX *pix, |
| PTA *ptas, |
| l_int32 width, |
| l_int32 op, |
| l_int32 closeflag) |
| { |
| PTA *pta; |
| |
| PROCNAME("pixRenderPolyline"); |
| |
| if (!pix) |
| return ERROR_INT("pix not defined", procName, 1); |
| if (!ptas) |
| return ERROR_INT("ptas not defined", procName, 1); |
| if (op != L_SET_PIXELS && op != L_CLEAR_PIXELS && op != L_FLIP_PIXELS) |
| return ERROR_INT("invalid op", procName, 1); |
| |
| if ((pta = generatePtaPolyline(ptas, width, closeflag, 0)) == NULL) |
| return ERROR_INT("pta not made", procName, 1); |
| pixRenderPta(pix, pta, op); |
| ptaDestroy(&pta); |
| return 0; |
| } |
| |
| |
| /*! |
| * pixRenderPolylineArb() |
| * |
| * Input: pix |
| * ptas |
| * width (thickness of line) |
| * rval, gval, bval |
| * closeflag (1 to close the contour; 0 otherwise) |
| * Return: 0 if OK, 1 on error |
| * |
| * Note: this renders a closed contour. |
| */ |
| l_int32 |
| pixRenderPolylineArb(PIX *pix, |
| PTA *ptas, |
| l_int32 width, |
| l_uint8 rval, |
| l_uint8 gval, |
| l_uint8 bval, |
| l_int32 closeflag) |
| { |
| PTA *pta; |
| |
| PROCNAME("pixRenderPolylineArb"); |
| |
| if (!pix) |
| return ERROR_INT("pix not defined", procName, 1); |
| if (!ptas) |
| return ERROR_INT("ptas not defined", procName, 1); |
| |
| if ((pta = generatePtaPolyline(ptas, width, closeflag, 0)) == NULL) |
| return ERROR_INT("pta not made", procName, 1); |
| pixRenderPtaArb(pix, pta, rval, gval, bval); |
| ptaDestroy(&pta); |
| return 0; |
| } |
| |
| |
| /*! |
| * pixRenderPolylineBlend() |
| * |
| * Input: pix |
| * ptas |
| * width (thickness of line) |
| * rval, gval, bval |
| * fract (in [0.0 - 1.0]; complete transparency (no effect) |
| * if 0.0; no transparency if 1.0) |
| * closeflag (1 to close the contour; 0 otherwise) |
| * removedups (1 to remove; 0 otherwise) |
| * Return: 0 if OK, 1 on error |
| */ |
| l_int32 |
| pixRenderPolylineBlend(PIX *pix, |
| PTA *ptas, |
| l_int32 width, |
| l_uint8 rval, |
| l_uint8 gval, |
| l_uint8 bval, |
| l_float32 fract, |
| l_int32 closeflag, |
| l_int32 removedups) |
| { |
| PTA *pta; |
| |
| PROCNAME("pixRenderPolylineBlend"); |
| |
| if (!pix) |
| return ERROR_INT("pix not defined", procName, 1); |
| if (!ptas) |
| return ERROR_INT("ptas not defined", procName, 1); |
| |
| if ((pta = generatePtaPolyline(ptas, width, closeflag, removedups)) == NULL) |
| return ERROR_INT("pta not made", procName, 1); |
| pixRenderPtaBlend(pix, pta, rval, gval, bval, fract); |
| ptaDestroy(&pta); |
| return 0; |
| } |
| |
| |
| /*! |
| * pixRenderRandomCmapPtaa() |
| * |
| * Input: pix (1, 2, 4, 8, 16, 32 bpp) |
| * ptaa |
| * polyflag (1 to interpret each Pta as a polyline; 0 to simply |
| * render the Pta as a set of pixels) |
| * width (thickness of line; use only for polyline) |
| * closeflag (1 to close the contour; 0 otherwise; |
| * use only for polyline mode) |
| * Return: pixd (cmapped, 8 bpp) or null on error |
| * |
| * Notes: |
| * (1) This is a debugging routine, that displays a set of |
| * pixels, selected by the set of Ptas in a Ptaa, |
| * in a random color in a pix. |
| * (2) If @polyflag == 1, each Pta is considered to be a polyline, |
| * and is rendered using @width and @closeflag. Each polyline |
| * is rendered in a random color. |
| * (3) If @polyflag == 0, all points in each Pta are rendered in a |
| * random color. The @width and @closeflag parameters are ignored. |
| * (4) The output pix is 8 bpp and colormapped. Up to 254 |
| * different, randomly selected colors, can be used. |
| * (5) The rendered pixels replace the input pixels. They will |
| * be clipped silently to the input pix. |
| */ |
| PIX * |
| pixRenderRandomCmapPtaa(PIX *pix, |
| PTAA *ptaa, |
| l_int32 polyflag, |
| l_int32 width, |
| l_int32 closeflag) |
| { |
| l_int32 i, n, index, rval, gval, bval; |
| PIXCMAP *cmap; |
| PTA *pta, *ptat; |
| PIX *pixd; |
| |
| PROCNAME("pixRenderRandomCmapPtaa"); |
| |
| if (!pix) |
| return (PIX *)ERROR_PTR("pix not defined", procName, NULL); |
| if (!ptaa) |
| return (PIX *)ERROR_PTR("ptaa not defined", procName, NULL); |
| |
| pixd = pixConvertTo8(pix, FALSE); |
| cmap = pixcmapCreateRandom(8, 1, 1); |
| pixSetColormap(pixd, cmap); |
| |
| if ((n = ptaaGetCount(ptaa)) == 0) |
| return pixd; |
| |
| for (i = 0; i < n; i++) { |
| index = 1 + (i % 254); |
| pixcmapGetColor(cmap, index, &rval, &gval, &bval); |
| pta = ptaaGetPta(ptaa, i, L_CLONE); |
| if (polyflag) |
| ptat = generatePtaPolyline(pta, width, closeflag, 0); |
| else |
| ptat = ptaClone(pta); |
| pixRenderPtaArb(pixd, ptat, rval, gval, bval); |
| ptaDestroy(&pta); |
| ptaDestroy(&ptat); |
| } |
| |
| return pixd; |
| } |
| |
| |
| /*------------------------------------------------------------------* |
| * Contour rendering on grayscale images * |
| *------------------------------------------------------------------*/ |
| /*! |
| * pixRenderContours() |
| * |
| * Input: pixs (8 or 16 bpp) |
| * startval (value of lowest contour; must be in [0 ... maxval]) |
| * incr (increment to next contour; must be > 0) |
| * outdepth (either 1 or depth of pixs) |
| * Return: pixd, or null on error |
| * |
| * The output can be either 1 bpp, showing just the contour |
| * lines, or a copy of the input pixs with the contour lines |
| * superposed. |
| */ |
| PIX * |
| pixRenderContours(PIX *pixs, |
| l_int32 startval, |
| l_int32 incr, |
| l_int32 outdepth) |
| { |
| l_int32 w, h, d, maxval, wpls, wpld, i, j, val, test; |
| l_uint32 *datas, *datad, *lines, *lined; |
| PIX *pixd; |
| |
| PROCNAME("pixRenderContours"); |
| |
| if (!pixs) |
| return (PIX *)ERROR_PTR("pixs not defined", procName, NULL); |
| if (pixGetColormap(pixs)) |
| return (PIX *)ERROR_PTR("pixs has colormap", procName, NULL); |
| d = pixGetDepth(pixs); |
| if (d != 8 && d != 16) |
| return (PIX *)ERROR_PTR("pixs not 8 or 16 bpp", procName, NULL); |
| if (outdepth != 1 && outdepth != d) { |
| L_WARNING("invalid outdepth; setting to 1", procName); |
| outdepth = 1; |
| } |
| maxval = (1 << d) - 1; |
| if (startval < 0 || startval > maxval) |
| return (PIX *)ERROR_PTR("startval not in [0 ... maxval]", |
| procName, NULL); |
| if (incr < 1) |
| return (PIX *)ERROR_PTR("incr < 1", procName, NULL); |
| |
| w = pixGetWidth(pixs); |
| h = pixGetHeight(pixs); |
| if (outdepth == d) |
| pixd = pixCopy(NULL, pixs); |
| else |
| pixd = pixCreate(w, h, 1); |
| |
| pixCopyResolution(pixd, pixs); |
| datad = pixGetData(pixd); |
| wpld = pixGetWpl(pixd); |
| datas = pixGetData(pixs); |
| wpls = pixGetWpl(pixs); |
| |
| switch (d) |
| { |
| case 8: |
| if (outdepth == 1) { |
| for (i = 0; i < h; i++) { |
| lines = datas + i * wpls; |
| lined = datad + i * wpld; |
| for (j = 0; j < w; j++) { |
| val = GET_DATA_BYTE(lines, j); |
| if (val < startval) |
| continue; |
| test = (val - startval) % incr; |
| if (!test) |
| SET_DATA_BIT(lined, j); |
| } |
| } |
| } |
| else { /* outdepth == d */ |
| for (i = 0; i < h; i++) { |
| lines = datas + i * wpls; |
| lined = datad + i * wpld; |
| for (j = 0; j < w; j++) { |
| val = GET_DATA_BYTE(lines, j); |
| if (val < startval) |
| continue; |
| test = (val - startval) % incr; |
| if (!test) |
| SET_DATA_BYTE(lined, j, 0); |
| } |
| } |
| } |
| break; |
| |
| case 16: |
| if (outdepth == 1) { |
| for (i = 0; i < h; i++) { |
| lines = datas + i * wpls; |
| lined = datad + i * wpld; |
| for (j = 0; j < w; j++) { |
| val = GET_DATA_TWO_BYTES(lines, j); |
| if (val < startval) |
| continue; |
| test = (val - startval) % incr; |
| if (!test) |
| SET_DATA_BIT(lined, j); |
| } |
| } |
| } |
| else { /* outdepth == d */ |
| for (i = 0; i < h; i++) { |
| lines = datas + i * wpls; |
| lined = datad + i * wpld; |
| for (j = 0; j < w; j++) { |
| val = GET_DATA_TWO_BYTES(lines, j); |
| if (val < startval) |
| continue; |
| test = (val - startval) % incr; |
| if (!test) |
| SET_DATA_TWO_BYTES(lined, j, 0); |
| } |
| } |
| } |
| break; |
| |
| default: |
| return (PIX *)ERROR_PTR("pixs not 8 or 16 bpp", procName, NULL); |
| } |
| |
| return pixd; |
| } |
| |