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 
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  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 
275 PIX *
277  L_BMF *bmf,
278  const char *textstr,
279  l_uint32 val,
280  l_int32 location)
281 {
282 char *str;
283 l_int32 i, w, h, d, rval, gval, bval, index;
284 l_int32 wline, wtext, htext, wadd, hadd, spacer, hbaseline, nlines;
285 l_uint32 textcolor;
286 PIX *pixd;
287 PIXCMAP *cmap, *cmapd;
288 SARRAY *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 
438 l_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 {
449 char *linestr;
450 l_int32 d, h, i, w, x, y, nlines, htext, xwidth, wline, ovf, overflow;
451 SARRAY *salines;
452 PIXCMAP *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 
551 l_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 {
561 char chr;
562 l_int32 d, i, x, w, nchar, baseline, index, rval, gval, bval;
563 l_uint32 textcolor;
564 PIX *pix;
565 PIXCMAP *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 
648 PIXA *
650  L_BMF *bmf,
651  NUMA *na,
652  l_uint32 val,
653  l_int32 location)
654 {
655 char textstr[128];
656 l_int32 i, n, index;
657 PIX *pix1, *pix2;
658 PIXA *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 
718 PIXA *
720  L_BMF *bmf,
721  SARRAY *sa,
722  l_uint32 val,
723  l_int32 location)
724 {
725 char *textstr;
726 l_int32 i, n, nstr;
727 PIX *pix1, *pix2;
728 PIXA *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 
788 l_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 {
797 l_int32 d;
798 L_BMF *bmf8;
799 PIX *pix1, *pix2, *pix3;
800 PIXCMAP *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  *---------------------------------------------------------------------*/
870 SARRAY *
872  const char *textstr,
873  l_int32 maxw,
874  l_int32 firstindent,
875  l_int32 *ph)
876 {
877 char *linestr;
878 l_int32 i, ifirst, sumw, newsum, w, nwords, nlines, len, xwidth;
879 NUMA *na;
880 SARRAY *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 
946 NUMA *
948  const char *textstr,
949  SARRAY *sa)
950 {
951 char *wordstr;
952 l_int32 i, nwords, width;
953 NUMA *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 
987 l_ok
989  const char *textstr,
990  l_int32 *pw)
991 {
992 char chr;
993 l_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  *---------------------------------------------------------------------*/
1031 SARRAY *
1033  l_int32 splitflag)
1034 {
1035 char *linestr, *parastring;
1036 l_int32 nlines, i, allwhite, leadwhite;
1037 SARRAY *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 
1081 static l_int32
1082 stringAllWhitespace(char *textstr,
1083  l_int32 *pval)
1084 {
1085 l_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 
1113 static 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
char * sarrayToString(SARRAY *sa, l_int32 addnlflag)
sarrayToString()
Definition: sarray1.c:785
PIX * bmfGetPix(L_BMF *bmf, char chr)
bmfGetPix()
Definition: bmf.c:204
PIX * pixConvertTo32(PIX *pixs)
pixConvertTo32()
Definition: pixconv.c:3332
l_int32 lineheight
Definition: bmf.h:54
Definition: pix.h:713
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:478
PIXA * pixaCreate(l_int32 n)
pixaCreate()
Definition: pixabasic.c:167
l_int32 * baselinetab
Definition: bmf.h:59
Definition: pix.h:712
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
PIX * pixCopy(PIX *pixd, const PIX *pixs)
pixCopy()
Definition: pix1.c:705
Definition: pix.h:710
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 * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:315
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
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:194
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
l_ok bmfGetStringWidth(L_BMF *bmf, const char *textstr, l_int32 *pw)
bmfGetStringWidth()
Definition: textops.c:988
l_ok bmfGetWidth(L_BMF *bmf, char chr, l_int32 *pw)
bmfGetWidth()
Definition: bmf.c:239
Definition: bmf.h:46
Definition: array.h:126
l_ok pixPaintThroughMask(PIX *pixd, PIX *pixm, l_int32 x, l_int32 y, l_uint32 val)
pixPaintThroughMask()
Definition: pix3.c:626
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:754
l_ok pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:506
Definition: array.h:70
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:658
l_ok sarrayAddString(SARRAY *sa, const char *string, l_int32 copyflag)
sarrayAddString()
Definition: sarray1.c:451
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
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
l_ok pixcmapGetColor(PIXCMAP *cmap, l_int32 index, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
pixcmapGetColor()
Definition: colormap.c:824
l_ok pixSetBlackOrWhite(PIX *pixs, l_int32 op)
pixSetBlackOrWhite()
Definition: pix2.c:1021
char * sarrayGetString(SARRAY *sa, l_int32 index, l_int32 copyflag)
sarrayGetString()
Definition: sarray1.c:703
l_int32 kernwidth
Definition: bmf.h:55
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:593
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:621
l_ok pixcmapAddNearestColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 *pindex)
pixcmapAddNearestColor()
Definition: colormap.c:545
SARRAY * splitStringToParagraphs(char *textstr, l_int32 splitflag)
splitStringToParagraphs()
Definition: textops.c:1032
Definition: pix.h:711
PIX * pixScaleByIntSampling(PIX *pixs, l_int32 factor)
pixScaleByIntSampling()
Definition: scale1.c:1444
l_ok bmfGetBaseline(L_BMF *bmf, char chr, l_int32 *pbaseline)
bmfGetBaseline()
Definition: bmf.c:278
SARRAY * sarrayCreateLinesFromString(const char *string, l_int32 blankflag)
sarrayCreateLinesFromString()
Definition: sarray1.c:283
Definition: pix.h:455
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:366
l_int32 vertlinesep
Definition: bmf.h:57
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1113
static l_int32 stringAllWhitespace(char *textstr, l_int32 *pval)
stringAllWhitespace()
Definition: textops.c:1082
l_int32 sarrayGetCount(SARRAY *sa)
sarrayGetCount()
Definition: sarray1.c:643
char * pixGetText(PIX *pix)
pixGetText()
Definition: pix1.c:1512
PIX * pixaGetPix(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetPix()
Definition: pixabasic.c:691
Definition: pix.h:138
#define PIX_SRC
Definition: pix.h:330
l_ok pixCopyColormap(PIX *pixd, const PIX *pixs)
pixCopyColormap()
Definition: pix1.c:816
PIX * pixAddTextlines(PIX *pixs, L_BMF *bmf, const char *textstr, l_uint32 val, l_int32 location)
pixAddTextlines()
Definition: textops.c:276
l_ok composeRGBPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 *ppixel)
composeRGBPixel()
Definition: pix2.c:2751
NUMA * bmfGetWordWidths(L_BMF *bmf, const char *textstr, SARRAY *sa)
bmfGetWordWidths()
Definition: textops.c:947
SARRAY * bmfGetLineStrings(L_BMF *bmf, const char *textstr, l_int32 maxw, l_int32 firstindent, l_int32 *ph)
bmfGetLineStrings()
Definition: textops.c:871
PIX * pixAddSingleTextblock(PIX *pixs, L_BMF *bmf, const char *textstr, l_uint32 val, l_int32 location, l_int32 *poverflow)
pixAddSingleTextblock()
Definition: textops.c:120
void extractRGBValues(l_uint32 pixel, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
extractRGBValues()
Definition: pix2.c:2820
l_int32 spacewidth
Definition: bmf.h:56
l_int32 pixaGetCount(PIXA *pixa)
pixaGetCount()
Definition: pixabasic.c:650
SARRAY * sarrayCreateWordsFromString(const char *string)
sarrayCreateWordsFromString()
Definition: sarray1.c:233
PIXA * pixaAddTextNumber(PIXA *pixas, L_BMF *bmf, NUMA *na, l_uint32 val, l_int32 location)
pixaAddTextNumber()
Definition: textops.c:649
void sarrayDestroy(SARRAY **psa)
sarrayDestroy()
Definition: sarray1.c:362
L_BMF * bmfCreate(const char *dir, l_int32 fontsize)
bmfCreate()
Definition: bmf.c:117