• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*====================================================================*
2  -  Copyright (C) 2001 Leptonica.  All rights reserved.
3  -  This software is distributed in the hope that it will be
4  -  useful, but with NO WARRANTY OF ANY KIND.
5  -  No author or distributor accepts responsibility to anyone for the
6  -  consequences of using this software, or for whether it serves any
7  -  particular purpose or works at all, unless he or she says so in
8  -  writing.  Everyone is granted permission to copy, modify and
9  -  redistribute this source code, for commercial or non-commercial
10  -  purposes, with the following restrictions: (1) the origin of this
11  -  source code must not be misrepresented; (2) modified versions must
12  -  be plainly marked as such; and (3) this notice may not be removed
13  -  or altered from any source or modified source distribution.
14  *====================================================================*/
15 
16 /*
17  *  graphics.c
18  *
19  *      Pta generation for arbitrary shapes built with lines
20  *
21  *          PTA        *generatePtaLine()
22  *          PTA        *generatePtaWideLine()
23  *          PTA        *generatePtaBox()
24  *          PTA        *generatePtaHashBox()
25  *          PTA        *generatePtaBoxa()
26  *          PTAA       *generatePtaaBoxa()
27  *          PTAA       *generatePtaaHashBoxa()
28  *          PTA        *generatePtaPolyline()
29  *          PTA        *generatePtaFilledCircle()
30  *          PTA        *generatePtaLineFromPt()
31  *          l_int32     locatePtRadially()
32  *
33  *      Pta rendering
34  *
35  *          l_int32     pixRenderPta()
36  *          l_int32     pixRenderPtaArb()
37  *          l_int32     pixRenderPtaBlend()
38  *
39  *      Rendering of arbitrary shapes built with lines
40  *
41  *          l_int32     pixRenderLine()
42  *          l_int32     pixRenderLineArb()
43  *          l_int32     pixRenderLineBlend()
44  *
45  *          l_int32     pixRenderBox()
46  *          l_int32     pixRenderBoxArb()
47  *          l_int32     pixRenderBoxBlend()
48  *
49  *          l_int32     pixRenderHashBox()
50  *          l_int32     pixRenderHashBoxArb()
51  *          l_int32     pixRenderHashBoxBlend()
52  *
53  *          l_int32     pixRenderBoxa()
54  *          l_int32     pixRenderBoxaArb()
55  *          l_int32     pixRenderBoxaBlend()
56  *
57  *          l_int32     pixRenderPolyline()
58  *          l_int32     pixRenderPolylineArb()
59  *          l_int32     pixRenderPolylineBlend()
60  *
61  *          l_int32     pixRenderRandomCmapPtaa()
62  *
63  *      Contour rendering on grayscale images
64  *
65  *          PIX        *pixRenderContours()
66  *
67  *  The line rendering functions are relatively crude, but they
68  *  get the job done for most simple situations.  We use the pta
69  *  as an intermediate data structure.  A pta is generated
70  *  for a line.  One of two rendering functions are used to
71  *  render this onto a Pix.
72  */
73 
74 #include <stdio.h>
75 #include <string.h>
76 #include <math.h>
77 #include "allheaders.h"
78 
79 
80 
81 /*------------------------------------------------------------------*
82  *        Pta generation for arbitrary shapes built with lines      *
83  *------------------------------------------------------------------*/
84 /*!
85  *  generatePtaLine()
86  *
87  *      Input:  x1, y1  (end point 1)
88  *              x2, y2  (end point 2)
89  *      Return: pta, or null on error
90  */
91 PTA  *
generatePtaLine(l_int32 x1,l_int32 y1,l_int32 x2,l_int32 y2)92 generatePtaLine(l_int32  x1,
93                 l_int32  y1,
94                 l_int32  x2,
95                 l_int32  y2)
96 {
97 l_int32    npts, diff, getyofx, sign, i, x, y;
98 l_float32  slope;
99 PTA       *pta;
100 
101     PROCNAME("generatePtaLine");
102 
103         /* Generate line parameters */
104     if (L_ABS(x2 - x1) >= L_ABS(y2 - y1)) {
105         getyofx = TRUE;
106         npts = L_ABS(x2 - x1) + 1;
107         diff = x2 - x1;
108         sign = L_SIGN(x2 - x1);
109         slope = (l_float32)(sign * (y2 - y1)) / (l_float32)diff;
110     }
111     else {
112         getyofx = FALSE;
113         npts = L_ABS(y2 - y1) + 1;
114         diff = y2 - y1;
115         sign = L_SIGN(y2 - y1);
116         slope = (l_float32)(sign * (x2 - x1)) / (l_float32)diff;
117     }
118 
119     if ((pta = ptaCreate(npts)) == NULL)
120         return (PTA *)ERROR_PTR("pta not made", procName, NULL);
121 
122     if (npts == 1) {  /* degenerate case */
123         ptaAddPt(pta, x1, y1);
124         return pta;
125     }
126 
127         /* Generate the set of points */
128     if (getyofx) {  /* y = y(x) */
129         for (i = 0; i < npts; i++) {
130             x = x1 + sign * i;
131             y = (l_int32)(y1 + (l_float32)i * slope + 0.5);
132             ptaAddPt(pta, x, y);
133         }
134     }
135     else {   /* x = x(y) */
136         for (i = 0; i < npts; i++) {
137             x = (l_int32)(x1 + (l_float32)i * slope + 0.5);
138             y = y1 + sign * i;
139             ptaAddPt(pta, x, y);
140         }
141     }
142 
143     return pta;
144 }
145 
146 
147 /*!
148  *  generatePtaWideLine()
149  *
150  *      Input:  x1, y1  (end point 1)
151  *              x2, y2  (end point 2)
152  *              width
153  *      Return: ptaj, or null on error
154  */
155 PTA  *
generatePtaWideLine(l_int32 x1,l_int32 y1,l_int32 x2,l_int32 y2,l_int32 width)156 generatePtaWideLine(l_int32  x1,
157                     l_int32  y1,
158                     l_int32  x2,
159                     l_int32  y2,
160                     l_int32  width)
161 {
162 l_int32  i, x1a, x2a, y1a, y2a;
163 PTA     *pta, *ptaj;
164 
165     PROCNAME("generatePtaWideLine");
166 
167     if (width < 1) {
168         L_WARNING("width < 1; setting to 1", procName);
169         width = 1;
170     }
171 
172     if ((ptaj = generatePtaLine(x1, y1, x2, y2)) == NULL)
173         return (PTA *)ERROR_PTR("ptaj not made", procName, NULL);
174     if (width == 1)
175         return ptaj;
176 
177         /* width > 1; estimate line direction & join */
178     if (L_ABS(x1 - x2) > L_ABS(y1 - y2)) {  /* "horizontal" line  */
179         for (i = 1; i < width; i++) {
180             if ((i & 1) == 1) {   /* place above */
181                 y1a = y1 - (i + 1) / 2;
182                 y2a = y2 - (i + 1) / 2;
183             }
184             else {  /* place below */
185                 y1a = y1 + (i + 1) / 2;
186                 y2a = y2 + (i + 1) / 2;
187             }
188             if ((pta = generatePtaLine(x1, y1a, x2, y2a)) == NULL)
189                 return (PTA *)ERROR_PTR("pta not made", procName, NULL);
190             ptaJoin(ptaj, pta, 0, 0);
191             ptaDestroy(&pta);
192         }
193     }
194     else  {  /* "vertical" line  */
195         for (i = 1; i < width; i++) {
196             if ((i & 1) == 1) {   /* place to left */
197                 x1a = x1 - (i + 1) / 2;
198                 x2a = x2 - (i + 1) / 2;
199             }
200             else {  /* place to right */
201                 x1a = x1 + (i + 1) / 2;
202                 x2a = x2 + (i + 1) / 2;
203             }
204             if ((pta = generatePtaLine(x1a, y1, x2a, y2)) == NULL)
205                 return (PTA *)ERROR_PTR("pta not made", procName, NULL);
206             ptaJoin(ptaj, pta, 0, 0);
207             ptaDestroy(&pta);
208         }
209     }
210 
211     return ptaj;
212 }
213 
214 
215 /*!
216  *  generatePtaBox()
217  *
218  *      Input:  box
219  *              width
220  *      Return: ptad, or null on error
221  *
222  *  Notes:
223  *      (1) Because the box is constructed so that we don't have any
224  *          overlapping lines, there is no need to remove duplicates.
225  */
226 PTA  *
generatePtaBox(BOX * box,l_int32 width)227 generatePtaBox(BOX     *box,
228                l_int32  width)
229 {
230 l_int32  x, y, w, h;
231 PTA     *ptad, *pta;
232 
233     PROCNAME("generatePtaBox");
234 
235     if (!box)
236         return (PTA *)ERROR_PTR("box not defined", procName, NULL);
237 
238         /* Generate line points and add them to the pta. */
239     boxGetGeometry(box, &x, &y, &w, &h);
240     ptad = ptaCreate(0);
241     if ((width & 1) == 1) {   /* odd width */
242         pta = generatePtaWideLine(x - width / 2, y,
243                                   x + w - 1 + width / 2, y, width);
244         ptaJoin(ptad, pta, 0, 0);
245         ptaDestroy(&pta);
246         pta = generatePtaWideLine(x + w - 1, y + 1 + width / 2,
247                                   x + w - 1, y + h - 2 - width / 2, width);
248         ptaJoin(ptad, pta, 0, 0);
249         ptaDestroy(&pta);
250         pta = generatePtaWideLine(x + w - 1 + width / 2, y + h - 1,
251                                   x - width / 2, y + h - 1, width);
252         ptaJoin(ptad, pta, 0, 0);
253         ptaDestroy(&pta);
254         pta = generatePtaWideLine(x, y + h - 2 - width / 2,
255                                   x, y + 1 + width / 2, width);
256         ptaJoin(ptad, pta, 0, 0);
257         ptaDestroy(&pta);
258     }
259     else {   /* even width */
260         pta = generatePtaWideLine(x - width / 2, y,
261                                   x + w - 2 + width / 2, y, width);
262         ptaJoin(ptad, pta, 0, 0);
263         ptaDestroy(&pta);
264         pta = generatePtaWideLine(x + w - 1, y + 0 + width / 2,
265                                   x + w - 1, y + h - 2 - width / 2, width);
266         ptaJoin(ptad, pta, 0, 0);
267         ptaDestroy(&pta);
268         pta = generatePtaWideLine(x + w - 2 + width / 2, y + h - 1,
269                                   x - width / 2, y + h - 1, width);
270         ptaJoin(ptad, pta, 0, 0);
271         ptaDestroy(&pta);
272         pta = generatePtaWideLine(x, y + h - 2 - width / 2,
273                                   x, y + 0 + width / 2, width);
274         ptaJoin(ptad, pta, 0, 0);
275         ptaDestroy(&pta);
276     }
277 
278     return ptad;
279 }
280 
281 
282 /*!
283  *  generatePtaHashBox()
284  *
285  *      Input:  box
286  *              spacing (spacing between lines; must be > 1)
287  *              width  (line width)
288  *              orient  (orientation of lines: L_HORIZONTAL_LINE, ...)
289  *              outline  (0 to skip drawing box outline)
290  *      Return: ptad, or null on error
291  *
292  *  Notes:
293  *      (1) The orientation takes on one of 4 orientations (horiz, vertical,
294  *          slope +1, slope -1).
295  *      (2) The full outline is also drawn if @outline = 1.
296  */
297 PTA  *
generatePtaHashBox(BOX * box,l_int32 spacing,l_int32 width,l_int32 orient,l_int32 outline)298 generatePtaHashBox(BOX     *box,
299                    l_int32  spacing,
300                    l_int32  width,
301                    l_int32  orient,
302                    l_int32  outline)
303 {
304 l_int32  bx, by, bh, bw, x, y, x1, y1, x2, y2, i, n, npts;
305 PTA     *ptad, *pta;
306 
307     PROCNAME("generatePtaHashBox");
308 
309     if (!box)
310         return (PTA *)ERROR_PTR("box not defined", procName, NULL);
311     if (spacing <= 1)
312         return (PTA *)ERROR_PTR("spacing not > 1", procName, NULL);
313     if (orient != L_HORIZONTAL_LINE && orient != L_POS_SLOPE_LINE &&
314         orient != L_VERTICAL_LINE && orient != L_NEG_SLOPE_LINE)
315         return (PTA *)ERROR_PTR("invalid line orientation", procName, NULL);
316 
317         /* Generate line points and add them to the pta. */
318     boxGetGeometry(box, &bx, &by, &bw, &bh);
319     ptad = ptaCreate(0);
320     if (outline) {
321         pta = generatePtaBox(box, width);
322         ptaJoin(ptad, pta, 0, 0);
323         ptaDestroy(&pta);
324     }
325     if (orient == L_HORIZONTAL_LINE) {
326         n = 1 + bh / spacing;
327         for (i = 0; i < n; i++) {
328             y = by + (i * (bh - 1)) / (n - 1);
329             pta = generatePtaWideLine(bx, y, bx + bw - 1, y, width);
330             ptaJoin(ptad, pta, 0, 0);
331             ptaDestroy(&pta);
332 	}
333     }
334     else if (orient == L_VERTICAL_LINE) {
335         n = 1 + bw / spacing;
336         for (i = 0; i < n; i++) {
337             x = bx + (i * (bw - 1)) / (n - 1);
338             pta = generatePtaWideLine(x, by, x, by + bh - 1, width);
339             ptaJoin(ptad, pta, 0, 0);
340             ptaDestroy(&pta);
341 	}
342     }
343     else if (orient == L_POS_SLOPE_LINE) {
344         n = 2 + (l_int32)((bw + bh) / (1.4 * spacing));
345         for (i = 0; i < n; i++) {
346             x = (l_int32)(bx + (i + 0.5) * 1.4 * spacing);
347             boxIntersectByLine(box, x, by - 1, 1.0, &x1, &y1, &x2, &y2, &npts);
348             if (npts == 2) {
349                 pta = generatePtaWideLine(x1, y1, x2, y2, width);
350                 ptaJoin(ptad, pta, 0, 0);
351                 ptaDestroy(&pta);
352             }
353         }
354     }
355     else {  /* orient == L_NEG_SLOPE_LINE */
356         n = 2 + (l_int32)((bw + bh) / (1.4 * spacing));
357         for (i = 0; i < n; i++) {
358             x = (l_int32)(bx - bh + (i + 0.5) * 1.4 * spacing);
359             boxIntersectByLine(box, x, by - 1, -1.0, &x1, &y1, &x2, &y2, &npts);
360             if (npts == 2) {
361                 pta = generatePtaWideLine(x1, y1, x2, y2, width);
362                 ptaJoin(ptad, pta, 0, 0);
363                 ptaDestroy(&pta);
364             }
365         }
366     }
367 
368     return ptad;
369 }
370 
371 
372 /*!
373  *  generatePtaBoxa()
374  *
375  *      Input:  boxa
376  *              width
377  *              removedups  (1 to remove, 0 to leave)
378  *      Return: ptad, or null on error
379  *
380  *  Notes:
381  *      (1) If the boxa has overlapping boxes, and if blending will
382  *          be used to give a transparent effect, transparency
383  *          artifacts at line intersections can be removed using
384  *          removedups = 1.
385  */
386 PTA  *
generatePtaBoxa(BOXA * boxa,l_int32 width,l_int32 removedups)387 generatePtaBoxa(BOXA    *boxa,
388                 l_int32  width,
389                 l_int32  removedups)
390 {
391 l_int32  i, n;
392 BOX     *box;
393 PTA     *ptad, *ptat, *pta;
394 
395     PROCNAME("generatePtaBoxa");
396 
397     if (!boxa)
398         return (PTA *)ERROR_PTR("boxa not defined", procName, NULL);
399 
400     n = boxaGetCount(boxa);
401     ptat = ptaCreate(0);
402     for (i = 0; i < n; i++) {
403         box = boxaGetBox(boxa, i, L_CLONE);
404         pta = generatePtaBox(box, width);
405         ptaJoin(ptat, pta, 0, 0);
406         ptaDestroy(&pta);
407         boxDestroy(&box);
408     }
409 
410     if (removedups)
411         ptad = ptaRemoveDuplicates(ptat, 0);
412     else
413         ptad = ptaClone(ptat);
414 
415     ptaDestroy(&ptat);
416     return ptad;
417 }
418 
419 
420 /*!
421  *  generatePtaaBoxa()
422  *
423  *      Input:  boxa
424  *      Return: ptaa, or null on error
425  *
426  *  Notes:
427  *      (1) This generates a pta of the four corners for each box in
428  *          the boxa.
429  *      (2) Each of these pta can be rendered onto a pix with random colors,
430  *          by using pixRenderRandomCmapPtaa() with closeflag = 1.
431  */
432 PTAA  *
generatePtaaBoxa(BOXA * boxa)433 generatePtaaBoxa(BOXA  *boxa)
434 {
435 l_int32  i, n, x, y, w, h;
436 BOX     *box;
437 PTA     *pta;
438 PTAA    *ptaa;
439 
440     PROCNAME("generatePtaaBoxa");
441 
442     if (!boxa)
443         return (PTAA *)ERROR_PTR("boxa not defined", procName, NULL);
444 
445     n = boxaGetCount(boxa);
446     ptaa = ptaaCreate(n);
447     for (i = 0; i < n; i++) {
448         box = boxaGetBox(boxa, i, L_CLONE);
449         boxGetGeometry(box, &x, &y, &w, &h);
450         pta = ptaCreate(4);
451         ptaAddPt(pta, x, y);
452         ptaAddPt(pta, x + w - 1, y);
453         ptaAddPt(pta, x + w - 1, y + h - 1);
454         ptaAddPt(pta, x, y + h - 1);
455         ptaaAddPta(ptaa, pta, L_INSERT);
456         boxDestroy(&box);
457     }
458 
459     return ptaa;
460 }
461 
462 
463 /*!
464  *  generatePtaaHashBoxa()
465  *
466  *      Input:  boxa
467  *              spacing (spacing between hash lines; must be > 1)
468  *              width  (hash line width)
469  *              orient  (orientation of lines: L_HORIZONTAL_LINE, ...)
470  *              outline  (0 to skip drawing box outline)
471  *      Return: ptaa, or null on error
472  *
473  *  Notes:
474  *      (1) The orientation takes on one of 4 orientations (horiz, vertical,
475  *          slope +1, slope -1).
476  *      (2) The full outline is also drawn if @outline = 1.
477  *      (3) Each of these pta can be rendered onto a pix with random colors,
478  *          by using pixRenderRandomCmapPtaa() with closeflag = 1.
479  *
480  */
481 PTAA  *
generatePtaaHashBoxa(BOXA * boxa,l_int32 spacing,l_int32 width,l_int32 orient,l_int32 outline)482 generatePtaaHashBoxa(BOXA    *boxa,
483                      l_int32  spacing,
484                      l_int32  width,
485                      l_int32  orient,
486                      l_int32  outline)
487 {
488 l_int32  i, n;
489 BOX     *box;
490 PTA     *pta;
491 PTAA    *ptaa;
492 
493     PROCNAME("generatePtaaHashBoxa");
494 
495     if (!boxa)
496         return (PTAA *)ERROR_PTR("boxa not defined", procName, NULL);
497     if (spacing <= 1)
498         return (PTAA *)ERROR_PTR("spacing not > 1", procName, NULL);
499     if (orient != L_HORIZONTAL_LINE && orient != L_POS_SLOPE_LINE &&
500         orient != L_VERTICAL_LINE && orient != L_NEG_SLOPE_LINE)
501         return (PTAA *)ERROR_PTR("invalid line orientation", procName, NULL);
502 
503     n = boxaGetCount(boxa);
504     ptaa = ptaaCreate(n);
505     for (i = 0; i < n; i++) {
506         box = boxaGetBox(boxa, i, L_CLONE);
507         pta = generatePtaHashBox(box, spacing, width, orient, outline);
508         ptaaAddPta(ptaa, pta, L_INSERT);
509         boxDestroy(&box);
510     }
511 
512     return ptaa;
513 }
514 
515 
516 /*!
517  *  generatePtaPolyline()
518  *
519  *      Input:  pta (vertices of polyline)
520  *              width
521  *              closeflag (1 to close the contour; 0 otherwise)
522  *              removedups  (1 to remove, 0 to leave)
523  *      Return: ptad, or null on error
524  *
525  *  Notes:
526  *      (1) If the boxa has overlapping boxes, and if blending will
527  *          be used to give a transparent effect, transparency
528  *          artifacts at line intersections can be removed using
529  *          removedups = 1.
530  */
531 PTA  *
generatePtaPolyline(PTA * ptas,l_int32 width,l_int32 closeflag,l_int32 removedups)532 generatePtaPolyline(PTA     *ptas,
533                     l_int32  width,
534                     l_int32  closeflag,
535                     l_int32  removedups)
536 {
537 l_int32  i, n, x1, y1, x2, y2;
538 PTA     *ptad, *ptat, *pta;
539 
540     PROCNAME("generatePtaPolyline");
541 
542     if (!ptas)
543         return (PTA *)ERROR_PTR("ptas not defined", procName, NULL);
544 
545     n = ptaGetCount(ptas);
546     ptat = ptaCreate(0);
547     if (n < 2)  /* nothing to do */
548         return ptat;
549 
550     ptaGetIPt(ptas, 0, &x1, &y1);
551     for (i = 1; i < n; i++) {
552         ptaGetIPt(ptas, i, &x2, &y2);
553         pta = generatePtaWideLine(x1, y1, x2, y2, width);
554         ptaJoin(ptat, pta, 0, 0);
555         ptaDestroy(&pta);
556         x1 = x2;
557         y1 = y2;
558     }
559 
560     if (closeflag) {
561         ptaGetIPt(ptas, 0, &x2, &y2);
562         pta = generatePtaWideLine(x1, y1, x2, y2, width);
563         ptaJoin(ptat, pta, 0, 0);
564         ptaDestroy(&pta);
565     }
566 
567     if (removedups)
568         ptad = ptaRemoveDuplicates(ptat, 0);
569     else
570         ptad = ptaClone(ptat);
571 
572     ptaDestroy(&ptat);
573     return ptad;
574 }
575 
576 
577 /*!
578  *  generatePtaFilledCircle()
579  *
580  *      Input:  radius
581  *      Return: pta, or null on error
582  *
583  *  Notes:
584  *      (1) The circle is has diameter = 2 * radius + 1.
585  *      (2) It is located with the center of the circle at the
586  *          point (radius, radius).
587  *      (3) Consequently, it typically must be translated if
588  *          it is to represent a set of pixels in an image.
589  */
590 PTA  *
generatePtaFilledCircle(l_int32 radius)591 generatePtaFilledCircle(l_int32  radius)
592 {
593 l_int32    x, y;
594 l_float32  radthresh, sqdist;
595 PTA       *pta;
596 
597     PROCNAME("generatePtaFilledCircle");
598 
599     if (radius < 1)
600         return (PTA *)ERROR_PTR("radius must be >= 1", procName, NULL);
601 
602     pta = ptaCreate(0);
603     radthresh = (radius + 0.5) * (radius + 0.5);
604     for (y = 0; y <= 2 * radius; y++) {
605         for (x = 0; x <= 2 * radius; x++) {
606             sqdist = (l_float32)((y - radius) * (y - radius) +
607                                  (x - radius) * (x - radius));
608             if (sqdist <= radthresh)
609                 ptaAddPt(pta, x, y);
610         }
611     }
612 
613     return pta;
614 }
615 
616 
617 /*!
618  *  generatePtaLineFromPt()
619  *
620  *      Input:  x, y  (point of origination)
621  *              length (of line, including starting point)
622  *              radang (angle in radians, CW from horizontal)
623  *      Return: pta, or null on error
624  *
625  *  Notes:
626  *      (1) The @length of the line is 1 greater than the distance
627  *          used in locatePtRadially().  Example: a distance of 1
628  *          gives rise to a length of 2.
629  */
630 PTA *
generatePtaLineFromPt(l_int32 x,l_int32 y,l_float64 length,l_float64 radang)631 generatePtaLineFromPt(l_int32    x,
632                       l_int32    y,
633                       l_float64  length,
634                       l_float64  radang)
635 {
636 l_int32  x2, y2;  /* the point at the other end of the line */
637 
638     x2 = x + (l_int32)((length - 1.0) * cos(radang));
639     y2 = y + (l_int32)((length - 1.0) * sin(radang));
640     return generatePtaLine(x, y, x2, y2);
641 }
642 
643 
644 /*!
645  *  locatePtRadially()
646  *
647  *      Input:  xr, yr  (reference point)
648  *              radang (angle in radians, CW from horizontal)
649  *              dist (distance of point from reference point along line
650  *                    given by the specified angle)
651  *              &x, &y (<return> location of point)
652  *      Return: 0 if OK, 1 on error
653  */
654 l_int32
locatePtRadially(l_int32 xr,l_int32 yr,l_float64 dist,l_float64 radang,l_float64 * px,l_float64 * py)655 locatePtRadially(l_int32     xr,
656                  l_int32     yr,
657                  l_float64   dist,
658                  l_float64   radang,
659                  l_float64  *px,
660                  l_float64  *py)
661 {
662     PROCNAME("locatePtRadially");
663 
664     if (!px || !py)
665         return ERROR_INT("&x and &y not both defined", procName, 1);
666 
667     *px = xr + dist * cos(radang);
668     *py = yr + dist * sin(radang);
669     return 0;
670 }
671 
672 
673 /*------------------------------------------------------------------*
674  *        Pta generation for arbitrary shapes built with lines      *
675  *------------------------------------------------------------------*/
676 /*!
677  *  pixRenderPta()
678  *
679  *      Input:  pix
680  *              pta (arbitrary set of points)
681  *              op   (one of L_SET_PIXELS, L_CLEAR_PIXELS, L_FLIP_PIXELS)
682  *      Return: 0 if OK, 1 on error
683  *
684  *  Notes:
685  *      (1) L_SET_PIXELS puts all image bits in each pixel to 1
686  *          (black for 1 bpp; white for depth > 1)
687  *      (2) L_CLEAR_PIXELS puts all image bits in each pixel to 0
688  *          (white for 1 bpp; black for depth > 1)
689  *      (3) L_FLIP_PIXELS reverses all image bits in each pixel
690  *      (4) This function clips the rendering to the pix.  It performs
691  *          clipping for functions such as pixRenderLine(),
692  *          pixRenderBox() and pixRenderBoxa(), that call pixRenderPta().
693  */
694 l_int32
pixRenderPta(PIX * pix,PTA * pta,l_int32 op)695 pixRenderPta(PIX     *pix,
696              PTA     *pta,
697              l_int32  op)
698 {
699 l_int32  i, n, x, y, w, h, d, maxval;
700 
701     PROCNAME("pixRenderPta");
702 
703     if (!pix)
704         return ERROR_INT("pix not defined", procName, 1);
705     if (!pta)
706         return ERROR_INT("pta not defined", procName, 1);
707     if (op != L_SET_PIXELS && op != L_CLEAR_PIXELS && op != L_FLIP_PIXELS)
708         return ERROR_INT("invalid op", procName, 1);
709 
710     pixGetDimensions(pix, &w, &h, &d);
711     maxval = 1;
712     if (op == L_SET_PIXELS) {
713         switch (d)
714         {
715         case 2:
716             maxval = 0x3;
717             break;
718         case 4:
719             maxval = 0xf;
720             break;
721         case 8:
722             maxval = 0xff;
723             break;
724         case 16:
725             maxval = 0xffff;
726             break;
727         case 32:
728             maxval = 0xffffffff;
729             break;
730         }
731     }
732 
733     n = ptaGetCount(pta);
734     for (i = 0; i < n; i++) {
735         ptaGetIPt(pta, i, &x, &y);
736         if (x < 0 || x >= w)
737             continue;
738         if (y < 0 || y >= h)
739             continue;
740         switch (op)
741         {
742         case L_SET_PIXELS:
743             pixSetPixel(pix, x, y, maxval);
744             break;
745         case L_CLEAR_PIXELS:
746             pixClearPixel(pix, x, y);
747             break;
748         case L_FLIP_PIXELS:
749             pixFlipPixel(pix, x, y);
750             break;
751         default:
752             break;
753         }
754     }
755 
756     return 0;
757 }
758 
759 
760 /*!
761  *  pixRenderPtaArb()
762  *
763  *      Input:  pix
764  *              pta (arbitrary set of points)
765  *              rval, gval, bval
766  *      Return: 0 if OK, 1 on error
767  *
768  *  Notes:
769  *      (1) If pix is colormapped, render this color on each pixel.
770  *      (2) If pix is not colormapped, do the best job you can using
771  *          the input colors:
772  *          - d = 1: set the pixels
773  *          - d = 2, 4, 8: average the input rgb value
774  *          - d = 32: use the input rgb value
775  *      (3) This function clips the rendering to the pix.
776  */
777 l_int32
pixRenderPtaArb(PIX * pix,PTA * pta,l_uint8 rval,l_uint8 gval,l_uint8 bval)778 pixRenderPtaArb(PIX     *pix,
779                 PTA     *pta,
780                 l_uint8  rval,
781                 l_uint8  gval,
782                 l_uint8  bval)
783 {
784 l_int32   i, n, x, y, w, h, d, index;
785 l_uint8   val;
786 l_uint32  val32;
787 PIXCMAP  *cmap;
788 
789     PROCNAME("pixRenderPtaArb");
790 
791     if (!pix)
792         return ERROR_INT("pix not defined", procName, 1);
793     if (!pta)
794         return ERROR_INT("pta not defined", procName, 1);
795     d = pixGetDepth(pix);
796     if (d != 1 && d != 2 && d != 4 && d != 8 && d != 32)
797         return ERROR_INT("depth not in {1,2,4,8,32}", procName, 1);
798 
799     if (d == 1) {
800         pixRenderPta(pix, pta, L_SET_PIXELS);
801         return 0;
802     }
803 
804     cmap = pixGetColormap(pix);
805     pixGetDimensions(pix, &w, &h, &d);
806     if (cmap) {
807         if (pixcmapAddNewColor(cmap, rval, gval, bval, &index))
808             return ERROR_INT("colormap is full", procName, 1);
809     }
810     else {
811         if (d == 2)
812             val = (rval + gval + bval) / (3 * 64);
813         else if (d == 4)
814             val = (rval + gval + bval) / (3 * 16);
815         else if (d == 8)
816             val = (rval + gval + bval) / 3;
817         else  /* d == 32 */
818             composeRGBPixel(rval, gval, bval, &val32);
819     }
820 
821     n = ptaGetCount(pta);
822     for (i = 0; i < n; i++) {
823         ptaGetIPt(pta, i, &x, &y);
824         if (x < 0 || x >= w)
825             continue;
826         if (y < 0 || y >= h)
827             continue;
828         if (cmap)
829             pixSetPixel(pix, x, y, index);
830         else if (d == 32)
831             pixSetPixel(pix, x, y, val32);
832         else
833             pixSetPixel(pix, x, y, val);
834     }
835 
836     return 0;
837 }
838 
839 
840 /*!
841  *  pixRenderPtaBlend()
842  *
843  *      Input:  pix (32 bpp rgb)
844  *              pta  (arbitrary set of points)
845  *              rval, gval, bval
846  *      Return: 0 if OK, 1 on error
847  *
848  *  Notes:
849  *      (1) This function clips the rendering to the pix.
850  */
851 l_int32
pixRenderPtaBlend(PIX * pix,PTA * pta,l_uint8 rval,l_uint8 gval,l_uint8 bval,l_float32 fract)852 pixRenderPtaBlend(PIX     *pix,
853                   PTA     *pta,
854                   l_uint8  rval,
855                   l_uint8  gval,
856                   l_uint8  bval,
857                   l_float32 fract)
858 {
859 l_int32    i, n, x, y, w, h;
860 l_uint8    nrval, ngval, nbval;
861 l_uint32   val32;
862 l_float32  frval, fgval, fbval;
863 
864     PROCNAME("pixRenderPtaBlend");
865 
866     if (!pix)
867         return ERROR_INT("pix not defined", procName, 1);
868     if (!pta)
869         return ERROR_INT("pta not defined", procName, 1);
870     if (pixGetDepth(pix) != 32)
871         return ERROR_INT("depth not 32 bpp", procName, 1);
872     if (fract < 0.0 || fract > 1.0) {
873         L_WARNING("fract must be in [0.0, 1.0]; setting to 0.5", procName);
874         fract = 0.5;
875     }
876 
877     pixGetDimensions(pix, &w, &h, NULL);
878     n = ptaGetCount(pta);
879     frval = fract * rval;
880     fgval = fract * gval;
881     fbval = fract * bval;
882     for (i = 0; i < n; i++) {
883         ptaGetIPt(pta, i, &x, &y);
884         if (x < 0 || x >= w)
885             continue;
886         if (y < 0 || y >= h)
887             continue;
888         pixGetPixel(pix, x, y, &val32);
889         nrval = GET_DATA_BYTE(&val32, COLOR_RED);
890         nrval = (l_uint8)((1. - fract) * nrval + frval);
891         ngval = GET_DATA_BYTE(&val32, COLOR_GREEN);
892         ngval = (l_uint8)((1. - fract) * ngval + fgval);
893         nbval = GET_DATA_BYTE(&val32, COLOR_BLUE);
894         nbval = (l_uint8)((1. - fract) * nbval + fbval);
895         composeRGBPixel(nrval, ngval, nbval, &val32);
896         pixSetPixel(pix, x, y, val32);
897     }
898 
899     return 0;
900 }
901 
902 
903 /*------------------------------------------------------------------*
904  *           Rendering of arbitrary shapes built with lines         *
905  *------------------------------------------------------------------*/
906 /*!
907  *  pixRenderLine()
908  *
909  *      Input:  pix
910  *              x1, y1
911  *              x2, y2
912  *              width  (thickness of line)
913  *              op  (one of L_SET_PIXELS, L_CLEAR_PIXELS, L_FLIP_PIXELS)
914  *      Return: 0 if OK, 1 on error
915  */
916 l_int32
pixRenderLine(PIX * pix,l_int32 x1,l_int32 y1,l_int32 x2,l_int32 y2,l_int32 width,l_int32 op)917 pixRenderLine(PIX     *pix,
918               l_int32  x1,
919               l_int32  y1,
920               l_int32  x2,
921               l_int32  y2,
922               l_int32  width,
923               l_int32  op)
924 {
925 PTA  *pta;
926 
927     PROCNAME("pixRenderLine");
928 
929     if (!pix)
930         return ERROR_INT("pix not defined", procName, 1);
931     if (width < 1) {
932         L_WARNING("width must be > 0; setting to 1", procName);
933         width = 1;
934     }
935     if (op != L_SET_PIXELS && op != L_CLEAR_PIXELS && op != L_FLIP_PIXELS)
936         return ERROR_INT("invalid op", procName, 1);
937 
938     if ((pta = generatePtaWideLine(x1, y1, x2, y2, width)) == NULL)
939         return ERROR_INT("pta not made", procName, 1);
940     pixRenderPta(pix, pta, op);
941     ptaDestroy(&pta);
942     return 0;
943 }
944 
945 
946 /*!
947  *  pixRenderLineArb()
948  *
949  *      Input:  pix
950  *              x1, y1
951  *              x2, y2
952  *              width  (thickness of line)
953  *              rval, gval, bval
954  *      Return: 0 if OK, 1 on error
955  */
956 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)957 pixRenderLineArb(PIX     *pix,
958                  l_int32  x1,
959                  l_int32  y1,
960                  l_int32  x2,
961                  l_int32  y2,
962                  l_int32  width,
963                  l_uint8  rval,
964                  l_uint8  gval,
965                  l_uint8  bval)
966 {
967 PTA  *pta;
968 
969     PROCNAME("pixRenderLineArb");
970 
971     if (!pix)
972         return ERROR_INT("pix not defined", procName, 1);
973     if (width < 1) {
974         L_WARNING("width must be > 0; setting to 1", procName);
975         width = 1;
976     }
977 
978     if ((pta = generatePtaWideLine(x1, y1, x2, y2, width)) == NULL)
979         return ERROR_INT("pta not made", procName, 1);
980     pixRenderPtaArb(pix, pta, rval, gval, bval);
981     ptaDestroy(&pta);
982     return 0;
983 }
984 
985 
986 /*!
987  *  pixRenderLineBlend()
988  *
989  *      Input:  pix
990  *              x1, y1
991  *              x2, y2
992  *              width  (thickness of line)
993  *              rval, gval, bval
994  *              fract
995  *      Return: 0 if OK, 1 on error
996  */
997 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)998 pixRenderLineBlend(PIX       *pix,
999                    l_int32    x1,
1000                    l_int32    y1,
1001                    l_int32    x2,
1002                    l_int32    y2,
1003                    l_int32    width,
1004                    l_uint8    rval,
1005                    l_uint8    gval,
1006                    l_uint8    bval,
1007                    l_float32  fract)
1008 {
1009 PTA  *pta;
1010 
1011     PROCNAME("pixRenderLineBlend");
1012 
1013     if (!pix)
1014         return ERROR_INT("pix not defined", procName, 1);
1015     if (width < 1) {
1016         L_WARNING("width must be > 0; setting to 1", procName);
1017         width = 1;
1018     }
1019 
1020     if ((pta = generatePtaWideLine(x1, y1, x2, y2, width)) == NULL)
1021         return ERROR_INT("pta not made", procName, 1);
1022     pixRenderPtaBlend(pix, pta, rval, gval, bval, fract);
1023     ptaDestroy(&pta);
1024     return 0;
1025 }
1026 
1027 
1028 /*!
1029  *  pixRenderBox()
1030  *
1031  *      Input:  pix
1032  *              box
1033  *              width  (thickness of box lines)
1034  *              op  (one of L_SET_PIXELS, L_CLEAR_PIXELS, L_FLIP_PIXELS)
1035  *      Return: 0 if OK, 1 on error
1036  */
1037 l_int32
pixRenderBox(PIX * pix,BOX * box,l_int32 width,l_int32 op)1038 pixRenderBox(PIX     *pix,
1039              BOX     *box,
1040              l_int32  width,
1041              l_int32  op)
1042 {
1043 PTA  *pta;
1044 
1045     PROCNAME("pixRenderBox");
1046 
1047     if (!pix)
1048         return ERROR_INT("pix not defined", procName, 1);
1049     if (!box)
1050         return ERROR_INT("box not defined", procName, 1);
1051     if (op != L_SET_PIXELS && op != L_CLEAR_PIXELS && op != L_FLIP_PIXELS)
1052         return ERROR_INT("invalid op", procName, 1);
1053 
1054     if ((pta = generatePtaBox(box, width)) == NULL)
1055         return ERROR_INT("pta not made", procName, 1);
1056     pixRenderPta(pix, pta, op);
1057     ptaDestroy(&pta);
1058     return 0;
1059 }
1060 
1061 
1062 /*!
1063  *  pixRenderBoxArb()
1064  *
1065  *      Input:  pix
1066  *              box
1067  *              width  (thickness of box lines)
1068  *              rval, gval, bval
1069  *      Return: 0 if OK, 1 on error
1070  */
1071 l_int32
pixRenderBoxArb(PIX * pix,BOX * box,l_int32 width,l_uint8 rval,l_uint8 gval,l_uint8 bval)1072 pixRenderBoxArb(PIX     *pix,
1073                 BOX     *box,
1074                 l_int32  width,
1075                 l_uint8  rval,
1076                 l_uint8  gval,
1077                 l_uint8  bval)
1078 {
1079 PTA  *pta;
1080 
1081     PROCNAME("pixRenderBoxArb");
1082 
1083     if (!pix)
1084         return ERROR_INT("pix not defined", procName, 1);
1085     if (!box)
1086         return ERROR_INT("box not defined", procName, 1);
1087 
1088     if ((pta = generatePtaBox(box, width)) == NULL)
1089         return ERROR_INT("pta not made", procName, 1);
1090     pixRenderPtaArb(pix, pta, rval, gval, bval);
1091     ptaDestroy(&pta);
1092     return 0;
1093 }
1094 
1095 
1096 /*!
1097  *  pixRenderBoxBlend()
1098  *
1099  *      Input:  pix
1100  *              box
1101  *              width  (thickness of box lines)
1102  *              rval, gval, bval
1103  *              fract (in [0.0 - 1.0]; complete transparency (no effect)
1104  *                     if 0.0; no transparency if 1.0)
1105  *      Return: 0 if OK, 1 on error
1106  */
1107 l_int32
pixRenderBoxBlend(PIX * pix,BOX * box,l_int32 width,l_uint8 rval,l_uint8 gval,l_uint8 bval,l_float32 fract)1108 pixRenderBoxBlend(PIX       *pix,
1109                   BOX       *box,
1110                   l_int32    width,
1111                   l_uint8    rval,
1112                   l_uint8    gval,
1113                   l_uint8    bval,
1114                   l_float32  fract)
1115 {
1116 PTA  *pta;
1117 
1118     PROCNAME("pixRenderBoxBlend");
1119 
1120     if (!pix)
1121         return ERROR_INT("pix not defined", procName, 1);
1122     if (!box)
1123         return ERROR_INT("box not defined", procName, 1);
1124 
1125     if ((pta = generatePtaBox(box, width)) == NULL)
1126         return ERROR_INT("pta not made", procName, 1);
1127     pixRenderPtaBlend(pix, pta, rval, gval, bval, fract);
1128     ptaDestroy(&pta);
1129     return 0;
1130 }
1131 
1132 
1133 /*!
1134  *  pixRenderHashBox()
1135  *
1136  *      Input:  pix
1137  *              box
1138  *              spacing (spacing between lines; must be > 1)
1139  *              width  (thickness of box and hash lines)
1140  *              orient  (orientation of lines: L_HORIZONTAL_LINE, ...)
1141  *              outline  (0 to skip drawing box outline)
1142  *              op  (one of L_SET_PIXELS, L_CLEAR_PIXELS, L_FLIP_PIXELS)
1143  *      Return: 0 if OK, 1 on error
1144  */
1145 l_int32
pixRenderHashBox(PIX * pix,BOX * box,l_int32 spacing,l_int32 width,l_int32 orient,l_int32 outline,l_int32 op)1146 pixRenderHashBox(PIX     *pix,
1147                  BOX     *box,
1148                  l_int32  spacing,
1149                  l_int32  width,
1150                  l_int32  orient,
1151                  l_int32  outline,
1152                  l_int32  op)
1153 {
1154 PTA  *pta;
1155 
1156     PROCNAME("pixRenderHashBox");
1157 
1158     if (!pix)
1159         return ERROR_INT("pix not defined", procName, 1);
1160     if (!box)
1161         return ERROR_INT("box not defined", procName, 1);
1162     if (spacing <= 1)
1163         return ERROR_INT("spacing not > 1", procName, 1);
1164     if (orient != L_HORIZONTAL_LINE && orient != L_POS_SLOPE_LINE &&
1165         orient != L_VERTICAL_LINE && orient != L_NEG_SLOPE_LINE)
1166         return ERROR_INT("invalid line orientation", procName, 1);
1167     if (op != L_SET_PIXELS && op != L_CLEAR_PIXELS && op != L_FLIP_PIXELS)
1168         return ERROR_INT("invalid op", procName, 1);
1169 
1170     pta = generatePtaHashBox(box, spacing, width, orient, outline);
1171     if (!pta)
1172         return ERROR_INT("pta not made", procName, 1);
1173     pixRenderPta(pix, pta, op);
1174     ptaDestroy(&pta);
1175     return 0;
1176 }
1177 
1178 
1179 /*!
1180  *  pixRenderBoxArb()
1181  *
1182  *      Input:  pix
1183  *              box
1184  *              spacing (spacing between lines; must be > 1)
1185  *              width  (thickness of box and hash lines)
1186  *              orient  (orientation of lines: L_HORIZONTAL_LINE, ...)
1187  *              outline  (0 to skip drawing box outline)
1188  *              rval, gval, bval
1189  *      Return: 0 if OK, 1 on error
1190  */
1191 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)1192 pixRenderHashBoxArb(PIX     *pix,
1193                     BOX     *box,
1194                     l_int32  spacing,
1195                     l_int32  width,
1196                     l_int32  orient,
1197                     l_int32  outline,
1198                     l_int32  rval,
1199                     l_int32  gval,
1200                     l_int32  bval)
1201 {
1202 PTA  *pta;
1203 
1204     PROCNAME("pixRenderHashBoxArb");
1205 
1206     if (!pix)
1207         return ERROR_INT("pix not defined", procName, 1);
1208     if (!box)
1209         return ERROR_INT("box not defined", procName, 1);
1210     if (spacing <= 1)
1211         return ERROR_INT("spacing not > 1", procName, 1);
1212     if (orient != L_HORIZONTAL_LINE && orient != L_POS_SLOPE_LINE &&
1213         orient != L_VERTICAL_LINE && orient != L_NEG_SLOPE_LINE)
1214         return ERROR_INT("invalid line orientation", procName, 1);
1215 
1216     pta = generatePtaHashBox(box, spacing, width, orient, outline);
1217     if (!pta)
1218         return ERROR_INT("pta not made", procName, 1);
1219     pixRenderPtaArb(pix, pta, rval, gval, bval);
1220     ptaDestroy(&pta);
1221     return 0;
1222 }
1223 
1224 
1225 /*!
1226  *  pixRenderHashBoxBlend()
1227  *
1228  *      Input:  pix
1229  *              box
1230  *              spacing (spacing between lines; must be > 1)
1231  *              width  (thickness of box and hash lines)
1232  *              orient  (orientation of lines: L_HORIZONTAL_LINE, ...)
1233  *              outline  (0 to skip drawing box outline)
1234  *              rval, gval, bval
1235  *              fract (in [0.0 - 1.0]; complete transparency (no effect)
1236  *                     if 0.0; no transparency if 1.0)
1237  *      Return: 0 if OK, 1 on error
1238  */
1239 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)1240 pixRenderHashBoxBlend(PIX       *pix,
1241                       BOX       *box,
1242                       l_int32    spacing,
1243                       l_int32    width,
1244                       l_int32    orient,
1245                       l_int32    outline,
1246                       l_int32    rval,
1247                       l_int32    gval,
1248                       l_int32    bval,
1249                       l_float32  fract)
1250 {
1251 PTA  *pta;
1252 
1253     PROCNAME("pixRenderHashBoxBlend");
1254 
1255     if (!pix)
1256         return ERROR_INT("pix not defined", procName, 1);
1257     if (!box)
1258         return ERROR_INT("box not defined", procName, 1);
1259     if (spacing <= 1)
1260         return ERROR_INT("spacing not > 1", procName, 1);
1261     if (orient != L_HORIZONTAL_LINE && orient != L_POS_SLOPE_LINE &&
1262         orient != L_VERTICAL_LINE && orient != L_NEG_SLOPE_LINE)
1263         return ERROR_INT("invalid line orientation", procName, 1);
1264 
1265     pta = generatePtaHashBox(box, spacing, width, orient, outline);
1266     if (!pta)
1267         return ERROR_INT("pta not made", procName, 1);
1268     pixRenderPtaBlend(pix, pta, rval, gval, bval, fract);
1269     ptaDestroy(&pta);
1270     return 0;
1271 }
1272 
1273 
1274 /*!
1275  *  pixRenderBoxa()
1276  *
1277  *      Input:  pix
1278  *              boxa
1279  *              width  (thickness of line)
1280  *              op  (one of L_SET_PIXELS, L_CLEAR_PIXELS, L_FLIP_PIXELS)
1281  *      Return: 0 if OK, 1 on error
1282  */
1283 l_int32
pixRenderBoxa(PIX * pix,BOXA * boxa,l_int32 width,l_int32 op)1284 pixRenderBoxa(PIX     *pix,
1285               BOXA    *boxa,
1286               l_int32  width,
1287               l_int32  op)
1288 {
1289 PTA  *pta;
1290 
1291     PROCNAME("pixRenderBoxa");
1292 
1293     if (!pix)
1294         return ERROR_INT("pix not defined", procName, 1);
1295     if (!boxa)
1296         return ERROR_INT("boxa not defined", procName, 1);
1297     if (op != L_SET_PIXELS && op != L_CLEAR_PIXELS && op != L_FLIP_PIXELS)
1298         return ERROR_INT("invalid op", procName, 1);
1299 
1300     if ((pta = generatePtaBoxa(boxa, width, 0)) == NULL)
1301         return ERROR_INT("pta not made", procName, 1);
1302     pixRenderPta(pix, pta, op);
1303     ptaDestroy(&pta);
1304     return 0;
1305 }
1306 
1307 
1308 /*!
1309  *  pixRenderBoxaArb()
1310  *
1311  *      Input:  pix
1312  *              boxa
1313  *              width  (thickness of line)
1314  *              rval, gval, bval
1315  *      Return: 0 if OK, 1 on error
1316  */
1317 l_int32
pixRenderBoxaArb(PIX * pix,BOXA * boxa,l_int32 width,l_uint8 rval,l_uint8 gval,l_uint8 bval)1318 pixRenderBoxaArb(PIX     *pix,
1319                  BOXA    *boxa,
1320                  l_int32  width,
1321                  l_uint8  rval,
1322                  l_uint8  gval,
1323                  l_uint8  bval)
1324 {
1325 PTA  *pta;
1326 
1327     PROCNAME("pixRenderBoxaArb");
1328 
1329     if (!pix)
1330         return ERROR_INT("pix not defined", procName, 1);
1331     if (!boxa)
1332         return ERROR_INT("boxa not defined", procName, 1);
1333 
1334     if ((pta = generatePtaBoxa(boxa, width, 0)) == NULL)
1335         return ERROR_INT("pta not made", procName, 1);
1336     pixRenderPtaArb(pix, pta, rval, gval, bval);
1337     ptaDestroy(&pta);
1338     return 0;
1339 }
1340 
1341 
1342 /*!
1343  *  pixRenderBoxaBlend()
1344  *
1345  *      Input:  pix
1346  *              boxa
1347  *              width  (thickness of line)
1348  *              rval, gval, bval
1349  *              fract (in [0.0 - 1.0]; complete transparency (no effect)
1350  *                     if 0.0; no transparency if 1.0)
1351  *              removedups  (1 to remove; 0 otherwise)
1352  *      Return: 0 if OK, 1 on error
1353  */
1354 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)1355 pixRenderBoxaBlend(PIX       *pix,
1356                    BOXA      *boxa,
1357                    l_int32    width,
1358                    l_uint8    rval,
1359                    l_uint8    gval,
1360                    l_uint8    bval,
1361                    l_float32  fract,
1362                    l_int32    removedups)
1363 {
1364 PTA  *pta;
1365 
1366     PROCNAME("pixRenderBoxaBlend");
1367 
1368     if (!pix)
1369         return ERROR_INT("pix not defined", procName, 1);
1370     if (!boxa)
1371         return ERROR_INT("boxa not defined", procName, 1);
1372 
1373     if ((pta = generatePtaBoxa(boxa, width, removedups)) == NULL)
1374         return ERROR_INT("pta not made", procName, 1);
1375     pixRenderPtaBlend(pix, pta, rval, gval, bval, fract);
1376     ptaDestroy(&pta);
1377     return 0;
1378 }
1379 
1380 
1381 /*!
1382  *  pixRenderPolyline()
1383  *
1384  *      Input:  pix
1385  *              ptas
1386  *              width  (thickness of line)
1387  *              op  (one of L_SET_PIXELS, L_CLEAR_PIXELS, L_FLIP_PIXELS)
1388  *              closeflag (1 to close the contour; 0 otherwise)
1389  *      Return: 0 if OK, 1 on error
1390  *
1391  *  Note: this renders a closed contour.
1392  */
1393 l_int32
pixRenderPolyline(PIX * pix,PTA * ptas,l_int32 width,l_int32 op,l_int32 closeflag)1394 pixRenderPolyline(PIX     *pix,
1395                   PTA     *ptas,
1396                   l_int32  width,
1397                   l_int32  op,
1398                   l_int32  closeflag)
1399 {
1400 PTA  *pta;
1401 
1402     PROCNAME("pixRenderPolyline");
1403 
1404     if (!pix)
1405         return ERROR_INT("pix not defined", procName, 1);
1406     if (!ptas)
1407         return ERROR_INT("ptas not defined", procName, 1);
1408     if (op != L_SET_PIXELS && op != L_CLEAR_PIXELS && op != L_FLIP_PIXELS)
1409         return ERROR_INT("invalid op", procName, 1);
1410 
1411     if ((pta = generatePtaPolyline(ptas, width, closeflag, 0)) == NULL)
1412         return ERROR_INT("pta not made", procName, 1);
1413     pixRenderPta(pix, pta, op);
1414     ptaDestroy(&pta);
1415     return 0;
1416 }
1417 
1418 
1419 /*!
1420  *  pixRenderPolylineArb()
1421  *
1422  *      Input:  pix
1423  *              ptas
1424  *              width  (thickness of line)
1425  *              rval, gval, bval
1426  *              closeflag (1 to close the contour; 0 otherwise)
1427  *      Return: 0 if OK, 1 on error
1428  *
1429  *  Note: this renders a closed contour.
1430  */
1431 l_int32
pixRenderPolylineArb(PIX * pix,PTA * ptas,l_int32 width,l_uint8 rval,l_uint8 gval,l_uint8 bval,l_int32 closeflag)1432 pixRenderPolylineArb(PIX     *pix,
1433                      PTA     *ptas,
1434                      l_int32  width,
1435                      l_uint8  rval,
1436                      l_uint8  gval,
1437                      l_uint8  bval,
1438                      l_int32  closeflag)
1439 {
1440 PTA  *pta;
1441 
1442     PROCNAME("pixRenderPolylineArb");
1443 
1444     if (!pix)
1445         return ERROR_INT("pix not defined", procName, 1);
1446     if (!ptas)
1447         return ERROR_INT("ptas not defined", procName, 1);
1448 
1449     if ((pta = generatePtaPolyline(ptas, width, closeflag, 0)) == NULL)
1450         return ERROR_INT("pta not made", procName, 1);
1451     pixRenderPtaArb(pix, pta, rval, gval, bval);
1452     ptaDestroy(&pta);
1453     return 0;
1454 }
1455 
1456 
1457 /*!
1458  *  pixRenderPolylineBlend()
1459  *
1460  *      Input:  pix
1461  *              ptas
1462  *              width  (thickness of line)
1463  *              rval, gval, bval
1464  *              fract (in [0.0 - 1.0]; complete transparency (no effect)
1465  *                     if 0.0; no transparency if 1.0)
1466  *              closeflag (1 to close the contour; 0 otherwise)
1467  *              removedups  (1 to remove; 0 otherwise)
1468  *      Return: 0 if OK, 1 on error
1469  */
1470 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)1471 pixRenderPolylineBlend(PIX       *pix,
1472                        PTA       *ptas,
1473                        l_int32    width,
1474                        l_uint8    rval,
1475                        l_uint8    gval,
1476                        l_uint8    bval,
1477                        l_float32  fract,
1478                        l_int32    closeflag,
1479                        l_int32    removedups)
1480 {
1481 PTA  *pta;
1482 
1483     PROCNAME("pixRenderPolylineBlend");
1484 
1485     if (!pix)
1486         return ERROR_INT("pix not defined", procName, 1);
1487     if (!ptas)
1488         return ERROR_INT("ptas not defined", procName, 1);
1489 
1490     if ((pta = generatePtaPolyline(ptas, width, closeflag, removedups)) == NULL)
1491         return ERROR_INT("pta not made", procName, 1);
1492     pixRenderPtaBlend(pix, pta, rval, gval, bval, fract);
1493     ptaDestroy(&pta);
1494     return 0;
1495 }
1496 
1497 
1498 /*!
1499  *  pixRenderRandomCmapPtaa()
1500  *
1501  *      Input:  pix (1, 2, 4, 8, 16, 32 bpp)
1502  *              ptaa
1503  *              polyflag (1 to interpret each Pta as a polyline; 0 to simply
1504  *                        render the Pta as a set of pixels)
1505  *              width  (thickness of line; use only for polyline)
1506  *              closeflag (1 to close the contour; 0 otherwise;
1507  *                         use only for polyline mode)
1508  *      Return: pixd (cmapped, 8 bpp) or null on error
1509  *
1510  *  Notes:
1511  *      (1) This is a debugging routine, that displays a set of
1512  *          pixels, selected by the set of Ptas in a Ptaa,
1513  *          in a random color in a pix.
1514  *      (2) If @polyflag == 1, each Pta is considered to be a polyline,
1515  *          and is rendered using @width and @closeflag.  Each polyline
1516  *          is rendered in a random color.
1517  *      (3) If @polyflag == 0, all points in each Pta are rendered in a
1518  *          random color.  The @width and @closeflag parameters are ignored.
1519  *      (4) The output pix is 8 bpp and colormapped.  Up to 254
1520  *          different, randomly selected colors, can be used.
1521  *      (5) The rendered pixels replace the input pixels.  They will
1522  *          be clipped silently to the input pix.
1523  */
1524 PIX  *
pixRenderRandomCmapPtaa(PIX * pix,PTAA * ptaa,l_int32 polyflag,l_int32 width,l_int32 closeflag)1525 pixRenderRandomCmapPtaa(PIX     *pix,
1526                         PTAA    *ptaa,
1527                         l_int32  polyflag,
1528                         l_int32  width,
1529                         l_int32  closeflag)
1530 {
1531 l_int32   i, n, index, rval, gval, bval;
1532 PIXCMAP  *cmap;
1533 PTA      *pta, *ptat;
1534 PIX      *pixd;
1535 
1536     PROCNAME("pixRenderRandomCmapPtaa");
1537 
1538     if (!pix)
1539         return (PIX *)ERROR_PTR("pix not defined", procName, NULL);
1540     if (!ptaa)
1541         return (PIX *)ERROR_PTR("ptaa not defined", procName, NULL);
1542 
1543     pixd = pixConvertTo8(pix, FALSE);
1544     cmap = pixcmapCreateRandom(8, 1, 1);
1545     pixSetColormap(pixd, cmap);
1546 
1547     if ((n = ptaaGetCount(ptaa)) == 0)
1548         return pixd;
1549 
1550     for (i = 0; i < n; i++) {
1551         index = 1 + (i % 254);
1552         pixcmapGetColor(cmap, index, &rval, &gval, &bval);
1553         pta = ptaaGetPta(ptaa, i, L_CLONE);
1554         if (polyflag)
1555             ptat = generatePtaPolyline(pta, width, closeflag, 0);
1556         else
1557             ptat = ptaClone(pta);
1558         pixRenderPtaArb(pixd, ptat, rval, gval, bval);
1559         ptaDestroy(&pta);
1560         ptaDestroy(&ptat);
1561     }
1562 
1563     return pixd;
1564 }
1565 
1566 
1567 /*------------------------------------------------------------------*
1568  *             Contour rendering on grayscale images                *
1569  *------------------------------------------------------------------*/
1570 /*!
1571  *  pixRenderContours()
1572  *
1573  *      Input:  pixs (8 or 16 bpp)
1574  *              startval (value of lowest contour; must be in [0 ... maxval])
1575  *              incr  (increment to next contour; must be > 0)
1576  *              outdepth (either 1 or depth of pixs)
1577  *      Return: pixd, or null on error
1578  *
1579  *  The output can be either 1 bpp, showing just the contour
1580  *  lines, or a copy of the input pixs with the contour lines
1581  *  superposed.
1582  */
1583 PIX *
pixRenderContours(PIX * pixs,l_int32 startval,l_int32 incr,l_int32 outdepth)1584 pixRenderContours(PIX     *pixs,
1585                   l_int32  startval,
1586                   l_int32  incr,
1587                   l_int32  outdepth)
1588 {
1589 l_int32    w, h, d, maxval, wpls, wpld, i, j, val, test;
1590 l_uint32  *datas, *datad, *lines, *lined;
1591 PIX       *pixd;
1592 
1593     PROCNAME("pixRenderContours");
1594 
1595     if (!pixs)
1596         return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
1597     if (pixGetColormap(pixs))
1598         return (PIX *)ERROR_PTR("pixs has colormap", procName, NULL);
1599     d = pixGetDepth(pixs);
1600     if (d != 8 && d != 16)
1601         return (PIX *)ERROR_PTR("pixs not 8 or 16 bpp", procName, NULL);
1602     if (outdepth != 1 && outdepth != d) {
1603         L_WARNING("invalid outdepth; setting to 1", procName);
1604         outdepth = 1;
1605     }
1606     maxval = (1 << d) - 1;
1607     if (startval < 0 || startval > maxval)
1608         return (PIX *)ERROR_PTR("startval not in [0 ... maxval]",
1609                procName, NULL);
1610     if (incr < 1)
1611         return (PIX *)ERROR_PTR("incr < 1", procName, NULL);
1612 
1613     w = pixGetWidth(pixs);
1614     h = pixGetHeight(pixs);
1615     if (outdepth == d)
1616         pixd = pixCopy(NULL, pixs);
1617     else
1618         pixd = pixCreate(w, h, 1);
1619 
1620     pixCopyResolution(pixd, pixs);
1621     datad = pixGetData(pixd);
1622     wpld = pixGetWpl(pixd);
1623     datas = pixGetData(pixs);
1624     wpls = pixGetWpl(pixs);
1625 
1626     switch (d)
1627     {
1628     case 8:
1629         if (outdepth == 1) {
1630             for (i = 0; i < h; i++) {
1631                 lines = datas + i * wpls;
1632                 lined = datad + i * wpld;
1633                 for (j = 0; j < w; j++) {
1634                     val = GET_DATA_BYTE(lines, j);
1635                     if (val < startval)
1636                         continue;
1637                     test = (val - startval) % incr;
1638                     if (!test)
1639                         SET_DATA_BIT(lined, j);
1640                 }
1641             }
1642         }
1643         else {  /* outdepth == d */
1644             for (i = 0; i < h; i++) {
1645                 lines = datas + i * wpls;
1646                 lined = datad + i * wpld;
1647                 for (j = 0; j < w; j++) {
1648                     val = GET_DATA_BYTE(lines, j);
1649                     if (val < startval)
1650                         continue;
1651                     test = (val - startval) % incr;
1652                     if (!test)
1653                         SET_DATA_BYTE(lined, j, 0);
1654                 }
1655             }
1656         }
1657         break;
1658 
1659     case 16:
1660         if (outdepth == 1) {
1661             for (i = 0; i < h; i++) {
1662                 lines = datas + i * wpls;
1663                 lined = datad + i * wpld;
1664                 for (j = 0; j < w; j++) {
1665                     val = GET_DATA_TWO_BYTES(lines, j);
1666                     if (val < startval)
1667                         continue;
1668                     test = (val - startval) % incr;
1669                     if (!test)
1670                         SET_DATA_BIT(lined, j);
1671                 }
1672             }
1673         }
1674         else {  /* outdepth == d */
1675             for (i = 0; i < h; i++) {
1676                 lines = datas + i * wpls;
1677                 lined = datad + i * wpld;
1678                 for (j = 0; j < w; j++) {
1679                     val = GET_DATA_TWO_BYTES(lines, j);
1680                     if (val < startval)
1681                         continue;
1682                     test = (val - startval) % incr;
1683                     if (!test)
1684                         SET_DATA_TWO_BYTES(lined, j, 0);
1685                 }
1686             }
1687         }
1688         break;
1689 
1690     default:
1691         return (PIX *)ERROR_PTR("pixs not 8 or 16 bpp", procName, NULL);
1692     }
1693 
1694     return pixd;
1695 }
1696 
1697