Leptonica 1.82.0
Image processing and image analysis suite
textops.c
Go to the documentation of this file.
1/*====================================================================*
2 - Copyright (C) 2001 Leptonica. All rights reserved.
3 -
4 - Redistribution and use in source and binary forms, with or without
5 - modification, are permitted provided that the following conditions
6 - are met:
7 - 1. Redistributions of source code must retain the above copyright
8 - notice, this list of conditions and the following disclaimer.
9 - 2. Redistributions in binary form must reproduce the above
10 - copyright notice, this list of conditions and the following
11 - disclaimer in the documentation and/or other materials
12 - provided with the distribution.
13 -
14 - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY
18 - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23 - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *====================================================================*/
26
27
75#ifdef HAVE_CONFIG_H
76#include <config_auto.h>
77#endif /* HAVE_CONFIG_H */
78
79#include <string.h>
80#include "allheaders.h"
81
82static l_int32 stringAllWhitespace(char *textstr, l_int32 *pval);
83static l_int32 stringLeadingWhitespace(char *textstr, l_int32 *pval);
84
85
86/*---------------------------------------------------------------------*
87 * Font layout *
88 *---------------------------------------------------------------------*/
119PIX *
121 L_BMF *bmf,
122 const char *textstr,
123 l_uint32 val,
124 l_int32 location,
125 l_int32 *poverflow)
126{
127char *linestr;
128l_int32 w, h, d, i, y, xstart, ystart, extra, spacer, rval, gval, bval;
129l_int32 nlines, htext, ovf, overflow, offset, index;
130l_uint32 textcolor;
131PIX *pixd;
132PIXCMAP *cmap, *cmapd;
133SARRAY *salines;
134
135 PROCNAME("pixAddSingleTextblock");
136
137 if (poverflow) *poverflow = 0;
138 if (!pixs)
139 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
140 if (location != L_ADD_ABOVE && location != L_ADD_AT_TOP &&
141 location != L_ADD_AT_BOT && location != L_ADD_BELOW)
142 return (PIX *)ERROR_PTR("invalid location", procName, NULL);
143 if (!bmf) {
144 L_ERROR("no bitmap fonts; returning a copy\n", procName);
145 return pixCopy(NULL, pixs);
146 }
147 if (!textstr)
148 textstr = pixGetText(pixs);
149 if (!textstr) {
150 L_WARNING("no textstring defined; returning a copy\n", procName);
151 return pixCopy(NULL, pixs);
152 }
153
154 /* Make sure the "color" value for the text will work
155 * for the pix. If the pix is not colormapped and the
156 * value is out of range, set it to mid-range. */
157 pixGetDimensions(pixs, &w, &h, &d);
158 cmap = pixGetColormap(pixs);
159 if (d == 1 && val > 1)
160 val = 1;
161 else if (d == 2 && val > 3 && !cmap)
162 val = 2;
163 else if (d == 4 && val > 15 && !cmap)
164 val = 8;
165 else if (d == 8 && val > 0xff && !cmap)
166 val = 128;
167 else if (d == 16 && val > 0xffff)
168 val = 0x8000;
169 else if (d == 32 && val < 256)
170 val = 0x80808000;
171
172 xstart = (l_int32)(0.1 * w);
173 salines = bmfGetLineStrings(bmf, textstr, w - 2 * xstart, 0, &htext);
174 if (!salines)
175 return (PIX *)ERROR_PTR("line string sa not made", procName, NULL);
176 nlines = sarrayGetCount(salines);
177
178 /* Add white border if required */
179 spacer = 10; /* pixels away from image boundary or added border */
180 if (location == L_ADD_ABOVE || location == L_ADD_BELOW) {
181 extra = htext + 2 * spacer;
182 pixd = pixCreate(w, h + extra, d);
183 pixCopyColormap(pixd, pixs);
184 pixCopyResolution(pixd, pixs);
185 pixCopyText(pixd, pixs);
187 if (location == L_ADD_ABOVE)
188 pixRasterop(pixd, 0, extra, w, h, PIX_SRC, pixs, 0, 0);
189 else /* add below */
190 pixRasterop(pixd, 0, 0, w, h, PIX_SRC, pixs, 0, 0);
191 } else {
192 pixd = pixCopy(NULL, pixs);
193 }
194 cmapd = pixGetColormap(pixd);
195
196 /* bmf->baselinetab[93] is the approximate distance from
197 * the top of the tallest character to the baseline. 93 was chosen
198 * at random, as all the baselines are essentially equal for
199 * each character in a font. */
200 offset = bmf->baselinetab[93];
201 if (location == L_ADD_ABOVE || location == L_ADD_AT_TOP)
202 ystart = offset + spacer;
203 else if (location == L_ADD_AT_BOT)
204 ystart = h - htext - spacer + offset;
205 else /* add below */
206 ystart = h + offset + spacer;
207
208 /* If cmapped, add the color if necessary to the cmap. If the
209 * cmap is full, use the nearest color to the requested color. */
210 if (cmapd) {
211 extractRGBValues(val, &rval, &gval, &bval);
212 pixcmapAddNearestColor(cmapd, rval, gval, bval, &index);
213 pixcmapGetColor(cmapd, index, &rval, &gval, &bval);
214 composeRGBPixel(rval, gval, bval, &textcolor);
215 } else {
216 textcolor = val;
217 }
218
219 /* Keep track of overflow condition on line width */
220 overflow = 0;
221 for (i = 0, y = ystart; i < nlines; i++) {
222 linestr = sarrayGetString(salines, i, L_NOCOPY);
223 pixSetTextline(pixd, bmf, linestr, textcolor,
224 xstart, y, NULL, &ovf);
225 y += bmf->lineheight + bmf->vertlinesep;
226 if (ovf)
227 overflow = 1;
228 }
229
230 /* Also consider vertical overflow where there is too much text to
231 * fit inside the image: the cases L_ADD_AT_TOP and L_ADD_AT_BOT.
232 * The text requires a total of htext + 2 * spacer vertical pixels. */
233 if (location == L_ADD_AT_TOP || location == L_ADD_AT_BOT) {
234 if (h < htext + 2 * spacer)
235 overflow = 1;
236 }
237 if (poverflow) *poverflow = overflow;
238
239 sarrayDestroy(&salines);
240 return pixd;
241}
242
243
275PIX *
277 L_BMF *bmf,
278 const char *textstr,
279 l_uint32 val,
280 l_int32 location)
281{
282char *str;
283l_int32 i, w, h, d, rval, gval, bval, index;
284l_int32 wline, wtext, htext, wadd, hadd, spacer, hbaseline, nlines;
285l_uint32 textcolor;
286PIX *pixd;
287PIXCMAP *cmap, *cmapd;
288SARRAY *sa;
289
290 PROCNAME("pixAddTextlines");
291
292 if (!pixs)
293 return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
294 if (location != L_ADD_ABOVE && location != L_ADD_BELOW &&
295 location != L_ADD_LEFT && location != L_ADD_RIGHT)
296 return (PIX *)ERROR_PTR("invalid location", procName, NULL);
297 if (!bmf) {
298 L_ERROR("no bitmap fonts; returning a copy\n", procName);
299 return pixCopy(NULL, pixs);
300 }
301 if (!textstr) {
302 textstr = pixGetText(pixs);
303 if (!textstr) {
304 L_WARNING("no textstring defined; returning a copy\n", procName);
305 return pixCopy(NULL, pixs);
306 }
307 }
308
309 /* Make sure the "color" value for the text will work
310 * for the pix. If the pix is not colormapped and the
311 * value is out of range, set it to mid-range. */
312 pixGetDimensions(pixs, &w, &h, &d);
313 cmap = pixGetColormap(pixs);
314 if (d == 1 && val > 1)
315 val = 1;
316 else if (d == 2 && val > 3 && !cmap)
317 val = 2;
318 else if (d == 4 && val > 15 && !cmap)
319 val = 8;
320 else if (d == 8 && val > 0xff && !cmap)
321 val = 128;
322 else if (d == 16 && val > 0xffff)
323 val = 0x8000;
324 else if (d == 32 && val < 256)
325 val = 0x80808000;
326
327 /* Get the text in each line */
328 sa = sarrayCreateLinesFromString(textstr, 0);
329 nlines = sarrayGetCount(sa);
330
331 /* Get the necessary text size */
332 wtext = 0;
333 for (i = 0; i < nlines; i++) {
334 str = sarrayGetString(sa, i, L_NOCOPY);
335 bmfGetStringWidth(bmf, str, &wline);
336 if (wline > wtext)
337 wtext = wline;
338 }
339 hbaseline = bmf->baselinetab[93];
340 htext = 1.5 * hbaseline * nlines;
341
342 /* Add white border */
343 spacer = 10; /* pixels away from the added border */
344 if (location == L_ADD_ABOVE || location == L_ADD_BELOW) {
345 hadd = htext + 2 * spacer;
346 pixd = pixCreate(w, h + hadd, d);
347 pixCopyColormap(pixd, pixs);
348 pixCopyResolution(pixd, pixs);
349 pixCopyText(pixd, pixs);
351 if (location == L_ADD_ABOVE)
352 pixRasterop(pixd, 0, hadd, w, h, PIX_SRC, pixs, 0, 0);
353 else /* add below */
354 pixRasterop(pixd, 0, 0, w, h, PIX_SRC, pixs, 0, 0);
355 } else { /* L_ADD_LEFT or L_ADD_RIGHT */
356 wadd = wtext + 2 * spacer;
357 pixd = pixCreate(w + wadd, h, d);
358 pixCopyColormap(pixd, pixs);
359 pixCopyResolution(pixd, pixs);
360 pixCopyText(pixd, pixs);
362 if (location == L_ADD_LEFT)
363 pixRasterop(pixd, wadd, 0, w, h, PIX_SRC, pixs, 0, 0);
364 else /* add to right */
365 pixRasterop(pixd, 0, 0, w, h, PIX_SRC, pixs, 0, 0);
366 }
367
368 /* If cmapped, add the color if necessary to the cmap. If the
369 * cmap is full, use the nearest color to the requested color. */
370 cmapd = pixGetColormap(pixd);
371 if (cmapd) {
372 extractRGBValues(val, &rval, &gval, &bval);
373 pixcmapAddNearestColor(cmapd, rval, gval, bval, &index);
374 pixcmapGetColor(cmapd, index, &rval, &gval, &bval);
375 composeRGBPixel(rval, gval, bval, &textcolor);
376 } else {
377 textcolor = val;
378 }
379
380 /* Add the text */
381 for (i = 0; i < nlines; i++) {
382 str = sarrayGetString(sa, i, L_NOCOPY);
383 bmfGetStringWidth(bmf, str, &wtext);
384 if (location == L_ADD_ABOVE)
385 pixSetTextline(pixd, bmf, str, textcolor,
386 (w - wtext) / 2, spacer + hbaseline * (1 + 1.5 * i),
387 NULL, NULL);
388 else if (location == L_ADD_BELOW)
389 pixSetTextline(pixd, bmf, str, textcolor,
390 (w - wtext) / 2, h + spacer +
391 hbaseline * (1 + 1.5 * i), NULL, NULL);
392 else if (location == L_ADD_LEFT)
393 pixSetTextline(pixd, bmf, str, textcolor,
394 spacer, (h - htext) / 2 + hbaseline * (1 + 1.5 * i),
395 NULL, NULL);
396 else /* location == L_ADD_RIGHT */
397 pixSetTextline(pixd, bmf, str, textcolor,
398 w + spacer, (h - htext) / 2 +
399 hbaseline * (1 + 1.5 * i), NULL, NULL);
400 }
401
402 sarrayDestroy(&sa);
403 return pixd;
404}
405
406
438l_ok
440 L_BMF *bmf,
441 const char *textstr,
442 l_uint32 val,
443 l_int32 x0,
444 l_int32 y0,
445 l_int32 wtext,
446 l_int32 firstindent,
447 l_int32 *poverflow)
448{
449char *linestr;
450l_int32 d, h, i, w, x, y, nlines, htext, xwidth, wline, ovf, overflow;
451SARRAY *salines;
452PIXCMAP *cmap;
453
454 PROCNAME("pixSetTextblock");
455
456 if (!pixs)
457 return ERROR_INT("pixs not defined", procName, 1);
458 if (!bmf)
459 return ERROR_INT("bmf not defined", procName, 1);
460 if (!textstr)
461 return ERROR_INT("textstr not defined", procName, 1);
462
463 /* Make sure the "color" value for the text will work
464 * for the pix. If the pix is not colormapped and the
465 * value is out of range, set it to mid-range. */
466 pixGetDimensions(pixs, &w, &h, &d);
467 cmap = pixGetColormap(pixs);
468 if (d == 1 && val > 1)
469 val = 1;
470 else if (d == 2 && val > 3 && !cmap)
471 val = 2;
472 else if (d == 4 && val > 15 && !cmap)
473 val = 8;
474 else if (d == 8 && val > 0xff && !cmap)
475 val = 128;
476 else if (d == 16 && val > 0xffff)
477 val = 0x8000;
478 else if (d == 32 && val < 256)
479 val = 0x80808000;
480
481 if (w < x0 + wtext) {
482 L_WARNING("reducing width of textblock\n", procName);
483 wtext = w - x0 - w / 10;
484 if (wtext <= 0)
485 return ERROR_INT("wtext too small; no room for text", procName, 1);
486 }
487
488 salines = bmfGetLineStrings(bmf, textstr, wtext, firstindent, &htext);
489 if (!salines)
490 return ERROR_INT("line string sa not made", procName, 1);
491 nlines = sarrayGetCount(salines);
492 bmfGetWidth(bmf, 'x', &xwidth);
493
494 y = y0;
495 overflow = 0;
496 for (i = 0; i < nlines; i++) {
497 if (i == 0)
498 x = x0 + firstindent * xwidth;
499 else
500 x = x0;
501 linestr = sarrayGetString(salines, i, L_NOCOPY);
502 pixSetTextline(pixs, bmf, linestr, val, x, y, &wline, &ovf);
503 y += bmf->lineheight + bmf->vertlinesep;
504 if (ovf)
505 overflow = 1;
506 }
507
508 /* (y0 - baseline) is the top of the printed text. Character
509 * 93 was chosen at random, as all the baselines are essentially
510 * equal for each character in a font. */
511 if (h < y0 - bmf->baselinetab[93] + htext)
512 overflow = 1;
513 if (poverflow)
514 *poverflow = overflow;
515
516 sarrayDestroy(&salines);
517 return 0;
518}
519
520
551l_ok
553 L_BMF *bmf,
554 const char *textstr,
555 l_uint32 val,
556 l_int32 x0,
557 l_int32 y0,
558 l_int32 *pwidth,
559 l_int32 *poverflow)
560{
561char chr;
562l_int32 d, i, x, w, nchar, baseline, index, rval, gval, bval;
563l_uint32 textcolor;
564PIX *pix;
565PIXCMAP *cmap;
566
567 PROCNAME("pixSetTextline");
568
569 if (!pixs)
570 return ERROR_INT("pixs not defined", procName, 1);
571 if (!bmf)
572 return ERROR_INT("bmf not defined", procName, 1);
573 if (!textstr)
574 return ERROR_INT("teststr not defined", procName, 1);
575
576 d = pixGetDepth(pixs);
577 cmap = pixGetColormap(pixs);
578 if (d == 1 && val > 1)
579 val = 1;
580 else if (d == 2 && val > 3 && !cmap)
581 val = 2;
582 else if (d == 4 && val > 15 && !cmap)
583 val = 8;
584 else if (d == 8 && val > 0xff && !cmap)
585 val = 128;
586 else if (d == 16 && val > 0xffff)
587 val = 0x8000;
588 else if (d == 32 && val < 256)
589 val = 0x80808000;
590
591 /* If cmapped, add the color if necessary to the cmap. If the
592 * cmap is full, use the nearest color to the requested color. */
593 if (cmap) {
594 extractRGBValues(val, &rval, &gval, &bval);
595 pixcmapAddNearestColor(cmap, rval, gval, bval, &index);
596 pixcmapGetColor(cmap, index, &rval, &gval, &bval);
597 composeRGBPixel(rval, gval, bval, &textcolor);
598 } else
599 textcolor = val;
600
601 nchar = strlen(textstr);
602 x = x0;
603 for (i = 0; i < nchar; i++) {
604 chr = textstr[i];
605 if ((l_int32)chr == 10) continue; /* NL */
606 pix = bmfGetPix(bmf, chr);
607 bmfGetBaseline(bmf, chr, &baseline);
608 pixPaintThroughMask(pixs, pix, x, y0 - baseline, textcolor);
609 w = pixGetWidth(pix);
610 x += w + bmf->kernwidth;
611 pixDestroy(&pix);
612 }
613
614 if (pwidth)
615 *pwidth = x - bmf->kernwidth - x0;
616 if (poverflow)
617 *poverflow = (x > pixGetWidth(pixs) - 1) ? 1 : 0;
618 return 0;
619}
620
621
648PIXA *
650 L_BMF *bmf,
651 NUMA *na,
652 l_uint32 val,
653 l_int32 location)
654{
655char textstr[128];
656l_int32 i, n, index;
657PIX *pix1, *pix2;
658PIXA *pixad;
659
660 PROCNAME("pixaAddTextNumber");
661
662 if (!pixas)
663 return (PIXA *)ERROR_PTR("pixas not defined", procName, NULL);
664 if (!bmf)
665 return (PIXA *)ERROR_PTR("bmf not defined", procName, NULL);
666 if (location != L_ADD_ABOVE && location != L_ADD_BELOW &&
667 location != L_ADD_LEFT && location != L_ADD_RIGHT)
668 return (PIXA *)ERROR_PTR("invalid location", procName, NULL);
669
670 n = pixaGetCount(pixas);
671 pixad = pixaCreate(n);
672 for (i = 0; i < n; i++) {
673 pix1 = pixaGetPix(pixas, i, L_CLONE);
674 if (na)
675 numaGetIValue(na, i, &index);
676 else
677 index = i + 1;
678 snprintf(textstr, sizeof(textstr), "%d", index);
679 pix2 = pixAddTextlines(pix1, bmf, textstr, val, location);
680 pixaAddPix(pixad, pix2, L_INSERT);
681 pixDestroy(&pix1);
682 }
683
684 return pixad;
685}
686
687
718PIXA *
720 L_BMF *bmf,
721 SARRAY *sa,
722 l_uint32 val,
723 l_int32 location)
724{
725char *textstr;
726l_int32 i, n, nstr;
727PIX *pix1, *pix2;
728PIXA *pixad;
729
730 PROCNAME("pixaAddTextlines");
731
732 if (!pixas)
733 return (PIXA *)ERROR_PTR("pixas not defined", procName, NULL);
734 if (!bmf)
735 return (PIXA *)ERROR_PTR("bmf not defined", procName, NULL);
736 if (location != L_ADD_ABOVE && location != L_ADD_BELOW &&
737 location != L_ADD_LEFT && location != L_ADD_RIGHT)
738 return (PIXA *)ERROR_PTR("invalid location", procName, NULL);
739
740 n = pixaGetCount(pixas);
741 pixad = pixaCreate(n);
742 nstr = (sa) ? sarrayGetCount(sa) : 0;
743 if (nstr > 0 && nstr < n)
744 L_WARNING("There are %d strings and %d pix\n", procName, nstr, n);
745 for (i = 0; i < n; i++) {
746 pix1 = pixaGetPix(pixas, i, L_CLONE);
747 if (i < nstr)
748 textstr = sarrayGetString(sa, i, L_NOCOPY);
749 else
750 textstr = pixGetText(pix1);
751 pix2 = pixAddTextlines(pix1, bmf, textstr, val, location);
752 pixaAddPix(pixad, pix2, L_INSERT);
753 pixDestroy(&pix1);
754 }
755
756 return pixad;
757}
758
759
788l_ok
790 PIX *pixs,
791 l_int32 reduction,
792 L_BMF *bmf,
793 const char *textstr,
794 l_uint32 val,
795 l_int32 location)
796{
797l_int32 d;
798L_BMF *bmf8;
799PIX *pix1, *pix2, *pix3;
800PIXCMAP *cmap;
801
802 PROCNAME("pixaAddPixWithText");
803
804 if (!pixa)
805 return ERROR_INT("pixa not defined", procName, 1);
806 if (!pixs)
807 return ERROR_INT("pixs not defined", procName, 1);
808 if (location != L_ADD_ABOVE && location != L_ADD_BELOW &&
809 location != L_ADD_LEFT && location != L_ADD_RIGHT)
810 return ERROR_INT("invalid location", procName, 1);
811
812 if (!textstr) {
813 textstr = pixGetText(pixs);
814 if (!textstr) {
815 L_WARNING("no textstring defined; inserting copy", procName);
816 pixaAddPix(pixa, pixs, L_COPY);
817 return 0;
818 }
819 }
820
821 /* Default font size is 8. */
822 bmf8 = (bmf) ? bmf : bmfCreate(NULL, 8);
823
824 if (reduction != 1)
825 pix1 = pixScaleByIntSampling(pixs, reduction);
826 else
827 pix1 = pixClone(pixs);
828
829 /* We want the text to be rendered in color. This works
830 * automatically if pixs is cmapped or 32 bpp rgb; otherwise,
831 * we need to convert to rgb. */
832 cmap = pixGetColormap(pix1);
833 d = pixGetDepth(pix1);
834 if (!cmap && d != 32)
835 pix2 = pixConvertTo32(pix1);
836 else
837 pix2 = pixClone(pix1);
838
839 pix3 = pixAddTextlines(pix2, bmf, textstr, val, location);
840 pixDestroy(&pix1);
841 pixDestroy(&pix2);
842 if (!bmf) bmfDestroy(&bmf8);
843 if (!pix3)
844 return ERROR_INT("pix3 not made", procName, 1);
845
846 pixaAddPix(pixa, pix3, L_INSERT);
847 return 0;
848}
849
850
851/*---------------------------------------------------------------------*
852 * Text size estimation and partitioning *
853 *---------------------------------------------------------------------*/
870SARRAY *
872 const char *textstr,
873 l_int32 maxw,
874 l_int32 firstindent,
875 l_int32 *ph)
876{
877char *linestr;
878l_int32 i, ifirst, sumw, newsum, w, nwords, nlines, len, xwidth;
879NUMA *na;
880SARRAY *sa, *sawords;
881
882 PROCNAME("bmfGetLineStrings");
883
884 if (!bmf)
885 return (SARRAY *)ERROR_PTR("bmf not defined", procName, NULL);
886 if (!textstr)
887 return (SARRAY *)ERROR_PTR("teststr not defined", procName, NULL);
888
889 if ((sawords = sarrayCreateWordsFromString(textstr)) == NULL)
890 return (SARRAY *)ERROR_PTR("sawords not made", procName, NULL);
891
892 if ((na = bmfGetWordWidths(bmf, textstr, sawords)) == NULL) {
893 sarrayDestroy(&sawords);
894 return (SARRAY *)ERROR_PTR("na not made", procName, NULL);
895 }
896 nwords = numaGetCount(na);
897 if (nwords == 0) {
898 sarrayDestroy(&sawords);
899 numaDestroy(&na);
900 return (SARRAY *)ERROR_PTR("no words in textstr", procName, NULL);
901 }
902 bmfGetWidth(bmf, 'x', &xwidth);
903
904 sa = sarrayCreate(0);
905 ifirst = 0;
906 numaGetIValue(na, 0, &w);
907 sumw = firstindent * xwidth + w;
908 for (i = 1; i < nwords; i++) {
909 numaGetIValue(na, i, &w);
910 newsum = sumw + bmf->spacewidth + w;
911 if (newsum > maxw) {
912 linestr = sarrayToStringRange(sawords, ifirst, i - ifirst, 2);
913 if (!linestr)
914 continue;
915 len = strlen(linestr);
916 if (len > 0) /* it should always be */
917 linestr[len - 1] = '\0'; /* remove the last space */
918 sarrayAddString(sa, linestr, L_INSERT);
919 ifirst = i;
920 sumw = w;
921 }
922 else
923 sumw += bmf->spacewidth + w;
924 }
925 linestr = sarrayToStringRange(sawords, ifirst, nwords - ifirst, 2);
926 if (linestr)
927 sarrayAddString(sa, linestr, L_INSERT);
928 nlines = sarrayGetCount(sa);
929 *ph = nlines * bmf->lineheight + (nlines - 1) * bmf->vertlinesep;
930
931 sarrayDestroy(&sawords);
932 numaDestroy(&na);
933 return sa;
934}
935
936
946NUMA *
948 const char *textstr,
949 SARRAY *sa)
950{
951char *wordstr;
952l_int32 i, nwords, width;
953NUMA *na;
954
955 PROCNAME("bmfGetWordWidths");
956
957 if (!bmf)
958 return (NUMA *)ERROR_PTR("bmf not defined", procName, NULL);
959 if (!textstr)
960 return (NUMA *)ERROR_PTR("teststr not defined", procName, NULL);
961 if (!sa)
962 return (NUMA *)ERROR_PTR("sa not defined", procName, NULL);
963
964 nwords = sarrayGetCount(sa);
965 if ((na = numaCreate(nwords)) == NULL)
966 return (NUMA *)ERROR_PTR("na not made", procName, NULL);
967
968 for (i = 0; i < nwords; i++) {
969 wordstr = sarrayGetString(sa, i, L_NOCOPY);
970 bmfGetStringWidth(bmf, wordstr, &width);
971 numaAddNumber(na, width);
972 }
973
974 return na;
975}
976
977
987l_ok
989 const char *textstr,
990 l_int32 *pw)
991{
992char chr;
993l_int32 i, w, width, nchar;
994
995 PROCNAME("bmfGetStringWidth");
996
997 if (!bmf)
998 return ERROR_INT("bmf not defined", procName, 1);
999 if (!textstr)
1000 return ERROR_INT("teststr not defined", procName, 1);
1001 if (!pw)
1002 return ERROR_INT("&w not defined", procName, 1);
1003
1004 nchar = strlen(textstr);
1005 w = 0;
1006 for (i = 0; i < nchar; i++) {
1007 chr = textstr[i];
1008 bmfGetWidth(bmf, chr, &width);
1009 if (width != UNDEF)
1010 w += width + bmf->kernwidth;
1011 }
1012 w -= bmf->kernwidth; /* remove last one */
1013
1014 *pw = w;
1015 return 0;
1016}
1017
1018
1019
1020/*---------------------------------------------------------------------*
1021 * Text splitting *
1022 *---------------------------------------------------------------------*/
1031SARRAY *
1033 l_int32 splitflag)
1034{
1035char *linestr, *parastring;
1036l_int32 nlines, i, allwhite, leadwhite;
1037SARRAY *salines, *satemp, *saout;
1038
1039 PROCNAME("splitStringToParagraphs");
1040
1041 if (!textstr)
1042 return (SARRAY *)ERROR_PTR("textstr not defined", procName, NULL);
1043
1044 if ((salines = sarrayCreateLinesFromString(textstr, 1)) == NULL)
1045 return (SARRAY *)ERROR_PTR("salines not made", procName, NULL);
1046 nlines = sarrayGetCount(salines);
1047 saout = sarrayCreate(0);
1048 satemp = sarrayCreate(0);
1049
1050 linestr = sarrayGetString(salines, 0, L_NOCOPY);
1051 sarrayAddString(satemp, linestr, L_COPY);
1052 for (i = 1; i < nlines; i++) {
1053 linestr = sarrayGetString(salines, i, L_NOCOPY);
1054 stringAllWhitespace(linestr, &allwhite);
1055 stringLeadingWhitespace(linestr, &leadwhite);
1056 if ((splitflag == SPLIT_ON_LEADING_WHITE && leadwhite) ||
1057 (splitflag == SPLIT_ON_BLANK_LINE && allwhite) ||
1058 (splitflag == SPLIT_ON_BOTH && (allwhite || leadwhite))) {
1059 parastring = sarrayToString(satemp, 1); /* add nl to each line */
1060 sarrayAddString(saout, parastring, L_INSERT);
1061 sarrayDestroy(&satemp);
1062 satemp = sarrayCreate(0);
1063 }
1064 sarrayAddString(satemp, linestr, L_COPY);
1065 }
1066 parastring = sarrayToString(satemp, 1); /* add nl to each line */
1067 sarrayAddString(saout, parastring, L_INSERT);
1068 sarrayDestroy(&satemp);
1069 sarrayDestroy(&salines);
1070 return saout;
1071}
1072
1073
1081static l_int32
1083 l_int32 *pval)
1084{
1085l_int32 len, i;
1086
1087 PROCNAME("stringAllWhitespace");
1088
1089 if (!textstr)
1090 return ERROR_INT("textstr not defined", procName, 1);
1091 if (!pval)
1092 return ERROR_INT("&va not defined", procName, 1);
1093
1094 len = strlen(textstr);
1095 *pval = 1;
1096 for (i = 0; i < len; i++) {
1097 if (textstr[i] != ' ' && textstr[i] != '\t' && textstr[i] != '\n') {
1098 *pval = 0;
1099 return 0;
1100 }
1101 }
1102 return 0;
1103}
1104
1105
1113static l_int32
1115 l_int32 *pval)
1116{
1117 PROCNAME("stringLeadingWhitespace");
1118
1119 if (!textstr)
1120 return ERROR_INT("textstr not defined", procName, 1);
1121 if (!pval)
1122 return ERROR_INT("&va not defined", procName, 1);
1123
1124 *pval = 0;
1125 if (textstr[0] == ' ' || textstr[0] == '\t')
1126 *pval = 1;
1127
1128 return 0;
1129}
void bmfDestroy(L_BMF **pbmf)
bmfDestroy()
Definition: bmf.c:169
L_BMF * bmfCreate(const char *dir, l_int32 fontsize)
bmfCreate()
Definition: bmf.c:117
l_ok bmfGetBaseline(L_BMF *bmf, char chr, l_int32 *pbaseline)
bmfGetBaseline()
Definition: bmf.c:278
l_ok bmfGetWidth(L_BMF *bmf, char chr, l_int32 *pw)
bmfGetWidth()
Definition: bmf.c:239
PIX * bmfGetPix(L_BMF *bmf, char chr)
bmfGetPix()
Definition: bmf.c:204
@ SPLIT_ON_BOTH
Definition: bmf.h:41
@ SPLIT_ON_LEADING_WHITE
Definition: bmf.h:39
@ SPLIT_ON_BLANK_LINE
Definition: bmf.h:40
l_ok pixcmapAddNearestColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 *pindex)
pixcmapAddNearestColor()
Definition: colormap.c:545
l_ok pixcmapGetColor(PIXCMAP *cmap, l_int32 index, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
pixcmapGetColor()
Definition: colormap.c:824
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:478
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:366
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:658
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:754
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:194
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:621
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1113
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:593
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:315
l_ok pixCopyColormap(PIX *pixd, const PIX *pixs)
pixCopyColormap()
Definition: pix1.c:816
PIX * pixCopy(PIX *pixd, const PIX *pixs)
pixCopy()
Definition: pix1.c:705
char * pixGetText(PIX *pix)
pixGetText()
Definition: pix1.c:1512
l_ok composeRGBPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 *ppixel)
composeRGBPixel()
Definition: pix2.c:2751
void extractRGBValues(l_uint32 pixel, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
extractRGBValues()
Definition: pix2.c:2820
l_ok pixSetBlackOrWhite(PIX *pixs, l_int32 op)
pixSetBlackOrWhite()
Definition: pix2.c:1021
l_ok pixPaintThroughMask(PIX *pixd, PIX *pixm, l_int32 x, l_int32 y, l_uint32 val)
pixPaintThroughMask()
Definition: pix3.c:626
@ L_ADD_AT_BOT
Definition: pix.h:1214
@ L_ADD_LEFT
Definition: pix.h:1211
@ L_ADD_BELOW
Definition: pix.h:1210
@ L_ADD_AT_TOP
Definition: pix.h:1213
@ L_ADD_ABOVE
Definition: pix.h:1209
@ L_ADD_RIGHT
Definition: pix.h:1212
@ L_COPY
Definition: pix.h:712
@ L_CLONE
Definition: pix.h:713
@ L_NOCOPY
Definition: pix.h:710
@ L_INSERT
Definition: pix.h:711
#define PIX_SRC
Definition: pix.h:330
@ L_BRING_IN_WHITE
Definition: pix.h:869
l_ok pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:506
PIXA * pixaCreate(l_int32 n)
pixaCreate()
Definition: pixabasic.c:167
l_int32 pixaGetCount(PIXA *pixa)
pixaGetCount()
Definition: pixabasic.c:650
PIX * pixaGetPix(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetPix()
Definition: pixabasic.c:691
PIX * pixConvertTo32(PIX *pixs)
pixConvertTo32()
Definition: pixconv.c:3332
l_ok pixRasterop(PIX *pixd, l_int32 dx, l_int32 dy, l_int32 dw, l_int32 dh, l_int32 op, PIX *pixs, l_int32 sx, l_int32 sy)
pixRasterop()
Definition: rop.c:204
SARRAY * sarrayCreate(l_int32 n)
sarrayCreate()
Definition: sarray1.c:170
char * sarrayToStringRange(SARRAY *sa, l_int32 first, l_int32 nstrings, l_int32 addnlflag)
sarrayToStringRange()
Definition: sarray1.c:820
char * sarrayToString(SARRAY *sa, l_int32 addnlflag)
sarrayToString()
Definition: sarray1.c:785
char * sarrayGetString(SARRAY *sa, l_int32 index, l_int32 copyflag)
sarrayGetString()
Definition: sarray1.c:703
l_int32 sarrayGetCount(SARRAY *sa)
sarrayGetCount()
Definition: sarray1.c:643
void sarrayDestroy(SARRAY **psa)
sarrayDestroy()
Definition: sarray1.c:362
SARRAY * sarrayCreateLinesFromString(const char *string, l_int32 blankflag)
sarrayCreateLinesFromString()
Definition: sarray1.c:283
l_ok sarrayAddString(SARRAY *sa, const char *string, l_int32 copyflag)
sarrayAddString()
Definition: sarray1.c:451
SARRAY * sarrayCreateWordsFromString(const char *string)
sarrayCreateWordsFromString()
Definition: sarray1.c:233
PIX * pixScaleByIntSampling(PIX *pixs, l_int32 factor)
pixScaleByIntSampling()
Definition: scale1.c:1444
Definition: bmf.h:47
l_int32 * baselinetab
Definition: bmf.h:59
l_int32 spacewidth
Definition: bmf.h:56
l_int32 vertlinesep
Definition: bmf.h:57
l_int32 kernwidth
Definition: bmf.h:55
l_int32 lineheight
Definition: bmf.h:54
Definition: array.h:71
Definition: pix.h:139
Definition: pix.h:456
Definition: array.h:127
PIXA * pixaAddTextNumber(PIXA *pixas, L_BMF *bmf, NUMA *na, l_uint32 val, l_int32 location)
pixaAddTextNumber()
Definition: textops.c:649
l_ok pixSetTextblock(PIX *pixs, L_BMF *bmf, const char *textstr, l_uint32 val, l_int32 x0, l_int32 y0, l_int32 wtext, l_int32 firstindent, l_int32 *poverflow)
pixSetTextblock()
Definition: textops.c:439
PIX * pixAddTextlines(PIX *pixs, L_BMF *bmf, const char *textstr, l_uint32 val, l_int32 location)
pixAddTextlines()
Definition: textops.c:276
SARRAY * splitStringToParagraphs(char *textstr, l_int32 splitflag)
splitStringToParagraphs()
Definition: textops.c:1032
l_ok bmfGetStringWidth(L_BMF *bmf, const char *textstr, l_int32 *pw)
bmfGetStringWidth()
Definition: textops.c:988
PIX * pixAddSingleTextblock(PIX *pixs, L_BMF *bmf, const char *textstr, l_uint32 val, l_int32 location, l_int32 *poverflow)
pixAddSingleTextblock()
Definition: textops.c:120
l_ok pixSetTextline(PIX *pixs, L_BMF *bmf, const char *textstr, l_uint32 val, l_int32 x0, l_int32 y0, l_int32 *pwidth, l_int32 *poverflow)
pixSetTextline()
Definition: textops.c:552
NUMA * bmfGetWordWidths(L_BMF *bmf, const char *textstr, SARRAY *sa)
bmfGetWordWidths()
Definition: textops.c:947
l_ok pixaAddPixWithText(PIXA *pixa, PIX *pixs, l_int32 reduction, L_BMF *bmf, const char *textstr, l_uint32 val, l_int32 location)
pixaAddPixWithText()
Definition: textops.c:789
static l_int32 stringAllWhitespace(char *textstr, l_int32 *pval)
stringAllWhitespace()
Definition: textops.c:1082
SARRAY * bmfGetLineStrings(L_BMF *bmf, const char *textstr, l_int32 maxw, l_int32 firstindent, l_int32 *ph)
bmfGetLineStrings()
Definition: textops.c:871
PIXA * pixaAddTextlines(PIXA *pixas, L_BMF *bmf, SARRAY *sa, l_uint32 val, l_int32 location)
pixaAddTextlines()
Definition: textops.c:719
static l_int32 stringLeadingWhitespace(char *textstr, l_int32 *pval)
stringLeadingWhitespace()
Definition: textops.c:1114