Leptonica 1.85.0
Image processing and image analysis suite
Loading...
Searching...
No Matches
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 if (poverflow) *poverflow = 0;
136 if (!pixs)
137 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
138 if (location != L_ADD_ABOVE && location != L_ADD_AT_TOP &&
139 location != L_ADD_AT_BOT && location != L_ADD_BELOW)
140 return (PIX *)ERROR_PTR("invalid location", __func__, NULL);
141 if (!bmf) {
142 L_ERROR("no bitmap fonts; returning a copy\n", __func__);
143 return pixCopy(NULL, pixs);
144 }
145 if (!textstr)
146 textstr = pixGetText(pixs);
147 if (!textstr) {
148 L_WARNING("no textstring defined; returning a copy\n", __func__);
149 return pixCopy(NULL, pixs);
150 }
151
152 /* Make sure the "color" value for the text will work
153 * for the pix. If the pix is not colormapped and the
154 * value is out of range, set it to mid-range. */
155 pixGetDimensions(pixs, &w, &h, &d);
156 cmap = pixGetColormap(pixs);
157 if (d == 1 && val > 1)
158 val = 1;
159 else if (d == 2 && val > 3 && !cmap)
160 val = 2;
161 else if (d == 4 && val > 15 && !cmap)
162 val = 8;
163 else if (d == 8 && val > 0xff && !cmap)
164 val = 128;
165 else if (d == 16 && val > 0xffff)
166 val = 0x8000;
167 else if (d == 32 && val < 256)
168 val = 0x80808000;
169
170 xstart = (l_int32)(0.1 * w);
171 salines = bmfGetLineStrings(bmf, textstr, w - 2 * xstart, 0, &htext);
172 if (!salines)
173 return (PIX *)ERROR_PTR("line string sa not made", __func__, NULL);
174 nlines = sarrayGetCount(salines);
175
176 /* Add white border if required */
177 spacer = 10; /* pixels away from image boundary or added border */
178 if (location == L_ADD_ABOVE || location == L_ADD_BELOW) {
179 extra = htext + 2 * spacer;
180 pixd = pixCreate(w, h + extra, d);
181 pixCopyColormap(pixd, pixs);
182 pixCopyResolution(pixd, pixs);
183 pixCopyText(pixd, pixs);
184 pixSetBlackOrWhite(pixd, L_BRING_IN_WHITE);
185 if (location == L_ADD_ABOVE)
186 pixRasterop(pixd, 0, extra, w, h, PIX_SRC, pixs, 0, 0);
187 else /* add below */
188 pixRasterop(pixd, 0, 0, w, h, PIX_SRC, pixs, 0, 0);
189 } else {
190 pixd = pixCopy(NULL, pixs);
191 }
192 cmapd = pixGetColormap(pixd);
193
194 /* bmf->baselinetab[93] is the approximate distance from
195 * the top of the tallest character to the baseline. 93 was chosen
196 * at random, as all the baselines are essentially equal for
197 * each character in a font. */
198 offset = bmf->baselinetab[93];
199 if (location == L_ADD_ABOVE || location == L_ADD_AT_TOP)
200 ystart = offset + spacer;
201 else if (location == L_ADD_AT_BOT)
202 ystart = h - htext - spacer + offset;
203 else /* add below */
204 ystart = h + offset + spacer;
205
206 /* If cmapped, add the color if necessary to the cmap. If the
207 * cmap is full, use the nearest color to the requested color. */
208 if (cmapd) {
209 extractRGBValues(val, &rval, &gval, &bval);
210 pixcmapAddNearestColor(cmapd, rval, gval, bval, &index);
211 pixcmapGetColor(cmapd, index, &rval, &gval, &bval);
212 composeRGBPixel(rval, gval, bval, &textcolor);
213 } else {
214 textcolor = val;
215 }
216
217 /* Keep track of overflow condition on line width */
218 overflow = 0;
219 for (i = 0, y = ystart; i < nlines; i++) {
220 linestr = sarrayGetString(salines, i, L_NOCOPY);
221 pixSetTextline(pixd, bmf, linestr, textcolor,
222 xstart, y, NULL, &ovf);
223 y += bmf->lineheight + bmf->vertlinesep;
224 if (ovf)
225 overflow = 1;
226 }
227
228 /* Also consider vertical overflow where there is too much text to
229 * fit inside the image: the cases L_ADD_AT_TOP and L_ADD_AT_BOT.
230 * The text requires a total of htext + 2 * spacer vertical pixels. */
231 if (location == L_ADD_AT_TOP || location == L_ADD_AT_BOT) {
232 if (h < htext + 2 * spacer)
233 overflow = 1;
234 }
235 if (poverflow) *poverflow = overflow;
236
237 sarrayDestroy(&salines);
238 return pixd;
239}
240
241
273PIX *
275 L_BMF *bmf,
276 const char *textstr,
277 l_uint32 val,
278 l_int32 location)
279{
280char *str;
281l_int32 i, w, h, d, rval, gval, bval, index;
282l_int32 wline, wtext, htext, wadd, hadd, spacer, hbaseline, nlines;
283l_uint32 textcolor;
284PIX *pixd;
285PIXCMAP *cmap, *cmapd;
286SARRAY *sa;
287
288 if (!pixs)
289 return (PIX *)ERROR_PTR("pixs not defined", __func__, NULL);
290 if (location != L_ADD_ABOVE && location != L_ADD_BELOW &&
291 location != L_ADD_LEFT && location != L_ADD_RIGHT)
292 return (PIX *)ERROR_PTR("invalid location", __func__, NULL);
293 if (!bmf) {
294 L_ERROR("no bitmap fonts; returning a copy\n", __func__);
295 return pixCopy(NULL, pixs);
296 }
297 if (!textstr) {
298 textstr = pixGetText(pixs);
299 if (!textstr) {
300 L_WARNING("no textstring defined; returning a copy\n", __func__);
301 return pixCopy(NULL, pixs);
302 }
303 }
304
305 /* Make sure the "color" value for the text will work
306 * for the pix. If the pix is not colormapped and the
307 * value is out of range, set it to mid-range. */
308 pixGetDimensions(pixs, &w, &h, &d);
309 cmap = pixGetColormap(pixs);
310 if (d == 1 && val > 1)
311 val = 1;
312 else if (d == 2 && val > 3 && !cmap)
313 val = 2;
314 else if (d == 4 && val > 15 && !cmap)
315 val = 8;
316 else if (d == 8 && val > 0xff && !cmap)
317 val = 128;
318 else if (d == 16 && val > 0xffff)
319 val = 0x8000;
320 else if (d == 32 && val < 256)
321 val = 0x80808000;
322
323 /* Get the text in each line */
324 sa = sarrayCreateLinesFromString(textstr, 0);
325 nlines = sarrayGetCount(sa);
326
327 /* Get the necessary text size */
328 wtext = 0;
329 for (i = 0; i < nlines; i++) {
330 str = sarrayGetString(sa, i, L_NOCOPY);
331 bmfGetStringWidth(bmf, str, &wline);
332 if (wline > wtext)
333 wtext = wline;
334 }
335 hbaseline = bmf->baselinetab[93];
336 htext = 1.5 * hbaseline * nlines;
337
338 /* Add white border */
339 spacer = 10; /* pixels away from the added border */
340 if (location == L_ADD_ABOVE || location == L_ADD_BELOW) {
341 hadd = htext + 2 * spacer;
342 pixd = pixCreate(w, h + hadd, d);
343 pixCopyColormap(pixd, pixs);
344 pixCopyResolution(pixd, pixs);
345 pixCopyText(pixd, pixs);
346 pixSetBlackOrWhite(pixd, L_BRING_IN_WHITE);
347 if (location == L_ADD_ABOVE)
348 pixRasterop(pixd, 0, hadd, w, h, PIX_SRC, pixs, 0, 0);
349 else /* add below */
350 pixRasterop(pixd, 0, 0, w, h, PIX_SRC, pixs, 0, 0);
351 } else { /* L_ADD_LEFT or L_ADD_RIGHT */
352 wadd = wtext + 2 * spacer;
353 pixd = pixCreate(w + wadd, h, d);
354 pixCopyColormap(pixd, pixs);
355 pixCopyResolution(pixd, pixs);
356 pixCopyText(pixd, pixs);
357 pixSetBlackOrWhite(pixd, L_BRING_IN_WHITE);
358 if (location == L_ADD_LEFT)
359 pixRasterop(pixd, wadd, 0, w, h, PIX_SRC, pixs, 0, 0);
360 else /* add to right */
361 pixRasterop(pixd, 0, 0, w, h, PIX_SRC, pixs, 0, 0);
362 }
363
364 /* If cmapped, add the color if necessary to the cmap. If the
365 * cmap is full, use the nearest color to the requested color. */
366 cmapd = pixGetColormap(pixd);
367 if (cmapd) {
368 extractRGBValues(val, &rval, &gval, &bval);
369 pixcmapAddNearestColor(cmapd, rval, gval, bval, &index);
370 pixcmapGetColor(cmapd, index, &rval, &gval, &bval);
371 composeRGBPixel(rval, gval, bval, &textcolor);
372 } else {
373 textcolor = val;
374 }
375
376 /* Add the text */
377 for (i = 0; i < nlines; i++) {
378 str = sarrayGetString(sa, i, L_NOCOPY);
379 bmfGetStringWidth(bmf, str, &wtext);
380 if (location == L_ADD_ABOVE)
381 pixSetTextline(pixd, bmf, str, textcolor,
382 (w - wtext) / 2, spacer + hbaseline * (1 + 1.5 * i),
383 NULL, NULL);
384 else if (location == L_ADD_BELOW)
385 pixSetTextline(pixd, bmf, str, textcolor,
386 (w - wtext) / 2, h + spacer +
387 hbaseline * (1 + 1.5 * i), NULL, NULL);
388 else if (location == L_ADD_LEFT)
389 pixSetTextline(pixd, bmf, str, textcolor,
390 spacer, (h - htext) / 2 + hbaseline * (1 + 1.5 * i),
391 NULL, NULL);
392 else /* location == L_ADD_RIGHT */
393 pixSetTextline(pixd, bmf, str, textcolor,
394 w + spacer, (h - htext) / 2 +
395 hbaseline * (1 + 1.5 * i), NULL, NULL);
396 }
397
398 sarrayDestroy(&sa);
399 return pixd;
400}
401
402
434l_ok
436 L_BMF *bmf,
437 const char *textstr,
438 l_uint32 val,
439 l_int32 x0,
440 l_int32 y0,
441 l_int32 wtext,
442 l_int32 firstindent,
443 l_int32 *poverflow)
444{
445char *linestr;
446l_int32 d, h, i, w, x, y, nlines, htext, xwidth, wline, ovf, overflow;
447SARRAY *salines;
448PIXCMAP *cmap;
449
450 if (!pixs)
451 return ERROR_INT("pixs not defined", __func__, 1);
452 if (!bmf)
453 return ERROR_INT("bmf not defined", __func__, 1);
454 if (!textstr)
455 return ERROR_INT("textstr not defined", __func__, 1);
456
457 /* Make sure the "color" value for the text will work
458 * for the pix. If the pix is not colormapped and the
459 * value is out of range, set it to mid-range. */
460 pixGetDimensions(pixs, &w, &h, &d);
461 cmap = pixGetColormap(pixs);
462 if (d == 1 && val > 1)
463 val = 1;
464 else if (d == 2 && val > 3 && !cmap)
465 val = 2;
466 else if (d == 4 && val > 15 && !cmap)
467 val = 8;
468 else if (d == 8 && val > 0xff && !cmap)
469 val = 128;
470 else if (d == 16 && val > 0xffff)
471 val = 0x8000;
472 else if (d == 32 && val < 256)
473 val = 0x80808000;
474
475 if (w < x0 + wtext) {
476 L_WARNING("reducing width of textblock\n", __func__);
477 wtext = w - x0 - w / 10;
478 if (wtext <= 0)
479 return ERROR_INT("wtext too small; no room for text", __func__, 1);
480 }
481
482 salines = bmfGetLineStrings(bmf, textstr, wtext, firstindent, &htext);
483 if (!salines)
484 return ERROR_INT("line string sa not made", __func__, 1);
485 nlines = sarrayGetCount(salines);
486 bmfGetWidth(bmf, 'x', &xwidth);
487
488 y = y0;
489 overflow = 0;
490 for (i = 0; i < nlines; i++) {
491 if (i == 0)
492 x = x0 + firstindent * xwidth;
493 else
494 x = x0;
495 linestr = sarrayGetString(salines, i, L_NOCOPY);
496 pixSetTextline(pixs, bmf, linestr, val, x, y, &wline, &ovf);
497 y += bmf->lineheight + bmf->vertlinesep;
498 if (ovf)
499 overflow = 1;
500 }
501
502 /* (y0 - baseline) is the top of the printed text. Character
503 * 93 was chosen at random, as all the baselines are essentially
504 * equal for each character in a font. */
505 if (h < y0 - bmf->baselinetab[93] + htext)
506 overflow = 1;
507 if (poverflow)
508 *poverflow = overflow;
509
510 sarrayDestroy(&salines);
511 return 0;
512}
513
514
545l_ok
547 L_BMF *bmf,
548 const char *textstr,
549 l_uint32 val,
550 l_int32 x0,
551 l_int32 y0,
552 l_int32 *pwidth,
553 l_int32 *poverflow)
554{
555char chr;
556l_int32 d, i, x, w, nchar, baseline, index, rval, gval, bval;
557l_uint32 textcolor;
558PIX *pix;
559PIXCMAP *cmap;
560
561 if (!pixs)
562 return ERROR_INT("pixs not defined", __func__, 1);
563 if (!bmf)
564 return ERROR_INT("bmf not defined", __func__, 1);
565 if (!textstr)
566 return ERROR_INT("teststr not defined", __func__, 1);
567
568 d = pixGetDepth(pixs);
569 cmap = pixGetColormap(pixs);
570 if (d == 1 && val > 1)
571 val = 1;
572 else if (d == 2 && val > 3 && !cmap)
573 val = 2;
574 else if (d == 4 && val > 15 && !cmap)
575 val = 8;
576 else if (d == 8 && val > 0xff && !cmap)
577 val = 128;
578 else if (d == 16 && val > 0xffff)
579 val = 0x8000;
580 else if (d == 32 && val < 256)
581 val = 0x80808000;
582
583 /* If cmapped, add the color if necessary to the cmap. If the
584 * cmap is full, use the nearest color to the requested color. */
585 if (cmap) {
586 extractRGBValues(val, &rval, &gval, &bval);
587 pixcmapAddNearestColor(cmap, rval, gval, bval, &index);
588 pixcmapGetColor(cmap, index, &rval, &gval, &bval);
589 composeRGBPixel(rval, gval, bval, &textcolor);
590 } else
591 textcolor = val;
592
593 nchar = strlen(textstr);
594 x = x0;
595 for (i = 0; i < nchar; i++) {
596 chr = textstr[i];
597 if ((l_int32)chr == 10) continue; /* NL */
598 pix = bmfGetPix(bmf, chr);
599 bmfGetBaseline(bmf, chr, &baseline);
600 pixPaintThroughMask(pixs, pix, x, y0 - baseline, textcolor);
601 w = pixGetWidth(pix);
602 x += w + bmf->kernwidth;
603 pixDestroy(&pix);
604 }
605
606 if (pwidth)
607 *pwidth = x - bmf->kernwidth - x0;
608 if (poverflow)
609 *poverflow = (x > pixGetWidth(pixs) - 1) ? 1 : 0;
610 return 0;
611}
612
613
640PIXA *
642 L_BMF *bmf,
643 NUMA *na,
644 l_uint32 val,
645 l_int32 location)
646{
647char textstr[128];
648l_int32 i, n, index;
649PIX *pix1, *pix2;
650PIXA *pixad;
651
652 if (!pixas)
653 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
654 if (!bmf)
655 return (PIXA *)ERROR_PTR("bmf not defined", __func__, NULL);
656 if (location != L_ADD_ABOVE && location != L_ADD_BELOW &&
657 location != L_ADD_LEFT && location != L_ADD_RIGHT)
658 return (PIXA *)ERROR_PTR("invalid location", __func__, NULL);
659
660 n = pixaGetCount(pixas);
661 pixad = pixaCreate(n);
662 for (i = 0; i < n; i++) {
663 pix1 = pixaGetPix(pixas, i, L_CLONE);
664 if (na)
665 numaGetIValue(na, i, &index);
666 else
667 index = i + 1;
668 snprintf(textstr, sizeof(textstr), "%d", index);
669 pix2 = pixAddTextlines(pix1, bmf, textstr, val, location);
670 pixaAddPix(pixad, pix2, L_INSERT);
671 pixDestroy(&pix1);
672 }
673
674 return pixad;
675}
676
677
708PIXA *
710 L_BMF *bmf,
711 SARRAY *sa,
712 l_uint32 val,
713 l_int32 location)
714{
715char *textstr;
716l_int32 i, n, nstr;
717PIX *pix1, *pix2;
718PIXA *pixad;
719
720 if (!pixas)
721 return (PIXA *)ERROR_PTR("pixas not defined", __func__, NULL);
722 if (!bmf)
723 return (PIXA *)ERROR_PTR("bmf not defined", __func__, NULL);
724 if (location != L_ADD_ABOVE && location != L_ADD_BELOW &&
725 location != L_ADD_LEFT && location != L_ADD_RIGHT)
726 return (PIXA *)ERROR_PTR("invalid location", __func__, NULL);
727
728 n = pixaGetCount(pixas);
729 pixad = pixaCreate(n);
730 nstr = (sa) ? sarrayGetCount(sa) : 0;
731 if (nstr > 0 && nstr < n)
732 L_WARNING("There are %d strings and %d pix\n", __func__, nstr, n);
733 for (i = 0; i < n; i++) {
734 pix1 = pixaGetPix(pixas, i, L_CLONE);
735 if (i < nstr)
736 textstr = sarrayGetString(sa, i, L_NOCOPY);
737 else
738 textstr = pixGetText(pix1);
739 pix2 = pixAddTextlines(pix1, bmf, textstr, val, location);
740 pixaAddPix(pixad, pix2, L_INSERT);
741 pixDestroy(&pix1);
742 }
743
744 return pixad;
745}
746
747
776l_ok
778 PIX *pixs,
779 l_int32 reduction,
780 L_BMF *bmf,
781 const char *textstr,
782 l_uint32 val,
783 l_int32 location)
784{
785l_int32 d;
786L_BMF *bmf8;
787PIX *pix1, *pix2, *pix3;
788PIXCMAP *cmap;
789
790 if (!pixa)
791 return ERROR_INT("pixa not defined", __func__, 1);
792 if (!pixs)
793 return ERROR_INT("pixs not defined", __func__, 1);
794 if (location != L_ADD_ABOVE && location != L_ADD_BELOW &&
795 location != L_ADD_LEFT && location != L_ADD_RIGHT)
796 return ERROR_INT("invalid location", __func__, 1);
797
798 if (!textstr) {
799 textstr = pixGetText(pixs);
800 if (!textstr) {
801 L_WARNING("no textstring defined; inserting copy", __func__);
802 pixaAddPix(pixa, pixs, L_COPY);
803 return 0;
804 }
805 }
806
807 /* Default font size is 8. */
808 bmf8 = (bmf) ? bmf : bmfCreate(NULL, 8);
809
810 if (reduction != 1)
811 pix1 = pixScaleByIntSampling(pixs, reduction);
812 else
813 pix1 = pixClone(pixs);
814
815 /* We want the text to be rendered in color. This works
816 * automatically if pixs is cmapped or 32 bpp rgb; otherwise,
817 * we need to convert to rgb. */
818 cmap = pixGetColormap(pix1);
819 d = pixGetDepth(pix1);
820 if (!cmap && d != 32)
821 pix2 = pixConvertTo32(pix1);
822 else
823 pix2 = pixClone(pix1);
824
825 pix3 = pixAddTextlines(pix2, bmf, textstr, val, location);
826 pixDestroy(&pix1);
827 pixDestroy(&pix2);
828 if (!bmf) bmfDestroy(&bmf8);
829 if (!pix3)
830 return ERROR_INT("pix3 not made", __func__, 1);
831
832 pixaAddPix(pixa, pix3, L_INSERT);
833 return 0;
834}
835
836
837/*---------------------------------------------------------------------*
838 * Text size estimation and partitioning *
839 *---------------------------------------------------------------------*/
856SARRAY *
858 const char *textstr,
859 l_int32 maxw,
860 l_int32 firstindent,
861 l_int32 *ph)
862{
863char *linestr;
864l_int32 i, ifirst, sumw, newsum, w, nwords, nlines, len, xwidth;
865NUMA *na;
866SARRAY *sa, *sawords;
867
868 if (!bmf)
869 return (SARRAY *)ERROR_PTR("bmf not defined", __func__, NULL);
870 if (!textstr)
871 return (SARRAY *)ERROR_PTR("teststr not defined", __func__, NULL);
872
873 if ((sawords = sarrayCreateWordsFromString(textstr)) == NULL)
874 return (SARRAY *)ERROR_PTR("sawords not made", __func__, NULL);
875
876 if ((na = bmfGetWordWidths(bmf, textstr, sawords)) == NULL) {
877 sarrayDestroy(&sawords);
878 return (SARRAY *)ERROR_PTR("na not made", __func__, NULL);
879 }
880 nwords = numaGetCount(na);
881 if (nwords == 0) {
882 sarrayDestroy(&sawords);
883 numaDestroy(&na);
884 return (SARRAY *)ERROR_PTR("no words in textstr", __func__, NULL);
885 }
886 bmfGetWidth(bmf, 'x', &xwidth);
887
888 sa = sarrayCreate(0);
889 ifirst = 0;
890 numaGetIValue(na, 0, &w);
891 sumw = firstindent * xwidth + w;
892 for (i = 1; i < nwords; i++) {
893 numaGetIValue(na, i, &w);
894 newsum = sumw + bmf->spacewidth + w;
895 if (newsum > maxw) {
896 linestr = sarrayToStringRange(sawords, ifirst, i - ifirst, 2);
897 if (!linestr)
898 continue;
899 len = strlen(linestr);
900 if (len > 0) /* it should always be */
901 linestr[len - 1] = '\0'; /* remove the last space */
902 sarrayAddString(sa, linestr, L_INSERT);
903 ifirst = i;
904 sumw = w;
905 }
906 else
907 sumw += bmf->spacewidth + w;
908 }
909 linestr = sarrayToStringRange(sawords, ifirst, nwords - ifirst, 2);
910 if (linestr)
911 sarrayAddString(sa, linestr, L_INSERT);
912 nlines = sarrayGetCount(sa);
913 *ph = nlines * bmf->lineheight + (nlines - 1) * bmf->vertlinesep;
914
915 sarrayDestroy(&sawords);
916 numaDestroy(&na);
917 return sa;
918}
919
920
930NUMA *
932 const char *textstr,
933 SARRAY *sa)
934{
935char *wordstr;
936l_int32 i, nwords, width;
937NUMA *na;
938
939 if (!bmf)
940 return (NUMA *)ERROR_PTR("bmf not defined", __func__, NULL);
941 if (!textstr)
942 return (NUMA *)ERROR_PTR("teststr not defined", __func__, NULL);
943 if (!sa)
944 return (NUMA *)ERROR_PTR("sa not defined", __func__, NULL);
945
946 nwords = sarrayGetCount(sa);
947 if ((na = numaCreate(nwords)) == NULL)
948 return (NUMA *)ERROR_PTR("na not made", __func__, NULL);
949
950 for (i = 0; i < nwords; i++) {
951 wordstr = sarrayGetString(sa, i, L_NOCOPY);
952 bmfGetStringWidth(bmf, wordstr, &width);
953 numaAddNumber(na, width);
954 }
955
956 return na;
957}
958
959
969l_ok
971 const char *textstr,
972 l_int32 *pw)
973{
974char chr;
975l_int32 i, w, width, nchar;
976
977 if (!bmf)
978 return ERROR_INT("bmf not defined", __func__, 1);
979 if (!textstr)
980 return ERROR_INT("teststr not defined", __func__, 1);
981 if (!pw)
982 return ERROR_INT("&w not defined", __func__, 1);
983
984 nchar = strlen(textstr);
985 w = 0;
986 for (i = 0; i < nchar; i++) {
987 chr = textstr[i];
988 bmfGetWidth(bmf, chr, &width);
989 if (width != UNDEF)
990 w += width + bmf->kernwidth;
991 }
992 w -= bmf->kernwidth; /* remove last one */
993
994 *pw = w;
995 return 0;
996}
997
998
999
1000/*---------------------------------------------------------------------*
1001 * Text splitting *
1002 *---------------------------------------------------------------------*/
1011SARRAY *
1013 l_int32 splitflag)
1014{
1015char *linestr, *parastring;
1016l_int32 nlines, i, allwhite, leadwhite;
1017SARRAY *salines, *satemp, *saout;
1018
1019 if (!textstr)
1020 return (SARRAY *)ERROR_PTR("textstr not defined", __func__, NULL);
1021
1022 if ((salines = sarrayCreateLinesFromString(textstr, 1)) == NULL)
1023 return (SARRAY *)ERROR_PTR("salines not made", __func__, NULL);
1024 nlines = sarrayGetCount(salines);
1025 saout = sarrayCreate(0);
1026 satemp = sarrayCreate(0);
1027
1028 linestr = sarrayGetString(salines, 0, L_NOCOPY);
1029 sarrayAddString(satemp, linestr, L_COPY);
1030 for (i = 1; i < nlines; i++) {
1031 linestr = sarrayGetString(salines, i, L_NOCOPY);
1032 stringAllWhitespace(linestr, &allwhite);
1033 stringLeadingWhitespace(linestr, &leadwhite);
1034 if ((splitflag == SPLIT_ON_LEADING_WHITE && leadwhite) ||
1035 (splitflag == SPLIT_ON_BLANK_LINE && allwhite) ||
1036 (splitflag == SPLIT_ON_BOTH && (allwhite || leadwhite))) {
1037 parastring = sarrayToString(satemp, 1); /* add nl to each line */
1038 sarrayAddString(saout, parastring, L_INSERT);
1039 sarrayDestroy(&satemp);
1040 satemp = sarrayCreate(0);
1041 }
1042 sarrayAddString(satemp, linestr, L_COPY);
1043 }
1044 parastring = sarrayToString(satemp, 1); /* add nl to each line */
1045 sarrayAddString(saout, parastring, L_INSERT);
1046 sarrayDestroy(&satemp);
1047 sarrayDestroy(&salines);
1048 return saout;
1049}
1050
1051
1059static l_int32
1061 l_int32 *pval)
1062{
1063l_int32 len, i;
1064
1065 if (!textstr)
1066 return ERROR_INT("textstr not defined", __func__, 1);
1067 if (!pval)
1068 return ERROR_INT("&va not defined", __func__, 1);
1069
1070 len = strlen(textstr);
1071 *pval = 1;
1072 for (i = 0; i < len; i++) {
1073 if (textstr[i] != ' ' && textstr[i] != '\t' && textstr[i] != '\n') {
1074 *pval = 0;
1075 return 0;
1076 }
1077 }
1078 return 0;
1079}
1080
1081
1089static l_int32
1091 l_int32 *pval)
1092{
1093 if (!textstr)
1094 return ERROR_INT("textstr not defined", __func__, 1);
1095 if (!pval)
1096 return ERROR_INT("&va not defined", __func__, 1);
1097
1098 *pval = 0;
1099 if (textstr[0] == ' ' || textstr[0] == '\t')
1100 *pval = 1;
1101
1102 return 0;
1103}
@ SPLIT_ON_BOTH
Definition bmf.h:41
@ SPLIT_ON_LEADING_WHITE
Definition bmf.h:39
@ SPLIT_ON_BLANK_LINE
Definition bmf.h:40
@ L_ADD_AT_BOT
Definition pix.h:1007
@ L_ADD_LEFT
Definition pix.h:1004
@ L_ADD_BELOW
Definition pix.h:1003
@ L_ADD_AT_TOP
Definition pix.h:1006
@ L_ADD_ABOVE
Definition pix.h:1002
@ L_ADD_RIGHT
Definition pix.h:1005
@ L_COPY
Definition pix.h:505
@ L_CLONE
Definition pix.h:506
@ L_NOCOPY
Definition pix.h:503
@ L_INSERT
Definition pix.h:504
#define PIX_SRC
Definition pix.h:444
@ L_BRING_IN_WHITE
Definition pix.h:662
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
PIXA * pixaAddTextNumber(PIXA *pixas, L_BMF *bmf, NUMA *na, l_uint32 val, l_int32 location)
pixaAddTextNumber()
Definition textops.c:641
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:435
PIX * pixAddTextlines(PIX *pixs, L_BMF *bmf, const char *textstr, l_uint32 val, l_int32 location)
pixAddTextlines()
Definition textops.c:274
SARRAY * splitStringToParagraphs(char *textstr, l_int32 splitflag)
splitStringToParagraphs()
Definition textops.c:1012
l_ok bmfGetStringWidth(L_BMF *bmf, const char *textstr, l_int32 *pw)
bmfGetStringWidth()
Definition textops.c:970
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:546
NUMA * bmfGetWordWidths(L_BMF *bmf, const char *textstr, SARRAY *sa)
bmfGetWordWidths()
Definition textops.c:931
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:777
static l_int32 stringAllWhitespace(char *textstr, l_int32 *pval)
stringAllWhitespace()
Definition textops.c:1060
SARRAY * bmfGetLineStrings(L_BMF *bmf, const char *textstr, l_int32 maxw, l_int32 firstindent, l_int32 *ph)
bmfGetLineStrings()
Definition textops.c:857
PIXA * pixaAddTextlines(PIXA *pixas, L_BMF *bmf, SARRAY *sa, l_uint32 val, l_int32 location)
pixaAddTextlines()
Definition textops.c:709
static l_int32 stringLeadingWhitespace(char *textstr, l_int32 *pval)
stringLeadingWhitespace()
Definition textops.c:1090