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