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