Leptonica  1.83.1
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 
82 static l_int32 stringAllWhitespace(char *textstr, l_int32 *pval);
83 static l_int32 stringLeadingWhitespace(char *textstr, l_int32 *pval);
84 
85 
86 /*---------------------------------------------------------------------*
87  * Font layout *
88  *---------------------------------------------------------------------*/
119 PIX *
121  L_BMF *bmf,
122  const char *textstr,
123  l_uint32 val,
124  l_int32 location,
125  l_int32 *poverflow)
126 {
127 char *linestr;
128 l_int32 w, h, d, i, y, xstart, ystart, extra, spacer, rval, gval, bval;
129 l_int32 nlines, htext, ovf, overflow, offset, index;
130 l_uint32 textcolor;
131 PIX *pixd;
132 PIXCMAP *cmap, *cmapd;
133 SARRAY *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);
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 
273 PIX *
275  L_BMF *bmf,
276  const char *textstr,
277  l_uint32 val,
278  l_int32 location)
279 {
280 char *str;
281 l_int32 i, w, h, d, rval, gval, bval, index;
282 l_int32 wline, wtext, htext, wadd, hadd, spacer, hbaseline, nlines;
283 l_uint32 textcolor;
284 PIX *pixd;
285 PIXCMAP *cmap, *cmapd;
286 SARRAY *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);
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);
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 
434 l_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 {
445 char *linestr;
446 l_int32 d, h, i, w, x, y, nlines, htext, xwidth, wline, ovf, overflow;
447 SARRAY *salines;
448 PIXCMAP *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 
545 l_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 {
555 char chr;
556 l_int32 d, i, x, w, nchar, baseline, index, rval, gval, bval;
557 l_uint32 textcolor;
558 PIX *pix;
559 PIXCMAP *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 
640 PIXA *
642  L_BMF *bmf,
643  NUMA *na,
644  l_uint32 val,
645  l_int32 location)
646 {
647 char textstr[128];
648 l_int32 i, n, index;
649 PIX *pix1, *pix2;
650 PIXA *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 
708 PIXA *
710  L_BMF *bmf,
711  SARRAY *sa,
712  l_uint32 val,
713  l_int32 location)
714 {
715 char *textstr;
716 l_int32 i, n, nstr;
717 PIX *pix1, *pix2;
718 PIXA *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 
776 l_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 {
785 l_int32 d;
786 L_BMF *bmf8;
787 PIX *pix1, *pix2, *pix3;
788 PIXCMAP *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  *---------------------------------------------------------------------*/
856 SARRAY *
858  const char *textstr,
859  l_int32 maxw,
860  l_int32 firstindent,
861  l_int32 *ph)
862 {
863 char *linestr;
864 l_int32 i, ifirst, sumw, newsum, w, nwords, nlines, len, xwidth;
865 NUMA *na;
866 SARRAY *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 
930 NUMA *
932  const char *textstr,
933  SARRAY *sa)
934 {
935 char *wordstr;
936 l_int32 i, nwords, width;
937 NUMA *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 
969 l_ok
971  const char *textstr,
972  l_int32 *pw)
973 {
974 char chr;
975 l_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  *---------------------------------------------------------------------*/
1011 SARRAY *
1013  l_int32 splitflag)
1014 {
1015 char *linestr, *parastring;
1016 l_int32 nlines, i, allwhite, leadwhite;
1017 SARRAY *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 
1059 static l_int32
1060 stringAllWhitespace(char *textstr,
1061  l_int32 *pval)
1062 {
1063 l_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 
1089 static 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 }
void bmfDestroy(L_BMF **pbmf)
bmfDestroy()
Definition: bmf.c:168
PIX * bmfGetPix(L_BMF *bmf, char chr)
bmfGetPix()
Definition: bmf.c:201
L_BMF * bmfCreate(const char *dir, l_int32 fontsize)
bmfCreate()
Definition: bmf.c:118
l_ok bmfGetBaseline(L_BMF *bmf, char chr, l_int32 *pbaseline)
bmfGetBaseline()
Definition: bmf.c:271
l_ok bmfGetWidth(L_BMF *bmf, char chr, l_int32 *pw)
bmfGetWidth()
Definition: bmf.c:234
@ 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:528
l_ok pixcmapGetColor(PIXCMAP *cmap, l_int32 index, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
pixcmapGetColor()
Definition: colormap.c:789
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:460
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:193
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:357
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:630
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:720
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:608
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1074
char * pixGetText(PIX *pix)
pixGetText()
Definition: pix1.c:1408
PIX * pixCopy(PIX *pixd, const PIX *pixs)
pixCopy()
Definition: pix1.c:689
l_ok pixCopyColormap(PIX *pixd, const PIX *pixs)
pixCopyColormap()
Definition: pix1.c:795
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:315
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:582
l_ok composeRGBPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 *ppixel)
composeRGBPixel()
Definition: pix2.c:2728
void extractRGBValues(l_uint32 pixel, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
extractRGBValues()
Definition: pix2.c:2793
l_ok pixSetBlackOrWhite(PIX *pixs, l_int32 op)
pixSetBlackOrWhite()
Definition: pix2.c:997
l_ok pixPaintThroughMask(PIX *pixd, PIX *pixm, l_int32 x, l_int32 y, l_uint32 val)
pixPaintThroughMask()
Definition: pix3.c:618
@ 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
l_ok pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:493
PIXA * pixaCreate(l_int32 n)
pixaCreate()
Definition: pixabasic.c:167
l_int32 pixaGetCount(PIXA *pixa)
pixaGetCount()
Definition: pixabasic.c:629
PIX * pixaGetPix(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetPix()
Definition: pixabasic.c:647
PIX * pixConvertTo32(PIX *pixs)
pixConvertTo32()
Definition: pixconv.c:3246
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:169
char * sarrayGetString(SARRAY *sa, l_int32 index, l_int32 copyflag)
sarrayGetString()
Definition: sarray1.c:673
char * sarrayToStringRange(SARRAY *sa, l_int32 first, l_int32 nstrings, l_int32 addnlflag)
sarrayToStringRange()
Definition: sarray1.c:749
l_int32 sarrayGetCount(SARRAY *sa)
sarrayGetCount()
Definition: sarray1.c:617
void sarrayDestroy(SARRAY **psa)
sarrayDestroy()
Definition: sarray1.c:353
SARRAY * sarrayCreateWordsFromString(const char *string)
sarrayCreateWordsFromString()
Definition: sarray1.c:228
SARRAY * sarrayCreateLinesFromString(const char *string, l_int32 blankflag)
sarrayCreateLinesFromString()
Definition: sarray1.c:276
l_ok sarrayAddString(SARRAY *sa, const char *string, l_int32 copyflag)
sarrayAddString()
Definition: sarray1.c:435
char * sarrayToString(SARRAY *sa, l_int32 addnlflag)
sarrayToString()
Definition: sarray1.c:716
PIX * pixScaleByIntSampling(PIX *pixs, l_int32 factor)
pixScaleByIntSampling()
Definition: scale1.c:1408
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
NUMA * bmfGetWordWidths(L_BMF *bmf, const char *textstr, SARRAY *sa)
bmfGetWordWidths()
Definition: textops.c:931
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
SARRAY * bmfGetLineStrings(L_BMF *bmf, const char *textstr, l_int32 maxw, l_int32 firstindent, l_int32 *ph)
bmfGetLineStrings()
Definition: textops.c:857
SARRAY * splitStringToParagraphs(char *textstr, l_int32 splitflag)
splitStringToParagraphs()
Definition: textops.c:1012
PIX * pixAddTextlines(PIX *pixs, L_BMF *bmf, const char *textstr, l_uint32 val, l_int32 location)
pixAddTextlines()
Definition: textops.c:274
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 bmfGetStringWidth(L_BMF *bmf, const char *textstr, l_int32 *pw)
bmfGetStringWidth()
Definition: textops.c:970
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
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
PIXA * pixaAddTextlines(PIXA *pixas, L_BMF *bmf, SARRAY *sa, l_uint32 val, l_int32 location)
pixaAddTextlines()
Definition: textops.c:709
static l_int32 stringAllWhitespace(char *textstr, l_int32 *pval)
stringAllWhitespace()
Definition: textops.c:1060
PIXA * pixaAddTextNumber(PIXA *pixas, L_BMF *bmf, NUMA *na, l_uint32 val, l_int32 location)
pixaAddTextNumber()
Definition: textops.c:641
static l_int32 stringLeadingWhitespace(char *textstr, l_int32 *pval)
stringLeadingWhitespace()
Definition: textops.c:1090