Leptonica 1.68
C Image Processing Library

graphics.c

Go to the documentation of this file.
00001 /*====================================================================*
00002  -  Copyright (C) 2001 Leptonica.  All rights reserved.
00003  -  This software is distributed in the hope that it will be
00004  -  useful, but with NO WARRANTY OF ANY KIND.
00005  -  No author or distributor accepts responsibility to anyone for the
00006  -  consequences of using this software, or for whether it serves any
00007  -  particular purpose or works at all, unless he or she says so in
00008  -  writing.  Everyone is granted permission to copy, modify and
00009  -  redistribute this source code, for commercial or non-commercial
00010  -  purposes, with the following restrictions: (1) the origin of this
00011  -  source code must not be misrepresented; (2) modified versions must
00012  -  be plainly marked as such; and (3) this notice may not be removed
00013  -  or altered from any source or modified source distribution.
00014  *====================================================================*/
00015 
00016 /*
00017  *  graphics.c
00018  *                     
00019  *      Pta generation for arbitrary shapes built with lines
00020  *
00021  *          PTA        *generatePtaLine()
00022  *          PTA        *generatePtaWideLine()
00023  *          PTA        *generatePtaBox()
00024  *          PTA        *generatePtaHashBox()
00025  *          PTA        *generatePtaBoxa()
00026  *          PTAA       *generatePtaaBoxa()
00027  *          PTAA       *generatePtaaHashBoxa()
00028  *          PTA        *generatePtaPolyline()
00029  *          PTA        *generatePtaFilledCircle()
00030  *          PTA        *generatePtaLineFromPt()
00031  *          l_int32     locatePtRadially()
00032  *
00033  *      Pta rendering
00034  *
00035  *          l_int32     pixRenderPta()
00036  *          l_int32     pixRenderPtaArb()
00037  *          l_int32     pixRenderPtaBlend()
00038  *
00039  *      Rendering of arbitrary shapes built with lines
00040  *
00041  *          l_int32     pixRenderLine()
00042  *          l_int32     pixRenderLineArb()
00043  *          l_int32     pixRenderLineBlend()
00044  *
00045  *          l_int32     pixRenderBox()
00046  *          l_int32     pixRenderBoxArb()
00047  *          l_int32     pixRenderBoxBlend()
00048  *
00049  *          l_int32     pixRenderHashBox()
00050  *          l_int32     pixRenderHashBoxArb()
00051  *          l_int32     pixRenderHashBoxBlend()
00052  *
00053  *          l_int32     pixRenderBoxa()
00054  *          l_int32     pixRenderBoxaArb()
00055  *          l_int32     pixRenderBoxaBlend()
00056  *
00057  *          l_int32     pixRenderPolyline()
00058  *          l_int32     pixRenderPolylineArb()
00059  *          l_int32     pixRenderPolylineBlend()
00060  *
00061  *          l_int32     pixRenderRandomCmapPtaa()
00062  *
00063  *      Contour rendering on grayscale images
00064  *
00065  *          PIX        *pixRenderContours()
00066  *          PIX        *fpixRenderContours()
00067  *
00068  *  The line rendering functions are relatively crude, but they
00069  *  get the job done for most simple situations.  We use the pta
00070  *  as an intermediate data structure.  A pta is generated
00071  *  for a line.  One of two rendering functions are used to
00072  *  render this onto a Pix.
00073  */
00074 
00075 #include <stdio.h>
00076 #include <string.h>
00077 #include <math.h>
00078 #include "allheaders.h"
00079 
00080 
00081 
00082 /*------------------------------------------------------------------*
00083  *        Pta generation for arbitrary shapes built with lines      *
00084  *------------------------------------------------------------------*/
00085 /*!
00086  *  generatePtaLine()
00087  *
00088  *      Input:  x1, y1  (end point 1)
00089  *              x2, y2  (end point 2)
00090  *      Return: pta, or null on error
00091  */
00092 PTA  *
00093 generatePtaLine(l_int32  x1,
00094                 l_int32  y1,
00095                 l_int32  x2,
00096                 l_int32  y2)
00097 {
00098 l_int32    npts, diff, getyofx, sign, i, x, y;
00099 l_float32  slope;
00100 PTA       *pta;
00101 
00102     PROCNAME("generatePtaLine");
00103 
00104         /* Generate line parameters */
00105     if (L_ABS(x2 - x1) >= L_ABS(y2 - y1)) {
00106         getyofx = TRUE;
00107         npts = L_ABS(x2 - x1) + 1;
00108         diff = x2 - x1;
00109         sign = L_SIGN(x2 - x1);
00110         slope = (l_float32)(sign * (y2 - y1)) / (l_float32)diff;
00111     }
00112     else {
00113         getyofx = FALSE;
00114         npts = L_ABS(y2 - y1) + 1;
00115         diff = y2 - y1;
00116         sign = L_SIGN(y2 - y1);
00117         slope = (l_float32)(sign * (x2 - x1)) / (l_float32)diff;
00118     }
00119 
00120     if ((pta = ptaCreate(npts)) == NULL)
00121         return (PTA *)ERROR_PTR("pta not made", procName, NULL);
00122 
00123     if (npts == 1) {  /* degenerate case */
00124         ptaAddPt(pta, x1, y1);
00125         return pta;
00126     }
00127 
00128         /* Generate the set of points */
00129     if (getyofx) {  /* y = y(x) */
00130         for (i = 0; i < npts; i++) {
00131             x = x1 + sign * i;
00132             y = (l_int32)(y1 + (l_float32)i * slope + 0.5);
00133             ptaAddPt(pta, x, y);
00134         }
00135     }
00136     else {   /* x = x(y) */
00137         for (i = 0; i < npts; i++) {
00138             x = (l_int32)(x1 + (l_float32)i * slope + 0.5);
00139             y = y1 + sign * i;
00140             ptaAddPt(pta, x, y);
00141         }
00142     }
00143 
00144     return pta;
00145 }
00146 
00147 
00148 /*!
00149  *  generatePtaWideLine()
00150  *
00151  *      Input:  x1, y1  (end point 1)
00152  *              x2, y2  (end point 2)
00153  *              width
00154  *      Return: ptaj, or null on error
00155  */
00156 PTA  *
00157 generatePtaWideLine(l_int32  x1,
00158                     l_int32  y1,
00159                     l_int32  x2,
00160                     l_int32  y2,
00161                     l_int32  width)
00162 {
00163 l_int32  i, x1a, x2a, y1a, y2a;
00164 PTA     *pta, *ptaj;
00165 
00166     PROCNAME("generatePtaWideLine");
00167 
00168     if (width < 1) {
00169         L_WARNING("width < 1; setting to 1", procName);
00170         width = 1;
00171     }
00172 
00173     if ((ptaj = generatePtaLine(x1, y1, x2, y2)) == NULL)
00174         return (PTA *)ERROR_PTR("ptaj not made", procName, NULL);
00175     if (width == 1)
00176         return ptaj;
00177 
00178         /* width > 1; estimate line direction & join */
00179     if (L_ABS(x1 - x2) > L_ABS(y1 - y2)) {  /* "horizontal" line  */
00180         for (i = 1; i < width; i++) {
00181             if ((i & 1) == 1) {   /* place above */
00182                 y1a = y1 - (i + 1) / 2;
00183                 y2a = y2 - (i + 1) / 2;
00184             }
00185             else {  /* place below */
00186                 y1a = y1 + (i + 1) / 2;
00187                 y2a = y2 + (i + 1) / 2;
00188             }
00189             if ((pta = generatePtaLine(x1, y1a, x2, y2a)) == NULL)
00190                 return (PTA *)ERROR_PTR("pta not made", procName, NULL);
00191             ptaJoin(ptaj, pta, 0, 0);
00192             ptaDestroy(&pta);
00193         }
00194     }
00195     else  {  /* "vertical" line  */
00196         for (i = 1; i < width; i++) {
00197             if ((i & 1) == 1) {   /* place to left */
00198                 x1a = x1 - (i + 1) / 2;
00199                 x2a = x2 - (i + 1) / 2;
00200             }
00201             else {  /* place to right */
00202                 x1a = x1 + (i + 1) / 2;
00203                 x2a = x2 + (i + 1) / 2;
00204             }
00205             if ((pta = generatePtaLine(x1a, y1, x2a, y2)) == NULL)
00206                 return (PTA *)ERROR_PTR("pta not made", procName, NULL);
00207             ptaJoin(ptaj, pta, 0, 0);
00208             ptaDestroy(&pta);
00209         }
00210     }
00211 
00212     return ptaj;
00213 }
00214 
00215 
00216 /*!
00217  *  generatePtaBox()
00218  *
00219  *      Input:  box
00220  *              width (of line)
00221  *      Return: ptad, or null on error
00222  *
00223  *  Notes:
00224  *      (1) Because the box is constructed so that we don't have any
00225  *          overlapping lines, there is no need to remove duplicates.
00226  */
00227 PTA  *
00228 generatePtaBox(BOX     *box,
00229                l_int32  width)
00230 {
00231 l_int32  x, y, w, h;
00232 PTA     *ptad, *pta;
00233 
00234     PROCNAME("generatePtaBox");
00235 
00236     if (!box)
00237         return (PTA *)ERROR_PTR("box not defined", procName, NULL);
00238 
00239         /* Generate line points and add them to the pta. */
00240     boxGetGeometry(box, &x, &y, &w, &h);
00241     if (w == 0 || h == 0)
00242         return (PTA *)ERROR_PTR("box has w = 0 or h = 0", procName, NULL);
00243     ptad = ptaCreate(0);
00244     if ((width & 1) == 1) {   /* odd width */
00245         pta = generatePtaWideLine(x - width / 2, y,
00246                                   x + w - 1 + width / 2, y, width);
00247         ptaJoin(ptad, pta, 0, 0);
00248         ptaDestroy(&pta);
00249         pta = generatePtaWideLine(x + w - 1, y + 1 + width / 2,
00250                                   x + w - 1, y + h - 2 - width / 2, width);
00251         ptaJoin(ptad, pta, 0, 0);
00252         ptaDestroy(&pta);
00253         pta = generatePtaWideLine(x + w - 1 + width / 2, y + h - 1,
00254                                   x - width / 2, y + h - 1, width);
00255         ptaJoin(ptad, pta, 0, 0);
00256         ptaDestroy(&pta);
00257         pta = generatePtaWideLine(x, y + h - 2 - width / 2,
00258                                   x, y + 1 + width / 2, width);
00259         ptaJoin(ptad, pta, 0, 0);
00260         ptaDestroy(&pta);
00261     }
00262     else {   /* even width */
00263         pta = generatePtaWideLine(x - width / 2, y,
00264                                   x + w - 2 + width / 2, y, width);
00265         ptaJoin(ptad, pta, 0, 0);
00266         ptaDestroy(&pta);
00267         pta = generatePtaWideLine(x + w - 1, y + 0 + width / 2,
00268                                   x + w - 1, y + h - 2 - width / 2, width);
00269         ptaJoin(ptad, pta, 0, 0);
00270         ptaDestroy(&pta);
00271         pta = generatePtaWideLine(x + w - 2 + width / 2, y + h - 1,
00272                                   x - width / 2, y + h - 1, width);
00273         ptaJoin(ptad, pta, 0, 0);
00274         ptaDestroy(&pta);
00275         pta = generatePtaWideLine(x, y + h - 2 - width / 2,
00276                                   x, y + 0 + width / 2, width);
00277         ptaJoin(ptad, pta, 0, 0);
00278         ptaDestroy(&pta);
00279     }
00280 
00281     return ptad;
00282 }
00283 
00284 
00285 /*!
00286  *  generatePtaHashBox()
00287  *
00288  *      Input:  box
00289  *              spacing (spacing between lines; must be > 1)
00290  *              width  (of line)
00291  *              orient  (orientation of lines: L_HORIZONTAL_LINE, ...)
00292  *              outline  (0 to skip drawing box outline)
00293  *      Return: ptad, or null on error
00294  *
00295  *  Notes:
00296  *      (1) The orientation takes on one of 4 orientations (horiz, vertical,
00297  *          slope +1, slope -1).
00298  *      (2) The full outline is also drawn if @outline = 1.
00299  */
00300 PTA  *
00301 generatePtaHashBox(BOX     *box,
00302                    l_int32  spacing,
00303                    l_int32  width,
00304                    l_int32  orient,
00305                    l_int32  outline)
00306 {
00307 l_int32  bx, by, bh, bw, x, y, x1, y1, x2, y2, i, n, npts;
00308 PTA     *ptad, *pta;
00309 
00310     PROCNAME("generatePtaHashBox");
00311 
00312     if (!box)
00313         return (PTA *)ERROR_PTR("box not defined", procName, NULL);
00314     if (spacing <= 1)
00315         return (PTA *)ERROR_PTR("spacing not > 1", procName, NULL);
00316     if (orient != L_HORIZONTAL_LINE && orient != L_POS_SLOPE_LINE &&
00317         orient != L_VERTICAL_LINE && orient != L_NEG_SLOPE_LINE)
00318         return (PTA *)ERROR_PTR("invalid line orientation", procName, NULL);
00319     boxGetGeometry(box, &bx, &by, &bw, &bh);
00320     if (bw == 0 || bh == 0)
00321         return (PTA *)ERROR_PTR("box has bw = 0 or bh = 0", procName, NULL);
00322 
00323         /* Generate line points and add them to the pta. */
00324     ptad = ptaCreate(0);
00325     if (outline) {
00326         pta = generatePtaBox(box, width);
00327         ptaJoin(ptad, pta, 0, 0);
00328         ptaDestroy(&pta);
00329     }
00330     if (orient == L_HORIZONTAL_LINE) {
00331         n = 1 + bh / spacing;
00332         for (i = 0; i < n; i++) {
00333             y = by + (i * (bh - 1)) / (n - 1);
00334             pta = generatePtaWideLine(bx, y, bx + bw - 1, y, width);
00335             ptaJoin(ptad, pta, 0, 0);
00336             ptaDestroy(&pta);
00337         }
00338     }
00339     else if (orient == L_VERTICAL_LINE) {
00340         n = 1 + bw / spacing;
00341         for (i = 0; i < n; i++) {
00342             x = bx + (i * (bw - 1)) / (n - 1);
00343             pta = generatePtaWideLine(x, by, x, by + bh - 1, width);
00344             ptaJoin(ptad, pta, 0, 0);
00345             ptaDestroy(&pta);
00346         }
00347     }
00348     else if (orient == L_POS_SLOPE_LINE) {
00349         n = 2 + (l_int32)((bw + bh) / (1.4 * spacing));
00350         for (i = 0; i < n; i++) {
00351             x = (l_int32)(bx + (i + 0.5) * 1.4 * spacing);
00352             boxIntersectByLine(box, x, by - 1, 1.0, &x1, &y1, &x2, &y2, &npts);
00353             if (npts == 2) {
00354                 pta = generatePtaWideLine(x1, y1, x2, y2, width);
00355                 ptaJoin(ptad, pta, 0, 0);
00356                 ptaDestroy(&pta);
00357             }
00358         }
00359     }
00360     else {  /* orient == L_NEG_SLOPE_LINE */
00361         n = 2 + (l_int32)((bw + bh) / (1.4 * spacing));
00362         for (i = 0; i < n; i++) {
00363             x = (l_int32)(bx - bh + (i + 0.5) * 1.4 * spacing);
00364             boxIntersectByLine(box, x, by - 1, -1.0, &x1, &y1, &x2, &y2, &npts);
00365             if (npts == 2) {
00366                 pta = generatePtaWideLine(x1, y1, x2, y2, width);
00367                 ptaJoin(ptad, pta, 0, 0);
00368                 ptaDestroy(&pta);
00369             }
00370         }
00371     }
00372 
00373     return ptad;
00374 }
00375 
00376 
00377 /*!
00378  *  generatePtaBoxa()
00379  *
00380  *      Input:  boxa
00381  *              width
00382  *              removedups  (1 to remove, 0 to leave)
00383  *      Return: ptad, or null on error
00384  *
00385  *  Notes:
00386  *      (1) If the boxa has overlapping boxes, and if blending will
00387  *          be used to give a transparent effect, transparency
00388  *          artifacts at line intersections can be removed using
00389  *          removedups = 1.
00390  */
00391 PTA  *
00392 generatePtaBoxa(BOXA    *boxa,
00393                 l_int32  width,
00394                 l_int32  removedups)
00395 {
00396 l_int32  i, n;
00397 BOX     *box;
00398 PTA     *ptad, *ptat, *pta;
00399 
00400     PROCNAME("generatePtaBoxa");
00401 
00402     if (!boxa)
00403         return (PTA *)ERROR_PTR("boxa not defined", procName, NULL);
00404 
00405     n = boxaGetCount(boxa);
00406     ptat = ptaCreate(0);
00407     for (i = 0; i < n; i++) {
00408         box = boxaGetBox(boxa, i, L_CLONE);
00409         pta = generatePtaBox(box, width);
00410         ptaJoin(ptat, pta, 0, 0);
00411         ptaDestroy(&pta);
00412         boxDestroy(&box);
00413     }
00414 
00415     if (removedups)
00416         ptad = ptaRemoveDuplicates(ptat, 0);
00417     else
00418         ptad = ptaClone(ptat);
00419 
00420     ptaDestroy(&ptat);
00421     return ptad;
00422 }
00423 
00424 
00425 /*!
00426  *  generatePtaaBoxa()
00427  *
00428  *      Input:  boxa
00429  *      Return: ptaa, or null on error
00430  *
00431  *  Notes:
00432  *      (1) This generates a pta of the four corners for each box in
00433  *          the boxa.
00434  *      (2) Each of these pta can be rendered onto a pix with random colors,
00435  *          by using pixRenderRandomCmapPtaa() with closeflag = 1.
00436  */
00437 PTAA  *
00438 generatePtaaBoxa(BOXA  *boxa)
00439 {
00440 l_int32  i, n, x, y, w, h;
00441 BOX     *box;
00442 PTA     *pta;
00443 PTAA    *ptaa;
00444 
00445     PROCNAME("generatePtaaBoxa");
00446 
00447     if (!boxa)
00448         return (PTAA *)ERROR_PTR("boxa not defined", procName, NULL);
00449 
00450     n = boxaGetCount(boxa);
00451     ptaa = ptaaCreate(n);
00452     for (i = 0; i < n; i++) {
00453         box = boxaGetBox(boxa, i, L_CLONE);
00454         boxGetGeometry(box, &x, &y, &w, &h);
00455         pta = ptaCreate(4);
00456         ptaAddPt(pta, x, y);
00457         ptaAddPt(pta, x + w - 1, y);
00458         ptaAddPt(pta, x + w - 1, y + h - 1);
00459         ptaAddPt(pta, x, y + h - 1);
00460         ptaaAddPta(ptaa, pta, L_INSERT);
00461         boxDestroy(&box);
00462     }
00463 
00464     return ptaa;
00465 }
00466 
00467 
00468 /*!
00469  *  generatePtaaHashBoxa()
00470  *
00471  *      Input:  boxa
00472  *              spacing (spacing between hash lines; must be > 1)
00473  *              width  (hash line width)
00474  *              orient  (orientation of lines: L_HORIZONTAL_LINE, ...)
00475  *              outline  (0 to skip drawing box outline)
00476  *      Return: ptaa, or null on error
00477  *
00478  *  Notes:
00479  *      (1) The orientation takes on one of 4 orientations (horiz, vertical,
00480  *          slope +1, slope -1).
00481  *      (2) The full outline is also drawn if @outline = 1.
00482  *      (3) Each of these pta can be rendered onto a pix with random colors,
00483  *          by using pixRenderRandomCmapPtaa() with closeflag = 1.
00484  *
00485  */
00486 PTAA  *
00487 generatePtaaHashBoxa(BOXA    *boxa,
00488                      l_int32  spacing,
00489                      l_int32  width,
00490                      l_int32  orient,
00491                      l_int32  outline)
00492 {
00493 l_int32  i, n;
00494 BOX     *box;
00495 PTA     *pta;
00496 PTAA    *ptaa;
00497 
00498     PROCNAME("generatePtaaHashBoxa");
00499 
00500     if (!boxa)
00501         return (PTAA *)ERROR_PTR("boxa not defined", procName, NULL);
00502     if (spacing <= 1)
00503         return (PTAA *)ERROR_PTR("spacing not > 1", procName, NULL);
00504     if (orient != L_HORIZONTAL_LINE && orient != L_POS_SLOPE_LINE &&
00505         orient != L_VERTICAL_LINE && orient != L_NEG_SLOPE_LINE)
00506         return (PTAA *)ERROR_PTR("invalid line orientation", procName, NULL);
00507 
00508     n = boxaGetCount(boxa);
00509     ptaa = ptaaCreate(n);
00510     for (i = 0; i < n; i++) {
00511         box = boxaGetBox(boxa, i, L_CLONE);
00512         pta = generatePtaHashBox(box, spacing, width, orient, outline);
00513         ptaaAddPta(ptaa, pta, L_INSERT);
00514         boxDestroy(&box);
00515     }
00516 
00517     return ptaa;
00518 }
00519 
00520 
00521 /*!
00522  *  generatePtaPolyline()
00523  *
00524  *      Input:  pta (vertices of polyline)
00525  *              width
00526  *              closeflag (1 to close the contour; 0 otherwise)
00527  *              removedups  (1 to remove, 0 to leave)
00528  *      Return: ptad, or null on error
00529  *
00530  *  Notes:
00531  *      (1) If the boxa has overlapping boxes, and if blending will
00532  *          be used to give a transparent effect, transparency
00533  *          artifacts at line intersections can be removed using
00534  *          removedups = 1.
00535  */
00536 PTA  *
00537 generatePtaPolyline(PTA     *ptas,
00538                     l_int32  width,
00539                     l_int32  closeflag,
00540                     l_int32  removedups)
00541 {
00542 l_int32  i, n, x1, y1, x2, y2;
00543 PTA     *ptad, *ptat, *pta;
00544 
00545     PROCNAME("generatePtaPolyline");
00546 
00547     if (!ptas)
00548         return (PTA *)ERROR_PTR("ptas not defined", procName, NULL);
00549 
00550     n = ptaGetCount(ptas);
00551     ptat = ptaCreate(0);
00552     if (n < 2)  /* nothing to do */
00553         return ptat;
00554 
00555     ptaGetIPt(ptas, 0, &x1, &y1);
00556     for (i = 1; i < n; i++) {
00557         ptaGetIPt(ptas, i, &x2, &y2);
00558         pta = generatePtaWideLine(x1, y1, x2, y2, width);
00559         ptaJoin(ptat, pta, 0, 0);
00560         ptaDestroy(&pta);
00561         x1 = x2;
00562         y1 = y2;
00563     }
00564 
00565     if (closeflag) {
00566         ptaGetIPt(ptas, 0, &x2, &y2);
00567         pta = generatePtaWideLine(x1, y1, x2, y2, width);
00568         ptaJoin(ptat, pta, 0, 0);
00569         ptaDestroy(&pta);
00570     }
00571 
00572     if (removedups)
00573         ptad = ptaRemoveDuplicates(ptat, 0);
00574     else
00575         ptad = ptaClone(ptat);
00576 
00577     ptaDestroy(&ptat);
00578     return ptad;
00579 }
00580 
00581 
00582 /*!
00583  *  generatePtaFilledCircle()
00584  *
00585  *      Input:  radius
00586  *      Return: pta, or null on error
00587  *
00588  *  Notes:
00589  *      (1) The circle is has diameter = 2 * radius + 1.
00590  *      (2) It is located with the center of the circle at the
00591  *          point (radius, radius).
00592  *      (3) Consequently, it typically must be translated if
00593  *          it is to represent a set of pixels in an image.
00594  */
00595 PTA  *
00596 generatePtaFilledCircle(l_int32  radius)
00597 {
00598 l_int32    x, y;
00599 l_float32  radthresh, sqdist;
00600 PTA       *pta;
00601 
00602     PROCNAME("generatePtaFilledCircle");
00603 
00604     if (radius < 1)
00605         return (PTA *)ERROR_PTR("radius must be >= 1", procName, NULL);
00606 
00607     pta = ptaCreate(0);
00608     radthresh = (radius + 0.5) * (radius + 0.5);
00609     for (y = 0; y <= 2 * radius; y++) {
00610         for (x = 0; x <= 2 * radius; x++) {
00611             sqdist = (l_float32)((y - radius) * (y - radius) +
00612                                  (x - radius) * (x - radius));
00613             if (sqdist <= radthresh)
00614                 ptaAddPt(pta, x, y);
00615         }
00616     }
00617 
00618     return pta;
00619 }
00620 
00621 
00622 /*!
00623  *  generatePtaLineFromPt()
00624  *
00625  *      Input:  x, y  (point of origination)
00626  *              length (of line, including starting point)
00627  *              radang (angle in radians, CW from horizontal)
00628  *      Return: pta, or null on error
00629  *
00630  *  Notes:
00631  *      (1) The @length of the line is 1 greater than the distance
00632  *          used in locatePtRadially().  Example: a distance of 1
00633  *          gives rise to a length of 2.
00634  */
00635 PTA *
00636 generatePtaLineFromPt(l_int32    x,
00637                       l_int32    y,
00638                       l_float64  length,
00639                       l_float64  radang)
00640 {
00641 l_int32  x2, y2;  /* the point at the other end of the line */
00642 
00643     x2 = x + (l_int32)((length - 1.0) * cos(radang));
00644     y2 = y + (l_int32)((length - 1.0) * sin(radang));
00645     return generatePtaLine(x, y, x2, y2);
00646 }
00647 
00648 
00649 /*!
00650  *  locatePtRadially()
00651  *
00652  *      Input:  xr, yr  (reference point)
00653  *              radang (angle in radians, CW from horizontal)
00654  *              dist (distance of point from reference point along line
00655  *                    given by the specified angle)
00656  *              &x, &y (<return> location of point)
00657  *      Return: 0 if OK, 1 on error
00658  */
00659 l_int32
00660 locatePtRadially(l_int32     xr,
00661                  l_int32     yr,
00662                  l_float64   dist,
00663                  l_float64   radang,
00664                  l_float64  *px,
00665                  l_float64  *py)
00666 {
00667     PROCNAME("locatePtRadially");
00668 
00669     if (!px || !py)
00670         return ERROR_INT("&x and &y not both defined", procName, 1);
00671 
00672     *px = xr + dist * cos(radang);
00673     *py = yr + dist * sin(radang);
00674     return 0;
00675 }
00676 
00677 
00678 /*------------------------------------------------------------------*
00679  *        Pta generation for arbitrary shapes built with lines      *
00680  *------------------------------------------------------------------*/
00681 /*!
00682  *  pixRenderPta()
00683  *
00684  *      Input:  pix
00685  *              pta (arbitrary set of points)
00686  *              op   (one of L_SET_PIXELS, L_CLEAR_PIXELS, L_FLIP_PIXELS)
00687  *      Return: 0 if OK, 1 on error
00688  *
00689  *  Notes:
00690  *      (1) L_SET_PIXELS puts all image bits in each pixel to 1
00691  *          (black for 1 bpp; white for depth > 1)
00692  *      (2) L_CLEAR_PIXELS puts all image bits in each pixel to 0
00693  *          (white for 1 bpp; black for depth > 1)
00694  *      (3) L_FLIP_PIXELS reverses all image bits in each pixel
00695  *      (4) This function clips the rendering to the pix.  It performs
00696  *          clipping for functions such as pixRenderLine(),
00697  *          pixRenderBox() and pixRenderBoxa(), that call pixRenderPta().
00698  */
00699 l_int32
00700 pixRenderPta(PIX     *pix,
00701              PTA     *pta,
00702              l_int32  op)
00703 {
00704 l_int32  i, n, x, y, w, h, d, maxval;
00705 
00706     PROCNAME("pixRenderPta");
00707 
00708     if (!pix)
00709         return ERROR_INT("pix not defined", procName, 1);
00710     if (!pta)
00711         return ERROR_INT("pta not defined", procName, 1);
00712     if (op != L_SET_PIXELS && op != L_CLEAR_PIXELS && op != L_FLIP_PIXELS)
00713         return ERROR_INT("invalid op", procName, 1);
00714 
00715     pixGetDimensions(pix, &w, &h, &d);
00716     maxval = 1;
00717     if (op == L_SET_PIXELS) {
00718         switch (d)
00719         {
00720         case 2: 
00721             maxval = 0x3;
00722             break;
00723         case 4: 
00724             maxval = 0xf;
00725             break;
00726         case 8: 
00727             maxval = 0xff;
00728             break;
00729         case 16: 
00730             maxval = 0xffff;
00731             break;
00732         case 32: 
00733             maxval = 0xffffffff;
00734             break;
00735         }
00736     }
00737 
00738     n = ptaGetCount(pta);
00739     for (i = 0; i < n; i++) {
00740         ptaGetIPt(pta, i, &x, &y);
00741         if (x < 0 || x >= w)
00742             continue;
00743         if (y < 0 || y >= h)
00744             continue;
00745         switch (op)
00746         {
00747         case L_SET_PIXELS:
00748             pixSetPixel(pix, x, y, maxval);
00749             break;
00750         case L_CLEAR_PIXELS:
00751             pixClearPixel(pix, x, y);
00752             break;
00753         case L_FLIP_PIXELS:
00754             pixFlipPixel(pix, x, y);
00755             break;
00756         default:
00757             break;
00758         }
00759     }
00760 
00761     return 0;
00762 }
00763 
00764 
00765 /*!
00766  *  pixRenderPtaArb()
00767  *
00768  *      Input:  pix
00769  *              pta (arbitrary set of points)
00770  *              rval, gval, bval
00771  *      Return: 0 if OK, 1 on error
00772  *
00773  *  Notes:
00774  *      (1) If pix is colormapped, render this color on each pixel.
00775  *      (2) If pix is not colormapped, do the best job you can using
00776  *          the input colors:
00777  *          - d = 1: set the pixels
00778  *          - d = 2, 4, 8: average the input rgb value
00779  *          - d = 32: use the input rgb value
00780  *      (3) This function clips the rendering to the pix.
00781  */
00782 l_int32
00783 pixRenderPtaArb(PIX     *pix,
00784                 PTA     *pta,
00785                 l_uint8  rval,
00786                 l_uint8  gval,
00787                 l_uint8  bval)
00788 {
00789 l_int32   i, n, x, y, w, h, d, index;
00790 l_uint8   val;
00791 l_uint32  val32;
00792 PIXCMAP  *cmap;
00793 
00794     PROCNAME("pixRenderPtaArb");
00795 
00796     if (!pix)
00797         return ERROR_INT("pix not defined", procName, 1);
00798     if (!pta)
00799         return ERROR_INT("pta not defined", procName, 1);
00800     d = pixGetDepth(pix);
00801     if (d != 1 && d != 2 && d != 4 && d != 8 && d != 32) 
00802         return ERROR_INT("depth not in {1,2,4,8,32}", procName, 1);
00803 
00804     if (d == 1) {
00805         pixRenderPta(pix, pta, L_SET_PIXELS);
00806         return 0;
00807     }
00808 
00809     cmap = pixGetColormap(pix);
00810     pixGetDimensions(pix, &w, &h, &d);
00811     if (cmap) {
00812         if (pixcmapAddNewColor(cmap, rval, gval, bval, &index))
00813             return ERROR_INT("colormap is full", procName, 1);
00814     }
00815     else {
00816         if (d == 2)
00817             val = (rval + gval + bval) / (3 * 64);
00818         else if (d == 4)
00819             val = (rval + gval + bval) / (3 * 16);
00820         else if (d == 8)
00821             val = (rval + gval + bval) / 3;
00822         else  /* d == 32 */
00823             composeRGBPixel(rval, gval, bval, &val32);
00824     }
00825 
00826     n = ptaGetCount(pta);
00827     for (i = 0; i < n; i++) {
00828         ptaGetIPt(pta, i, &x, &y);
00829         if (x < 0 || x >= w)
00830             continue;
00831         if (y < 0 || y >= h)
00832             continue;
00833         if (cmap)
00834             pixSetPixel(pix, x, y, index);
00835         else if (d == 32)
00836             pixSetPixel(pix, x, y, val32);
00837         else
00838             pixSetPixel(pix, x, y, val);
00839     }
00840 
00841     return 0;
00842 }
00843 
00844 
00845 /*!
00846  *  pixRenderPtaBlend()
00847  *
00848  *      Input:  pix (32 bpp rgb)
00849  *              pta  (arbitrary set of points)
00850  *              rval, gval, bval
00851  *      Return: 0 if OK, 1 on error
00852  *
00853  *  Notes:
00854  *      (1) This function clips the rendering to the pix.
00855  */
00856 l_int32
00857 pixRenderPtaBlend(PIX     *pix,
00858                   PTA     *pta,
00859                   l_uint8  rval,
00860                   l_uint8  gval,
00861                   l_uint8  bval,
00862                   l_float32 fract)
00863 {
00864 l_int32    i, n, x, y, w, h;
00865 l_uint8    nrval, ngval, nbval;
00866 l_uint32   val32;
00867 l_float32  frval, fgval, fbval;
00868 
00869     PROCNAME("pixRenderPtaBlend");
00870 
00871     if (!pix)
00872         return ERROR_INT("pix not defined", procName, 1);
00873     if (!pta)
00874         return ERROR_INT("pta not defined", procName, 1);
00875     if (pixGetDepth(pix) != 32)
00876         return ERROR_INT("depth not 32 bpp", procName, 1);
00877     if (fract < 0.0 || fract > 1.0) {
00878         L_WARNING("fract must be in [0.0, 1.0]; setting to 0.5", procName);
00879         fract = 0.5;
00880     }
00881 
00882     pixGetDimensions(pix, &w, &h, NULL);
00883     n = ptaGetCount(pta);
00884     frval = fract * rval;
00885     fgval = fract * gval;
00886     fbval = fract * bval;
00887     for (i = 0; i < n; i++) {
00888         ptaGetIPt(pta, i, &x, &y);
00889         if (x < 0 || x >= w)
00890             continue;
00891         if (y < 0 || y >= h)
00892             continue;
00893         pixGetPixel(pix, x, y, &val32);
00894         nrval = GET_DATA_BYTE(&val32, COLOR_RED);
00895         nrval = (l_uint8)((1. - fract) * nrval + frval);
00896         ngval = GET_DATA_BYTE(&val32, COLOR_GREEN);
00897         ngval = (l_uint8)((1. - fract) * ngval + fgval);
00898         nbval = GET_DATA_BYTE(&val32, COLOR_BLUE);
00899         nbval = (l_uint8)((1. - fract) * nbval + fbval);
00900         composeRGBPixel(nrval, ngval, nbval, &val32);
00901         pixSetPixel(pix, x, y, val32);
00902     }
00903 
00904     return 0;
00905 }
00906 
00907 
00908 /*------------------------------------------------------------------*
00909  *           Rendering of arbitrary shapes built with lines         *
00910  *------------------------------------------------------------------*/
00911 /*!
00912  *  pixRenderLine()
00913  *
00914  *      Input:  pix
00915  *              x1, y1
00916  *              x2, y2
00917  *              width  (thickness of line)
00918  *              op  (one of L_SET_PIXELS, L_CLEAR_PIXELS, L_FLIP_PIXELS)
00919  *      Return: 0 if OK, 1 on error
00920  */
00921 l_int32
00922 pixRenderLine(PIX     *pix,
00923               l_int32  x1,
00924               l_int32  y1,
00925               l_int32  x2,
00926               l_int32  y2,
00927               l_int32  width,
00928               l_int32  op)
00929 {
00930 PTA  *pta;
00931 
00932     PROCNAME("pixRenderLine");
00933 
00934     if (!pix)
00935         return ERROR_INT("pix not defined", procName, 1);
00936     if (width < 1) {
00937         L_WARNING("width must be > 0; setting to 1", procName);
00938         width = 1;
00939     }
00940     if (op != L_SET_PIXELS && op != L_CLEAR_PIXELS && op != L_FLIP_PIXELS)
00941         return ERROR_INT("invalid op", procName, 1);
00942 
00943     if ((pta = generatePtaWideLine(x1, y1, x2, y2, width)) == NULL)
00944         return ERROR_INT("pta not made", procName, 1);
00945     pixRenderPta(pix, pta, op);
00946     ptaDestroy(&pta);
00947     return 0;
00948 }
00949 
00950 
00951 /*!
00952  *  pixRenderLineArb()
00953  *
00954  *      Input:  pix
00955  *              x1, y1
00956  *              x2, y2
00957  *              width  (thickness of line)
00958  *              rval, gval, bval
00959  *      Return: 0 if OK, 1 on error
00960  */
00961 l_int32
00962 pixRenderLineArb(PIX     *pix,
00963                  l_int32  x1,
00964                  l_int32  y1,
00965                  l_int32  x2,
00966                  l_int32  y2,
00967                  l_int32  width,
00968                  l_uint8  rval,
00969                  l_uint8  gval,
00970                  l_uint8  bval)
00971 {
00972 PTA  *pta;
00973 
00974     PROCNAME("pixRenderLineArb");
00975 
00976     if (!pix)
00977         return ERROR_INT("pix not defined", procName, 1);
00978     if (width < 1) {
00979         L_WARNING("width must be > 0; setting to 1", procName);
00980         width = 1;
00981     }
00982 
00983     if ((pta = generatePtaWideLine(x1, y1, x2, y2, width)) == NULL)
00984         return ERROR_INT("pta not made", procName, 1);
00985     pixRenderPtaArb(pix, pta, rval, gval, bval);
00986     ptaDestroy(&pta);
00987     return 0;
00988 }
00989 
00990 
00991 /*!
00992  *  pixRenderLineBlend()
00993  *
00994  *      Input:  pix
00995  *              x1, y1
00996  *              x2, y2
00997  *              width  (thickness of line)
00998  *              rval, gval, bval
00999  *              fract
01000  *      Return: 0 if OK, 1 on error
01001  */
01002 l_int32
01003 pixRenderLineBlend(PIX       *pix,
01004                    l_int32    x1,
01005                    l_int32    y1,
01006                    l_int32    x2,
01007                    l_int32    y2,
01008                    l_int32    width,
01009                    l_uint8    rval,
01010                    l_uint8    gval,
01011                    l_uint8    bval,
01012                    l_float32  fract)
01013 {
01014 PTA  *pta;
01015 
01016     PROCNAME("pixRenderLineBlend");
01017 
01018     if (!pix)
01019         return ERROR_INT("pix not defined", procName, 1);
01020     if (width < 1) {
01021         L_WARNING("width must be > 0; setting to 1", procName);
01022         width = 1;
01023     }
01024 
01025     if ((pta = generatePtaWideLine(x1, y1, x2, y2, width)) == NULL)
01026         return ERROR_INT("pta not made", procName, 1);
01027     pixRenderPtaBlend(pix, pta, rval, gval, bval, fract);
01028     ptaDestroy(&pta);
01029     return 0;
01030 }
01031 
01032 
01033 /*!
01034  *  pixRenderBox()
01035  *
01036  *      Input:  pix
01037  *              box
01038  *              width  (thickness of box lines)
01039  *              op  (one of L_SET_PIXELS, L_CLEAR_PIXELS, L_FLIP_PIXELS)
01040  *      Return: 0 if OK, 1 on error
01041  */
01042 l_int32
01043 pixRenderBox(PIX     *pix,
01044              BOX     *box,
01045              l_int32  width,
01046              l_int32  op)
01047 {
01048 PTA  *pta;
01049 
01050     PROCNAME("pixRenderBox");
01051 
01052     if (!pix)
01053         return ERROR_INT("pix not defined", procName, 1);
01054     if (!box)
01055         return ERROR_INT("box not defined", procName, 1);
01056     if (op != L_SET_PIXELS && op != L_CLEAR_PIXELS && op != L_FLIP_PIXELS)
01057         return ERROR_INT("invalid op", procName, 1);
01058 
01059     if ((pta = generatePtaBox(box, width)) == NULL)
01060         return ERROR_INT("pta not made", procName, 1);
01061     pixRenderPta(pix, pta, op);
01062     ptaDestroy(&pta);
01063     return 0;
01064 }
01065 
01066 
01067 /*!
01068  *  pixRenderBoxArb()
01069  *
01070  *      Input:  pix
01071  *              box
01072  *              width  (thickness of box lines)
01073  *              rval, gval, bval
01074  *      Return: 0 if OK, 1 on error
01075  */
01076 l_int32
01077 pixRenderBoxArb(PIX     *pix,
01078                 BOX     *box,
01079                 l_int32  width,
01080                 l_uint8  rval,
01081                 l_uint8  gval,
01082                 l_uint8  bval)
01083 {
01084 PTA  *pta;
01085 
01086     PROCNAME("pixRenderBoxArb");
01087 
01088     if (!pix)
01089         return ERROR_INT("pix not defined", procName, 1);
01090     if (!box)
01091         return ERROR_INT("box not defined", procName, 1);
01092 
01093     if ((pta = generatePtaBox(box, width)) == NULL)
01094         return ERROR_INT("pta not made", procName, 1);
01095     pixRenderPtaArb(pix, pta, rval, gval, bval);
01096     ptaDestroy(&pta);
01097     return 0;
01098 }
01099 
01100 
01101 /*!
01102  *  pixRenderBoxBlend()
01103  *
01104  *      Input:  pix
01105  *              box
01106  *              width  (thickness of box lines)
01107  *              rval, gval, bval
01108  *              fract (in [0.0 - 1.0]; complete transparency (no effect)
01109  *                     if 0.0; no transparency if 1.0)
01110  *      Return: 0 if OK, 1 on error
01111  */
01112 l_int32
01113 pixRenderBoxBlend(PIX       *pix,
01114                   BOX       *box,
01115                   l_int32    width,
01116                   l_uint8    rval,
01117                   l_uint8    gval,
01118                   l_uint8    bval,
01119                   l_float32  fract)
01120 {
01121 PTA  *pta;
01122 
01123     PROCNAME("pixRenderBoxBlend");
01124 
01125     if (!pix)
01126         return ERROR_INT("pix not defined", procName, 1);
01127     if (!box)
01128         return ERROR_INT("box not defined", procName, 1);
01129 
01130     if ((pta = generatePtaBox(box, width)) == NULL)
01131         return ERROR_INT("pta not made", procName, 1);
01132     pixRenderPtaBlend(pix, pta, rval, gval, bval, fract);
01133     ptaDestroy(&pta);
01134     return 0;
01135 }
01136 
01137 
01138 /*!
01139  *  pixRenderHashBox()
01140  *
01141  *      Input:  pix
01142  *              box
01143  *              spacing (spacing between lines; must be > 1)
01144  *              width  (thickness of box and hash lines)
01145  *              orient  (orientation of lines: L_HORIZONTAL_LINE, ...)
01146  *              outline  (0 to skip drawing box outline)
01147  *              op  (one of L_SET_PIXELS, L_CLEAR_PIXELS, L_FLIP_PIXELS)
01148  *      Return: 0 if OK, 1 on error
01149  */
01150 l_int32
01151 pixRenderHashBox(PIX     *pix,
01152                  BOX     *box,
01153                  l_int32  spacing,
01154                  l_int32  width,
01155                  l_int32  orient,
01156                  l_int32  outline,
01157                  l_int32  op)
01158 {
01159 PTA  *pta;
01160 
01161     PROCNAME("pixRenderHashBox");
01162 
01163     if (!pix)
01164         return ERROR_INT("pix not defined", procName, 1);
01165     if (!box)
01166         return ERROR_INT("box not defined", procName, 1);
01167     if (spacing <= 1)
01168         return ERROR_INT("spacing not > 1", procName, 1);
01169     if (orient != L_HORIZONTAL_LINE && orient != L_POS_SLOPE_LINE &&
01170         orient != L_VERTICAL_LINE && orient != L_NEG_SLOPE_LINE)
01171         return ERROR_INT("invalid line orientation", procName, 1);
01172     if (op != L_SET_PIXELS && op != L_CLEAR_PIXELS && op != L_FLIP_PIXELS)
01173         return ERROR_INT("invalid op", procName, 1);
01174 
01175     pta = generatePtaHashBox(box, spacing, width, orient, outline);
01176     if (!pta)
01177         return ERROR_INT("pta not made", procName, 1);
01178     pixRenderPta(pix, pta, op);
01179     ptaDestroy(&pta);
01180     return 0;
01181 }
01182 
01183 
01184 /*!
01185  *  pixRenderBoxArb()
01186  *
01187  *      Input:  pix
01188  *              box
01189  *              spacing (spacing between lines; must be > 1)
01190  *              width  (thickness of box and hash lines)
01191  *              orient  (orientation of lines: L_HORIZONTAL_LINE, ...)
01192  *              outline  (0 to skip drawing box outline)
01193  *              rval, gval, bval
01194  *      Return: 0 if OK, 1 on error
01195  */
01196 l_int32
01197 pixRenderHashBoxArb(PIX     *pix,
01198                     BOX     *box,
01199                     l_int32  spacing,
01200                     l_int32  width,
01201                     l_int32  orient,
01202                     l_int32  outline,
01203                     l_int32  rval,
01204                     l_int32  gval,
01205                     l_int32  bval)
01206 {
01207 PTA  *pta;
01208 
01209     PROCNAME("pixRenderHashBoxArb");
01210 
01211     if (!pix)
01212         return ERROR_INT("pix not defined", procName, 1);
01213     if (!box)
01214         return ERROR_INT("box not defined", procName, 1);
01215     if (spacing <= 1)
01216         return ERROR_INT("spacing not > 1", procName, 1);
01217     if (orient != L_HORIZONTAL_LINE && orient != L_POS_SLOPE_LINE &&
01218         orient != L_VERTICAL_LINE && orient != L_NEG_SLOPE_LINE)
01219         return ERROR_INT("invalid line orientation", procName, 1);
01220 
01221     pta = generatePtaHashBox(box, spacing, width, orient, outline);
01222     if (!pta)
01223         return ERROR_INT("pta not made", procName, 1);
01224     pixRenderPtaArb(pix, pta, rval, gval, bval);
01225     ptaDestroy(&pta);
01226     return 0;
01227 }
01228 
01229 
01230 /*!
01231  *  pixRenderHashBoxBlend()
01232  *
01233  *      Input:  pix
01234  *              box
01235  *              spacing (spacing between lines; must be > 1)
01236  *              width  (thickness of box and hash lines)
01237  *              orient  (orientation of lines: L_HORIZONTAL_LINE, ...)
01238  *              outline  (0 to skip drawing box outline)
01239  *              rval, gval, bval
01240  *              fract (in [0.0 - 1.0]; complete transparency (no effect)
01241  *                     if 0.0; no transparency if 1.0)
01242  *      Return: 0 if OK, 1 on error
01243  */
01244 l_int32
01245 pixRenderHashBoxBlend(PIX       *pix,
01246                       BOX       *box,
01247                       l_int32    spacing,
01248                       l_int32    width,
01249                       l_int32    orient,
01250                       l_int32    outline,
01251                       l_int32    rval,
01252                       l_int32    gval,
01253                       l_int32    bval,
01254                       l_float32  fract)
01255 {
01256 PTA  *pta;
01257 
01258     PROCNAME("pixRenderHashBoxBlend");
01259 
01260     if (!pix)
01261         return ERROR_INT("pix not defined", procName, 1);
01262     if (!box)
01263         return ERROR_INT("box not defined", procName, 1);
01264     if (spacing <= 1)
01265         return ERROR_INT("spacing not > 1", procName, 1);
01266     if (orient != L_HORIZONTAL_LINE && orient != L_POS_SLOPE_LINE &&
01267         orient != L_VERTICAL_LINE && orient != L_NEG_SLOPE_LINE)
01268         return ERROR_INT("invalid line orientation", procName, 1);
01269 
01270     pta = generatePtaHashBox(box, spacing, width, orient, outline);
01271     if (!pta)
01272         return ERROR_INT("pta not made", procName, 1);
01273     pixRenderPtaBlend(pix, pta, rval, gval, bval, fract);
01274     ptaDestroy(&pta);
01275     return 0;
01276 }
01277 
01278 
01279 /*!
01280  *  pixRenderBoxa()
01281  *
01282  *      Input:  pix
01283  *              boxa
01284  *              width  (thickness of line)
01285  *              op  (one of L_SET_PIXELS, L_CLEAR_PIXELS, L_FLIP_PIXELS)
01286  *      Return: 0 if OK, 1 on error
01287  */
01288 l_int32
01289 pixRenderBoxa(PIX     *pix,
01290               BOXA    *boxa,
01291               l_int32  width,
01292               l_int32  op)
01293 {
01294 PTA  *pta;
01295 
01296     PROCNAME("pixRenderBoxa");
01297 
01298     if (!pix)
01299         return ERROR_INT("pix not defined", procName, 1);
01300     if (!boxa)
01301         return ERROR_INT("boxa not defined", procName, 1);
01302     if (op != L_SET_PIXELS && op != L_CLEAR_PIXELS && op != L_FLIP_PIXELS)
01303         return ERROR_INT("invalid op", procName, 1);
01304 
01305     if ((pta = generatePtaBoxa(boxa, width, 0)) == NULL)
01306         return ERROR_INT("pta not made", procName, 1);
01307     pixRenderPta(pix, pta, op);
01308     ptaDestroy(&pta);
01309     return 0;
01310 }
01311 
01312 
01313 /*!
01314  *  pixRenderBoxaArb()
01315  *
01316  *      Input:  pix
01317  *              boxa
01318  *              width  (thickness of line)
01319  *              rval, gval, bval
01320  *      Return: 0 if OK, 1 on error
01321  */
01322 l_int32
01323 pixRenderBoxaArb(PIX     *pix,
01324                  BOXA    *boxa,
01325                  l_int32  width,
01326                  l_uint8  rval,
01327                  l_uint8  gval,
01328                  l_uint8  bval)
01329 {
01330 PTA  *pta;
01331 
01332     PROCNAME("pixRenderBoxaArb");
01333 
01334     if (!pix)
01335         return ERROR_INT("pix not defined", procName, 1);
01336     if (!boxa)
01337         return ERROR_INT("boxa not defined", procName, 1);
01338 
01339     if ((pta = generatePtaBoxa(boxa, width, 0)) == NULL)
01340         return ERROR_INT("pta not made", procName, 1);
01341     pixRenderPtaArb(pix, pta, rval, gval, bval);
01342     ptaDestroy(&pta);
01343     return 0;
01344 }
01345 
01346 
01347 /*!
01348  *  pixRenderBoxaBlend()
01349  *
01350  *      Input:  pix
01351  *              boxa
01352  *              width  (thickness of line)
01353  *              rval, gval, bval
01354  *              fract (in [0.0 - 1.0]; complete transparency (no effect)
01355  *                     if 0.0; no transparency if 1.0)
01356  *              removedups  (1 to remove; 0 otherwise)
01357  *      Return: 0 if OK, 1 on error
01358  */
01359 l_int32
01360 pixRenderBoxaBlend(PIX       *pix,
01361                    BOXA      *boxa,
01362                    l_int32    width,
01363                    l_uint8    rval,
01364                    l_uint8    gval,
01365                    l_uint8    bval,
01366                    l_float32  fract,
01367                    l_int32    removedups)
01368 {
01369 PTA  *pta;
01370 
01371     PROCNAME("pixRenderBoxaBlend");
01372 
01373     if (!pix)
01374         return ERROR_INT("pix not defined", procName, 1);
01375     if (!boxa)
01376         return ERROR_INT("boxa not defined", procName, 1);
01377 
01378     if ((pta = generatePtaBoxa(boxa, width, removedups)) == NULL)
01379         return ERROR_INT("pta not made", procName, 1);
01380     pixRenderPtaBlend(pix, pta, rval, gval, bval, fract);
01381     ptaDestroy(&pta);
01382     return 0;
01383 }
01384 
01385 
01386 /*!
01387  *  pixRenderPolyline()
01388  *
01389  *      Input:  pix
01390  *              ptas
01391  *              width  (thickness of line)
01392  *              op  (one of L_SET_PIXELS, L_CLEAR_PIXELS, L_FLIP_PIXELS)
01393  *              closeflag (1 to close the contour; 0 otherwise)
01394  *      Return: 0 if OK, 1 on error
01395  *
01396  *  Note: this renders a closed contour.
01397  */
01398 l_int32
01399 pixRenderPolyline(PIX     *pix,
01400                   PTA     *ptas,
01401                   l_int32  width,
01402                   l_int32  op,
01403                   l_int32  closeflag)
01404 {
01405 PTA  *pta;
01406 
01407     PROCNAME("pixRenderPolyline");
01408 
01409     if (!pix)
01410         return ERROR_INT("pix not defined", procName, 1);
01411     if (!ptas)
01412         return ERROR_INT("ptas not defined", procName, 1);
01413     if (op != L_SET_PIXELS && op != L_CLEAR_PIXELS && op != L_FLIP_PIXELS)
01414         return ERROR_INT("invalid op", procName, 1);
01415 
01416     if ((pta = generatePtaPolyline(ptas, width, closeflag, 0)) == NULL)
01417         return ERROR_INT("pta not made", procName, 1);
01418     pixRenderPta(pix, pta, op);
01419     ptaDestroy(&pta);
01420     return 0;
01421 }
01422 
01423 
01424 /*!
01425  *  pixRenderPolylineArb()
01426  *
01427  *      Input:  pix
01428  *              ptas
01429  *              width  (thickness of line)
01430  *              rval, gval, bval
01431  *              closeflag (1 to close the contour; 0 otherwise)
01432  *      Return: 0 if OK, 1 on error
01433  *
01434  *  Note: this renders a closed contour.
01435  */
01436 l_int32
01437 pixRenderPolylineArb(PIX     *pix,
01438                      PTA     *ptas,
01439                      l_int32  width,
01440                      l_uint8  rval,
01441                      l_uint8  gval,
01442                      l_uint8  bval,
01443                      l_int32  closeflag)
01444 {
01445 PTA  *pta;
01446 
01447     PROCNAME("pixRenderPolylineArb");
01448 
01449     if (!pix)
01450         return ERROR_INT("pix not defined", procName, 1);
01451     if (!ptas)
01452         return ERROR_INT("ptas not defined", procName, 1);
01453 
01454     if ((pta = generatePtaPolyline(ptas, width, closeflag, 0)) == NULL)
01455         return ERROR_INT("pta not made", procName, 1);
01456     pixRenderPtaArb(pix, pta, rval, gval, bval);
01457     ptaDestroy(&pta);
01458     return 0;
01459 }
01460 
01461 
01462 /*!
01463  *  pixRenderPolylineBlend()
01464  *
01465  *      Input:  pix
01466  *              ptas
01467  *              width  (thickness of line)
01468  *              rval, gval, bval
01469  *              fract (in [0.0 - 1.0]; complete transparency (no effect)
01470  *                     if 0.0; no transparency if 1.0)
01471  *              closeflag (1 to close the contour; 0 otherwise)
01472  *              removedups  (1 to remove; 0 otherwise)
01473  *      Return: 0 if OK, 1 on error
01474  */
01475 l_int32
01476 pixRenderPolylineBlend(PIX       *pix,
01477                        PTA       *ptas,
01478                        l_int32    width,
01479                        l_uint8    rval,
01480                        l_uint8    gval,
01481                        l_uint8    bval,
01482                        l_float32  fract,
01483                        l_int32    closeflag,
01484                        l_int32    removedups)
01485 {
01486 PTA  *pta;
01487 
01488     PROCNAME("pixRenderPolylineBlend");
01489 
01490     if (!pix)
01491         return ERROR_INT("pix not defined", procName, 1);
01492     if (!ptas)
01493         return ERROR_INT("ptas not defined", procName, 1);
01494 
01495     if ((pta = generatePtaPolyline(ptas, width, closeflag, removedups)) == NULL)
01496         return ERROR_INT("pta not made", procName, 1);
01497     pixRenderPtaBlend(pix, pta, rval, gval, bval, fract);
01498     ptaDestroy(&pta);
01499     return 0;
01500 }
01501 
01502 
01503 /*!
01504  *  pixRenderRandomCmapPtaa()
01505  *
01506  *      Input:  pix (1, 2, 4, 8, 16, 32 bpp)
01507  *              ptaa
01508  *              polyflag (1 to interpret each Pta as a polyline; 0 to simply
01509  *                        render the Pta as a set of pixels)
01510  *              width  (thickness of line; use only for polyline)
01511  *              closeflag (1 to close the contour; 0 otherwise;
01512  *                         use only for polyline mode)
01513  *      Return: pixd (cmapped, 8 bpp) or null on error
01514  *
01515  *  Notes:
01516  *      (1) This is a debugging routine, that displays a set of
01517  *          pixels, selected by the set of Ptas in a Ptaa,
01518  *          in a random color in a pix.
01519  *      (2) If @polyflag == 1, each Pta is considered to be a polyline,
01520  *          and is rendered using @width and @closeflag.  Each polyline
01521  *          is rendered in a random color.
01522  *      (3) If @polyflag == 0, all points in each Pta are rendered in a
01523  *          random color.  The @width and @closeflag parameters are ignored.
01524  *      (4) The output pix is 8 bpp and colormapped.  Up to 254
01525  *          different, randomly selected colors, can be used.
01526  *      (5) The rendered pixels replace the input pixels.  They will
01527  *          be clipped silently to the input pix.
01528  */
01529 PIX  *
01530 pixRenderRandomCmapPtaa(PIX     *pix,
01531                         PTAA    *ptaa,
01532                         l_int32  polyflag,
01533                         l_int32  width,
01534                         l_int32  closeflag)
01535 {
01536 l_int32   i, n, index, rval, gval, bval;
01537 PIXCMAP  *cmap;
01538 PTA      *pta, *ptat;
01539 PIX      *pixd;
01540 
01541     PROCNAME("pixRenderRandomCmapPtaa");
01542 
01543     if (!pix)
01544         return (PIX *)ERROR_PTR("pix not defined", procName, NULL);
01545     if (!ptaa)
01546         return (PIX *)ERROR_PTR("ptaa not defined", procName, NULL);
01547 
01548     pixd = pixConvertTo8(pix, FALSE);
01549     cmap = pixcmapCreateRandom(8, 1, 1);
01550     pixSetColormap(pixd, cmap);
01551 
01552     if ((n = ptaaGetCount(ptaa)) == 0)
01553         return pixd;
01554 
01555     for (i = 0; i < n; i++) {
01556         index = 1 + (i % 254);
01557         pixcmapGetColor(cmap, index, &rval, &gval, &bval);
01558         pta = ptaaGetPta(ptaa, i, L_CLONE);
01559         if (polyflag)
01560             ptat = generatePtaPolyline(pta, width, closeflag, 0);
01561         else
01562             ptat = ptaClone(pta);
01563         pixRenderPtaArb(pixd, ptat, rval, gval, bval);
01564         ptaDestroy(&pta);
01565         ptaDestroy(&ptat);
01566     }
01567 
01568     return pixd;
01569 }
01570 
01571 
01572 /*------------------------------------------------------------------*
01573  *             Contour rendering on grayscale images                *
01574  *------------------------------------------------------------------*/
01575 /*!
01576  *  pixRenderContours()
01577  *
01578  *      Input:  pixs (8 or 16 bpp; no colormap)
01579  *              startval (value of lowest contour; must be in [0 ... maxval])
01580  *              incr  (increment to next contour; must be > 0)
01581  *              outdepth (either 1 or depth of pixs)
01582  *      Return: pixd, or null on error
01583  *
01584  *  Notes:
01585  *      (1) The output can be either 1 bpp, showing just the contour
01586  *          lines, or a copy of the input pixs with the contour lines
01587  *          superposed.
01588  */
01589 PIX *
01590 pixRenderContours(PIX     *pixs,
01591                   l_int32  startval,
01592                   l_int32  incr,
01593                   l_int32  outdepth)
01594 {
01595 l_int32    w, h, d, maxval, wpls, wpld, i, j, val, test;
01596 l_uint32  *datas, *datad, *lines, *lined;
01597 PIX       *pixd;
01598 
01599     PROCNAME("pixRenderContours");
01600 
01601     if (!pixs)
01602         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
01603     if (pixGetColormap(pixs))
01604         return (PIX *)ERROR_PTR("pixs has colormap", procName, NULL);
01605     pixGetDimensions(pixs, &w, &h, &d);
01606     if (d != 8 && d != 16)
01607         return (PIX *)ERROR_PTR("pixs not 8 or 16 bpp", procName, NULL);
01608     if (outdepth != 1 && outdepth != d) {
01609         L_WARNING("invalid outdepth; setting to 1", procName);
01610         outdepth = 1;
01611     }
01612     maxval = (1 << d) - 1;
01613     if (startval < 0 || startval > maxval)
01614         return (PIX *)ERROR_PTR("startval not in [0 ... maxval]",
01615                procName, NULL);
01616     if (incr < 1)
01617         return (PIX *)ERROR_PTR("incr < 1", procName, NULL);
01618 
01619     if (outdepth == d)
01620         pixd = pixCopy(NULL, pixs);
01621     else
01622         pixd = pixCreate(w, h, 1);
01623 
01624     pixCopyResolution(pixd, pixs);
01625     datad = pixGetData(pixd);
01626     wpld = pixGetWpl(pixd);
01627     datas = pixGetData(pixs);
01628     wpls = pixGetWpl(pixs);
01629 
01630     switch (d)
01631     {
01632     case 8:
01633         if (outdepth == 1) {
01634             for (i = 0; i < h; i++) {
01635                 lines = datas + i * wpls;
01636                 lined = datad + i * wpld;
01637                 for (j = 0; j < w; j++) {
01638                     val = GET_DATA_BYTE(lines, j);
01639                     if (val < startval)
01640                         continue;
01641                     test = (val - startval) % incr;
01642                     if (!test)
01643                         SET_DATA_BIT(lined, j); 
01644                 }
01645             }
01646         }
01647         else {  /* outdepth == d */
01648             for (i = 0; i < h; i++) {
01649                 lines = datas + i * wpls;
01650                 lined = datad + i * wpld;
01651                 for (j = 0; j < w; j++) {
01652                     val = GET_DATA_BYTE(lines, j);
01653                     if (val < startval)
01654                         continue;
01655                     test = (val - startval) % incr;
01656                     if (!test)
01657                         SET_DATA_BYTE(lined, j, 0); 
01658                 }
01659             }
01660         }
01661         break;
01662 
01663     case 16:
01664         if (outdepth == 1) {
01665             for (i = 0; i < h; i++) {
01666                 lines = datas + i * wpls;
01667                 lined = datad + i * wpld;
01668                 for (j = 0; j < w; j++) {
01669                     val = GET_DATA_TWO_BYTES(lines, j);
01670                     if (val < startval)
01671                         continue;
01672                     test = (val - startval) % incr;
01673                     if (!test)
01674                         SET_DATA_BIT(lined, j); 
01675                 }
01676             }
01677         }
01678         else {  /* outdepth == d */
01679             for (i = 0; i < h; i++) {
01680                 lines = datas + i * wpls;
01681                 lined = datad + i * wpld;
01682                 for (j = 0; j < w; j++) {
01683                     val = GET_DATA_TWO_BYTES(lines, j);
01684                     if (val < startval)
01685                         continue;
01686                     test = (val - startval) % incr;
01687                     if (!test)
01688                         SET_DATA_TWO_BYTES(lined, j, 0); 
01689                 }
01690             }
01691         }
01692         break;
01693 
01694     default:
01695         return (PIX *)ERROR_PTR("pixs not 8 or 16 bpp", procName, NULL);
01696     }
01697 
01698     return pixd;
01699 }
01700 
01701 
01702 /*!
01703  *  fpixRenderContours()
01704  *
01705  *      Input:  fpixs
01706  *              startval (value of lowest contour
01707  *              incr  (increment to next contour; must be > 0.0)
01708  *              proxim (required proximity to target value; typ. 0.1 * incr)
01709  *      Return: pixd (1 bpp), or null on error
01710  */
01711 PIX *
01712 fpixRenderContours(FPIX      *fpixs,
01713                    l_float32  startval,
01714                    l_float32  incr,
01715                    l_float32  proxim)
01716 {
01717 l_int32     i, j, w, h, wpls, wpld;
01718 l_float32   val, invincr, finter, diff;
01719 l_uint32   *datad, *lined;
01720 l_float32  *datas, *lines;
01721 PIX        *pixd;
01722 
01723     PROCNAME("fpixRenderContours");
01724 
01725     if (!fpixs)
01726         return (PIX *)ERROR_PTR("fpixs not defined", procName, NULL);
01727     if (incr <= 0.0)
01728         return (PIX *)ERROR_PTR("incr <= 0.0", procName, NULL);
01729 
01730     fpixGetDimensions(fpixs, &w, &h);
01731     if ((pixd = pixCreate(w, h, 1)) == NULL)
01732         return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
01733 
01734     datas = fpixGetData(fpixs);
01735     wpls = fpixGetWpl(fpixs);
01736     datad = pixGetData(pixd);
01737     wpld = pixGetWpl(pixd);
01738     invincr = 1.0 / incr;
01739     for (i = 0; i < h; i++) {
01740         lines = datas + i * wpls;
01741         lined = datad + i * wpld;
01742         for (j = 0; j < w; j++) {
01743             val = lines[j];
01744             if (val < startval)
01745                 continue;
01746             finter = L_ABS(invincr * (val - startval));
01747             diff = finter - floorf(finter);
01748             if (diff <= proxim)
01749                 SET_DATA_BIT(lined, j); 
01750         }
01751     }
01752 
01753     return pixd;
01754 }
01755 
01756 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines