Leptonica  1.77.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 #include <string.h>
76 #include "allheaders.h"
77 
78 static l_int32 stringAllWhitespace(char *textstr, l_int32 *pval);
79 static l_int32 stringLeadingWhitespace(char *textstr, l_int32 *pval);
80 
81 
82 /*---------------------------------------------------------------------*
83  * Font layout *
84  *---------------------------------------------------------------------*/
114 PIX *
116  L_BMF *bmf,
117  const char *textstr,
118  l_uint32 val,
119  l_int32 location,
120  l_int32 *poverflow)
121 {
122 char *linestr;
123 l_int32 w, h, d, i, y, xstart, ystart, extra, spacer, rval, gval, bval;
124 l_int32 nlines, htext, ovf, overflow, offset, index;
125 l_uint32 textcolor;
126 PIX *pixd;
127 PIXCMAP *cmap, *cmapd;
128 SARRAY *salines;
129 
130  PROCNAME("pixAddSingleTextblock");
131 
132  if (poverflow) *poverflow = 0;
133  if (!pixs)
134  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
135  if (location != L_ADD_ABOVE && location != L_ADD_AT_TOP &&
136  location != L_ADD_AT_BOT && location != L_ADD_BELOW)
137  return (PIX *)ERROR_PTR("invalid location", procName, NULL);
138  if (!bmf) {
139  L_ERROR("no bitmap fonts; returning a copy\n", procName);
140  return pixCopy(NULL, pixs);
141  }
142  if (!textstr)
143  textstr = pixGetText(pixs);
144  if (!textstr) {
145  L_WARNING("no textstring defined; returning a copy\n", procName);
146  return pixCopy(NULL, pixs);
147  }
148 
149  /* Make sure the "color" value for the text will work
150  * for the pix. If the pix is not colormapped and the
151  * value is out of range, set it to mid-range. */
152  pixGetDimensions(pixs, &w, &h, &d);
153  cmap = pixGetColormap(pixs);
154  if (d == 1 && val > 1)
155  val = 1;
156  else if (d == 2 && val > 3 && !cmap)
157  val = 2;
158  else if (d == 4 && val > 15 && !cmap)
159  val = 8;
160  else if (d == 8 && val > 0xff && !cmap)
161  val = 128;
162  else if (d == 16 && val > 0xffff)
163  val = 0x8000;
164  else if (d == 32 && val < 256)
165  val = 0x80808000;
166 
167  xstart = (l_int32)(0.1 * w);
168  salines = bmfGetLineStrings(bmf, textstr, w - 2 * xstart, 0, &htext);
169  if (!salines)
170  return (PIX *)ERROR_PTR("line string sa not made", procName, NULL);
171  nlines = sarrayGetCount(salines);
172 
173  /* Add white border if required */
174  spacer = 10; /* pixels away from image boundary or added border */
175  if (location == L_ADD_ABOVE || location == L_ADD_BELOW) {
176  extra = htext + 2 * spacer;
177  pixd = pixCreate(w, h + extra, d);
178  pixCopyColormap(pixd, pixs);
179  pixCopyResolution(pixd, pixs);
181  if (location == L_ADD_ABOVE)
182  pixRasterop(pixd, 0, extra, w, h, PIX_SRC, pixs, 0, 0);
183  else /* add below */
184  pixRasterop(pixd, 0, 0, w, h, PIX_SRC, pixs, 0, 0);
185  } else {
186  pixd = pixCopy(NULL, pixs);
187  }
188  cmapd = pixGetColormap(pixd);
189 
190  /* bmf->baselinetab[93] is the approximate distance from
191  * the top of the tallest character to the baseline. 93 was chosen
192  * at random, as all the baselines are essentially equal for
193  * each character in a font. */
194  offset = bmf->baselinetab[93];
195  if (location == L_ADD_ABOVE || location == L_ADD_AT_TOP)
196  ystart = offset + spacer;
197  else if (location == L_ADD_AT_BOT)
198  ystart = h - htext - spacer + offset;
199  else /* add below */
200  ystart = h + offset + spacer;
201 
202  /* If cmapped, add the color if necessary to the cmap. If the
203  * cmap is full, use the nearest color to the requested color. */
204  if (cmapd) {
205  extractRGBValues(val, &rval, &gval, &bval);
206  pixcmapAddNearestColor(cmapd, rval, gval, bval, &index);
207  pixcmapGetColor(cmapd, index, &rval, &gval, &bval);
208  composeRGBPixel(rval, gval, bval, &textcolor);
209  } else {
210  textcolor = val;
211  }
212 
213  /* Keep track of overflow condition on line width */
214  overflow = 0;
215  for (i = 0, y = ystart; i < nlines; i++) {
216  linestr = sarrayGetString(salines, i, L_NOCOPY);
217  pixSetTextline(pixd, bmf, linestr, textcolor,
218  xstart, y, NULL, &ovf);
219  y += bmf->lineheight + bmf->vertlinesep;
220  if (ovf)
221  overflow = 1;
222  }
223 
224  /* Also consider vertical overflow where there is too much text to
225  * fit inside the image: the cases L_ADD_AT_TOP and L_ADD_AT_BOT.
226  * The text requires a total of htext + 2 * spacer vertical pixels. */
227  if (location == L_ADD_AT_TOP || location == L_ADD_AT_BOT) {
228  if (h < htext + 2 * spacer)
229  overflow = 1;
230  }
231  if (poverflow) *poverflow = overflow;
232 
233  sarrayDestroy(&salines);
234  return pixd;
235 }
236 
237 
269 PIX *
271  L_BMF *bmf,
272  const char *textstr,
273  l_uint32 val,
274  l_int32 location)
275 {
276 char *str;
277 l_int32 i, w, h, d, rval, gval, bval, index;
278 l_int32 wline, wtext, htext, wadd, hadd, spacer, hbaseline, nlines;
279 l_uint32 textcolor;
280 PIX *pixd;
281 PIXCMAP *cmap, *cmapd;
282 SARRAY *sa;
283 
284  PROCNAME("pixAddTextlines");
285 
286  if (!pixs)
287  return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
288  if (location != L_ADD_ABOVE && location != L_ADD_BELOW &&
289  location != L_ADD_LEFT && location != L_ADD_RIGHT)
290  return (PIX *)ERROR_PTR("invalid location", procName, NULL);
291  if (!bmf) {
292  L_ERROR("no bitmap fonts; returning a copy\n", procName);
293  return pixCopy(NULL, pixs);
294  }
295  if (!textstr) {
296  textstr = pixGetText(pixs);
297  if (!textstr) {
298  L_WARNING("no textstring defined; returning a copy\n", procName);
299  return pixCopy(NULL, pixs);
300  }
301  }
302 
303  /* Make sure the "color" value for the text will work
304  * for the pix. If the pix is not colormapped and the
305  * value is out of range, set it to mid-range. */
306  pixGetDimensions(pixs, &w, &h, &d);
307  cmap = pixGetColormap(pixs);
308  if (d == 1 && val > 1)
309  val = 1;
310  else if (d == 2 && val > 3 && !cmap)
311  val = 2;
312  else if (d == 4 && val > 15 && !cmap)
313  val = 8;
314  else if (d == 8 && val > 0xff && !cmap)
315  val = 128;
316  else if (d == 16 && val > 0xffff)
317  val = 0x8000;
318  else if (d == 32 && val < 256)
319  val = 0x80808000;
320 
321  /* Get the text in each line */
322  sa = sarrayCreateLinesFromString(textstr, 0);
323  nlines = sarrayGetCount(sa);
324 
325  /* Get the necessary text size */
326  wtext = 0;
327  for (i = 0; i < nlines; i++) {
328  str = sarrayGetString(sa, i, L_NOCOPY);
329  bmfGetStringWidth(bmf, str, &wline);
330  if (wline > wtext)
331  wtext = wline;
332  }
333  hbaseline = bmf->baselinetab[93];
334  htext = 1.5 * hbaseline * nlines;
335 
336  /* Add white border */
337  spacer = 10; /* pixels away from the added border */
338  if (location == L_ADD_ABOVE || location == L_ADD_BELOW) {
339  hadd = htext + 2 * spacer;
340  pixd = pixCreate(w, h + hadd, d);
341  pixCopyColormap(pixd, pixs);
342  pixCopyResolution(pixd, pixs);
344  if (location == L_ADD_ABOVE)
345  pixRasterop(pixd, 0, hadd, w, h, PIX_SRC, pixs, 0, 0);
346  else /* add below */
347  pixRasterop(pixd, 0, 0, w, h, PIX_SRC, pixs, 0, 0);
348  } else { /* L_ADD_LEFT or L_ADD_RIGHT */
349  wadd = wtext + 2 * spacer;
350  pixd = pixCreate(w + wadd, h, d);
351  pixCopyColormap(pixd, pixs);
352  pixCopyResolution(pixd, pixs);
354  if (location == L_ADD_LEFT)
355  pixRasterop(pixd, wadd, 0, w, h, PIX_SRC, pixs, 0, 0);
356  else /* add to right */
357  pixRasterop(pixd, 0, 0, w, h, PIX_SRC, pixs, 0, 0);
358  }
359 
360  /* If cmapped, add the color if necessary to the cmap. If the
361  * cmap is full, use the nearest color to the requested color. */
362  cmapd = pixGetColormap(pixd);
363  if (cmapd) {
364  extractRGBValues(val, &rval, &gval, &bval);
365  pixcmapAddNearestColor(cmapd, rval, gval, bval, &index);
366  pixcmapGetColor(cmapd, index, &rval, &gval, &bval);
367  composeRGBPixel(rval, gval, bval, &textcolor);
368  } else {
369  textcolor = val;
370  }
371 
372  /* Add the text */
373  for (i = 0; i < nlines; i++) {
374  str = sarrayGetString(sa, i, L_NOCOPY);
375  bmfGetStringWidth(bmf, str, &wtext);
376  if (location == L_ADD_ABOVE)
377  pixSetTextline(pixd, bmf, str, textcolor,
378  (w - wtext) / 2, spacer + hbaseline * (1 + 1.5 * i),
379  NULL, NULL);
380  else if (location == L_ADD_BELOW)
381  pixSetTextline(pixd, bmf, str, textcolor,
382  (w - wtext) / 2, h + spacer +
383  hbaseline * (1 + 1.5 * i), NULL, NULL);
384  else if (location == L_ADD_LEFT)
385  pixSetTextline(pixd, bmf, str, textcolor,
386  spacer, (h - htext) / 2 + hbaseline * (1 + 1.5 * i),
387  NULL, NULL);
388  else /* location == L_ADD_RIGHT */
389  pixSetTextline(pixd, bmf, str, textcolor,
390  w + spacer, (h - htext) / 2 +
391  hbaseline * (1 + 1.5 * i), NULL, NULL);
392  }
393 
394  sarrayDestroy(&sa);
395  return pixd;
396 }
397 
398 
430 l_ok
432  L_BMF *bmf,
433  const char *textstr,
434  l_uint32 val,
435  l_int32 x0,
436  l_int32 y0,
437  l_int32 wtext,
438  l_int32 firstindent,
439  l_int32 *poverflow)
440 {
441 char *linestr;
442 l_int32 d, h, i, w, x, y, nlines, htext, xwidth, wline, ovf, overflow;
443 SARRAY *salines;
444 PIXCMAP *cmap;
445 
446  PROCNAME("pixSetTextblock");
447 
448  if (!pixs)
449  return ERROR_INT("pixs not defined", procName, 1);
450  if (!bmf)
451  return ERROR_INT("bmf not defined", procName, 1);
452  if (!textstr)
453  return ERROR_INT("textstr not defined", procName, 1);
454 
455  /* Make sure the "color" value for the text will work
456  * for the pix. If the pix is not colormapped and the
457  * value is out of range, set it to mid-range. */
458  pixGetDimensions(pixs, &w, &h, &d);
459  cmap = pixGetColormap(pixs);
460  if (d == 1 && val > 1)
461  val = 1;
462  else if (d == 2 && val > 3 && !cmap)
463  val = 2;
464  else if (d == 4 && val > 15 && !cmap)
465  val = 8;
466  else if (d == 8 && val > 0xff && !cmap)
467  val = 128;
468  else if (d == 16 && val > 0xffff)
469  val = 0x8000;
470  else if (d == 32 && val < 256)
471  val = 0x80808000;
472 
473  if (w < x0 + wtext) {
474  L_WARNING("reducing width of textblock\n", procName);
475  wtext = w - x0 - w / 10;
476  if (wtext <= 0)
477  return ERROR_INT("wtext too small; no room for text", procName, 1);
478  }
479 
480  salines = bmfGetLineStrings(bmf, textstr, wtext, firstindent, &htext);
481  if (!salines)
482  return ERROR_INT("line string sa not made", procName, 1);
483  nlines = sarrayGetCount(salines);
484  bmfGetWidth(bmf, 'x', &xwidth);
485 
486  y = y0;
487  overflow = 0;
488  for (i = 0; i < nlines; i++) {
489  if (i == 0)
490  x = x0 + firstindent * xwidth;
491  else
492  x = x0;
493  linestr = sarrayGetString(salines, i, L_NOCOPY);
494  pixSetTextline(pixs, bmf, linestr, val, x, y, &wline, &ovf);
495  y += bmf->lineheight + bmf->vertlinesep;
496  if (ovf)
497  overflow = 1;
498  }
499 
500  /* (y0 - baseline) is the top of the printed text. Character
501  * 93 was chosen at random, as all the baselines are essentially
502  * equal for each character in a font. */
503  if (h < y0 - bmf->baselinetab[93] + htext)
504  overflow = 1;
505  if (poverflow)
506  *poverflow = overflow;
507 
508  sarrayDestroy(&salines);
509  return 0;
510 }
511 
512 
543 l_ok
545  L_BMF *bmf,
546  const char *textstr,
547  l_uint32 val,
548  l_int32 x0,
549  l_int32 y0,
550  l_int32 *pwidth,
551  l_int32 *poverflow)
552 {
553 char chr;
554 l_int32 d, i, x, w, nchar, baseline, index, rval, gval, bval;
555 l_uint32 textcolor;
556 PIX *pix;
557 PIXCMAP *cmap;
558 
559  PROCNAME("pixSetTextline");
560 
561  if (!pixs)
562  return ERROR_INT("pixs not defined", procName, 1);
563  if (!bmf)
564  return ERROR_INT("bmf not defined", procName, 1);
565  if (!textstr)
566  return ERROR_INT("teststr not defined", procName, 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  PROCNAME("pixaAddTextNumber");
653 
654  if (!pixas)
655  return (PIXA *)ERROR_PTR("pixas not defined", procName, NULL);
656  if (!bmf)
657  return (PIXA *)ERROR_PTR("bmf not defined", procName, NULL);
658  if (location != L_ADD_ABOVE && location != L_ADD_BELOW &&
659  location != L_ADD_LEFT && location != L_ADD_RIGHT)
660  return (PIXA *)ERROR_PTR("invalid location", procName, NULL);
661 
662  n = pixaGetCount(pixas);
663  pixad = pixaCreate(n);
664  for (i = 0; i < n; i++) {
665  pix1 = pixaGetPix(pixas, i, L_CLONE);
666  if (na)
667  numaGetIValue(na, i, &index);
668  else
669  index = i + 1;
670  snprintf(textstr, sizeof(textstr), "%d", index);
671  pix2 = pixAddTextlines(pix1, bmf, textstr, val, location);
672  pixaAddPix(pixad, pix2, L_INSERT);
673  pixDestroy(&pix1);
674  }
675 
676  return pixad;
677 }
678 
679 
709 PIXA *
711  L_BMF *bmf,
712  SARRAY *sa,
713  l_uint32 val,
714  l_int32 location)
715 {
716 char *textstr;
717 l_int32 i, n, nstr;
718 PIX *pix1, *pix2;
719 PIXA *pixad;
720 
721  PROCNAME("pixaAddTextlines");
722 
723  if (!pixas)
724  return (PIXA *)ERROR_PTR("pixas not defined", procName, NULL);
725  if (!bmf)
726  return (PIXA *)ERROR_PTR("bmf not defined", procName, NULL);
727  if (location != L_ADD_ABOVE && location != L_ADD_BELOW &&
728  location != L_ADD_LEFT && location != L_ADD_RIGHT)
729  return (PIXA *)ERROR_PTR("invalid location", procName, NULL);
730 
731  n = pixaGetCount(pixas);
732  pixad = pixaCreate(n);
733  nstr = (sa) ? sarrayGetCount(sa) : 0;
734  if (nstr > 0 && nstr < n)
735  L_WARNING("There are %d strings and %d pix\n", procName, nstr, n);
736  for (i = 0; i < n; i++) {
737  pix1 = pixaGetPix(pixas, i, L_CLONE);
738  if (i < nstr)
739  textstr = sarrayGetString(sa, i, L_NOCOPY);
740  else
741  textstr = pixGetText(pix1);
742  pix2 = pixAddTextlines(pix1, bmf, textstr, val, location);
743  pixaAddPix(pixad, pix2, L_INSERT);
744  pixDestroy(&pix1);
745  }
746 
747  return pixad;
748 }
749 
750 
779 l_ok
781  PIX *pixs,
782  l_int32 reduction,
783  L_BMF *bmf,
784  const char *textstr,
785  l_uint32 val,
786  l_int32 location)
787 {
788 l_int32 d;
789 L_BMF *bmf8;
790 PIX *pix1, *pix2, *pix3;
791 PIXCMAP *cmap;
792 
793  PROCNAME("pixaAddPixWithText");
794 
795  if (!pixa)
796  return ERROR_INT("pixa not defined", procName, 1);
797  if (!pixs)
798  return ERROR_INT("pixs not defined", procName, 1);
799  if (location != L_ADD_ABOVE && location != L_ADD_BELOW &&
800  location != L_ADD_LEFT && location != L_ADD_RIGHT)
801  return ERROR_INT("invalid location", procName, 1);
802 
803  if (!textstr) {
804  textstr = pixGetText(pixs);
805  if (!textstr) {
806  L_WARNING("no textstring defined; inserting copy", procName);
807  pixaAddPix(pixa, pixs, L_COPY);
808  return 0;
809  }
810  }
811 
812  /* Default font size is 8. */
813  bmf8 = (bmf) ? bmf : bmfCreate(NULL, 8);
814 
815  if (reduction != 1)
816  pix1 = pixScaleByIntSampling(pixs, reduction);
817  else
818  pix1 = pixClone(pixs);
819 
820  /* We want the text to be rendered in color. This works
821  * automatically if pixs is cmapped or 32 bpp rgb; otherwise,
822  * we need to convert to rgb. */
823  cmap = pixGetColormap(pix1);
824  d = pixGetDepth(pix1);
825  if (!cmap && d != 32)
826  pix2 = pixConvertTo32(pix1);
827  else
828  pix2 = pixClone(pix1);
829 
830  pix3 = pixAddTextlines(pix2, bmf, textstr, val, location);
831  pixDestroy(&pix1);
832  pixDestroy(&pix2);
833  if (!bmf) bmfDestroy(&bmf8);
834  if (!pix3)
835  return ERROR_INT("pix3 not made", procName, 1);
836 
837  pixaAddPix(pixa, pix3, L_INSERT);
838  return 0;
839 }
840 
841 
842 /*---------------------------------------------------------------------*
843  * Text size estimation and partitioning *
844  *---------------------------------------------------------------------*/
861 SARRAY *
863  const char *textstr,
864  l_int32 maxw,
865  l_int32 firstindent,
866  l_int32 *ph)
867 {
868 char *linestr;
869 l_int32 i, ifirst, sumw, newsum, w, nwords, nlines, len, xwidth;
870 NUMA *na;
871 SARRAY *sa, *sawords;
872 
873  PROCNAME("bmfGetLineStrings");
874 
875  if (!bmf)
876  return (SARRAY *)ERROR_PTR("bmf not defined", procName, NULL);
877  if (!textstr)
878  return (SARRAY *)ERROR_PTR("teststr not defined", procName, NULL);
879 
880  if ((sawords = sarrayCreateWordsFromString(textstr)) == NULL)
881  return (SARRAY *)ERROR_PTR("sawords not made", procName, NULL);
882 
883  if ((na = bmfGetWordWidths(bmf, textstr, sawords)) == NULL) {
884  sarrayDestroy(&sawords);
885  return (SARRAY *)ERROR_PTR("na not made", procName, NULL);
886  }
887  nwords = numaGetCount(na);
888  if (nwords == 0) {
889  sarrayDestroy(&sawords);
890  numaDestroy(&na);
891  return (SARRAY *)ERROR_PTR("no words in textstr", procName, NULL);
892  }
893  bmfGetWidth(bmf, 'x', &xwidth);
894 
895  sa = sarrayCreate(0);
896  ifirst = 0;
897  numaGetIValue(na, 0, &w);
898  sumw = firstindent * xwidth + w;
899  for (i = 1; i < nwords; i++) {
900  numaGetIValue(na, i, &w);
901  newsum = sumw + bmf->spacewidth + w;
902  if (newsum > maxw) {
903  linestr = sarrayToStringRange(sawords, ifirst, i - ifirst, 2);
904  if (!linestr)
905  continue;
906  len = strlen(linestr);
907  if (len > 0) /* it should always be */
908  linestr[len - 1] = '\0'; /* remove the last space */
909  sarrayAddString(sa, linestr, L_INSERT);
910  ifirst = i;
911  sumw = w;
912  }
913  else
914  sumw += bmf->spacewidth + w;
915  }
916  linestr = sarrayToStringRange(sawords, ifirst, nwords - ifirst, 2);
917  if (linestr)
918  sarrayAddString(sa, linestr, L_INSERT);
919  nlines = sarrayGetCount(sa);
920  *ph = nlines * bmf->lineheight + (nlines - 1) * bmf->vertlinesep;
921 
922  sarrayDestroy(&sawords);
923  numaDestroy(&na);
924  return sa;
925 }
926 
927 
937 NUMA *
939  const char *textstr,
940  SARRAY *sa)
941 {
942 char *wordstr;
943 l_int32 i, nwords, width;
944 NUMA *na;
945 
946  PROCNAME("bmfGetWordWidths");
947 
948  if (!bmf)
949  return (NUMA *)ERROR_PTR("bmf not defined", procName, NULL);
950  if (!textstr)
951  return (NUMA *)ERROR_PTR("teststr not defined", procName, NULL);
952  if (!sa)
953  return (NUMA *)ERROR_PTR("sa not defined", procName, NULL);
954 
955  nwords = sarrayGetCount(sa);
956  if ((na = numaCreate(nwords)) == NULL)
957  return (NUMA *)ERROR_PTR("na not made", procName, NULL);
958 
959  for (i = 0; i < nwords; i++) {
960  wordstr = sarrayGetString(sa, i, L_NOCOPY);
961  bmfGetStringWidth(bmf, wordstr, &width);
962  numaAddNumber(na, width);
963  }
964 
965  return na;
966 }
967 
968 
978 l_ok
980  const char *textstr,
981  l_int32 *pw)
982 {
983 char chr;
984 l_int32 i, w, width, nchar;
985 
986  PROCNAME("bmfGetStringWidth");
987 
988  if (!bmf)
989  return ERROR_INT("bmf not defined", procName, 1);
990  if (!textstr)
991  return ERROR_INT("teststr not defined", procName, 1);
992  if (!pw)
993  return ERROR_INT("&w not defined", procName, 1);
994 
995  nchar = strlen(textstr);
996  w = 0;
997  for (i = 0; i < nchar; i++) {
998  chr = textstr[i];
999  bmfGetWidth(bmf, chr, &width);
1000  if (width != UNDEF)
1001  w += width + bmf->kernwidth;
1002  }
1003  w -= bmf->kernwidth; /* remove last one */
1004 
1005  *pw = w;
1006  return 0;
1007 }
1008 
1009 
1010 
1011 /*---------------------------------------------------------------------*
1012  * Text splitting *
1013  *---------------------------------------------------------------------*/
1022 SARRAY *
1024  l_int32 splitflag)
1025 {
1026 char *linestr, *parastring;
1027 l_int32 nlines, i, allwhite, leadwhite;
1028 SARRAY *salines, *satemp, *saout;
1029 
1030  PROCNAME("splitStringToParagraphs");
1031 
1032  if (!textstr)
1033  return (SARRAY *)ERROR_PTR("textstr not defined", procName, NULL);
1034 
1035  if ((salines = sarrayCreateLinesFromString(textstr, 1)) == NULL)
1036  return (SARRAY *)ERROR_PTR("salines not made", procName, NULL);
1037  nlines = sarrayGetCount(salines);
1038  saout = sarrayCreate(0);
1039  satemp = sarrayCreate(0);
1040 
1041  linestr = sarrayGetString(salines, 0, L_NOCOPY);
1042  sarrayAddString(satemp, linestr, L_COPY);
1043  for (i = 1; i < nlines; i++) {
1044  linestr = sarrayGetString(salines, i, L_NOCOPY);
1045  stringAllWhitespace(linestr, &allwhite);
1046  stringLeadingWhitespace(linestr, &leadwhite);
1047  if ((splitflag == SPLIT_ON_LEADING_WHITE && leadwhite) ||
1048  (splitflag == SPLIT_ON_BLANK_LINE && allwhite) ||
1049  (splitflag == SPLIT_ON_BOTH && (allwhite || leadwhite))) {
1050  parastring = sarrayToString(satemp, 1); /* add nl to each line */
1051  sarrayAddString(saout, parastring, L_INSERT);
1052  sarrayDestroy(&satemp);
1053  satemp = sarrayCreate(0);
1054  }
1055  sarrayAddString(satemp, linestr, L_COPY);
1056  }
1057  parastring = sarrayToString(satemp, 1); /* add nl to each line */
1058  sarrayAddString(saout, parastring, L_INSERT);
1059  sarrayDestroy(&satemp);
1060  sarrayDestroy(&salines);
1061  return saout;
1062 }
1063 
1064 
1072 static l_int32
1073 stringAllWhitespace(char *textstr,
1074  l_int32 *pval)
1075 {
1076 l_int32 len, i;
1077 
1078  PROCNAME("stringAllWhitespace");
1079 
1080  if (!textstr)
1081  return ERROR_INT("textstr not defined", procName, 1);
1082  if (!pval)
1083  return ERROR_INT("&va not defined", procName, 1);
1084 
1085  len = strlen(textstr);
1086  *pval = 1;
1087  for (i = 0; i < len; i++) {
1088  if (textstr[i] != ' ' && textstr[i] != '\t' && textstr[i] != '\n') {
1089  *pval = 0;
1090  return 0;
1091  }
1092  }
1093  return 0;
1094 }
1095 
1096 
1104 static l_int32
1106  l_int32 *pval)
1107 {
1108  PROCNAME("stringLeadingWhitespace");
1109 
1110  if (!textstr)
1111  return ERROR_INT("textstr not defined", procName, 1);
1112  if (!pval)
1113  return ERROR_INT("&va not defined", procName, 1);
1114 
1115  *pval = 0;
1116  if (textstr[0] == ' ' || textstr[0] == '\t')
1117  *pval = 1;
1118 
1119  return 0;
1120 }
void bmfDestroy(L_BMF **pbmf)
bmfDestroy()
Definition: bmf.c:166
char * sarrayToString(SARRAY *sa, l_int32 addnlflag)
sarrayToString()
Definition: sarray1.c:763
Definition: pix.h:717
PIX * bmfGetPix(L_BMF *bmf, char chr)
bmfGetPix()
Definition: bmf.c:202
PIX * pixConvertTo32(PIX *pixs)
pixConvertTo32()
Definition: pixconv.c:3233
l_int32 lineheight
Definition: bmf.h:53
l_ok numaAddNumber(NUMA *na, l_float32 val)
numaAddNumber()
Definition: numabasic.c:473
PIXA * pixaCreate(l_int32 n)
pixaCreate()
Definition: pixabasic.c:163
l_int32 * baselinetab
Definition: bmf.h:58
Definition: pix.h:716
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:193
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:431
PIX * pixCreate(l_int32 width, l_int32 height, l_int32 depth)
pixCreate()
Definition: pix1.c:302
SARRAY * sarrayCreate(l_int32 n)
sarrayCreate()
Definition: sarray1.c:163
char * sarrayToStringRange(SARRAY *sa, l_int32 first, l_int32 nstrings, l_int32 addnlflag)
sarrayToStringRange()
Definition: sarray1.c:798
NUMA * numaCreate(l_int32 n)
numaCreate()
Definition: numabasic.c:187
PIXA * pixaAddTextlines(PIXA *pixas, L_BMF *bmf, SARRAY *sa, l_uint32 val, l_int32 location)
pixaAddTextlines()
Definition: textops.c:710
static l_int32 stringLeadingWhitespace(char *textstr, l_int32 *pval)
stringLeadingWhitespace()
Definition: textops.c:1105
l_ok bmfGetStringWidth(L_BMF *bmf, const char *textstr, l_int32 *pw)
bmfGetStringWidth()
Definition: textops.c:979
l_ok bmfGetWidth(L_BMF *bmf, char chr, l_int32 *pw)
bmfGetWidth()
Definition: bmf.c:237
Definition: bmf.h:45
Definition: array.h:116
l_ok pixPaintThroughMask(PIX *pixd, PIX *pixm, l_int32 x, l_int32 y, l_uint32 val)
pixPaintThroughMask()
Definition: pix3.c:618
l_ok numaGetIValue(NUMA *na, l_int32 index, l_int32 *pival)
numaGetIValue()
Definition: numabasic.c:727
l_ok pixaAddPix(PIXA *pixa, PIX *pix, l_int32 copyflag)
pixaAddPix()
Definition: pixabasic.c:503
Definition: array.h:59
l_int32 numaGetCount(NUMA *na)
numaGetCount()
Definition: numabasic.c:631
l_ok sarrayAddString(SARRAY *sa, const char *string, l_int32 copyflag)
sarrayAddString()
Definition: sarray1.c:446
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:780
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:544
l_ok pixcmapGetColor(PIXCMAP *cmap, l_int32 index, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
pixcmapGetColor()
Definition: colormap.c:751
l_ok pixSetBlackOrWhite(PIX *pixs, l_int32 op)
pixSetBlackOrWhite()
Definition: pix2.c:946
char * sarrayGetString(SARRAY *sa, l_int32 index, l_int32 copyflag)
sarrayGetString()
Definition: sarray1.c:681
l_int32 kernwidth
Definition: bmf.h:54
PIX * pixClone(PIX *pixs)
pixClone()
Definition: pix1.c:515
void pixDestroy(PIX **ppix)
pixDestroy()
Definition: pix1.c:543
l_ok pixCopyColormap(PIX *pixd, PIX *pixs)
pixCopyColormap()
Definition: pix1.c:745
l_ok pixcmapAddNearestColor(PIXCMAP *cmap, l_int32 rval, l_int32 gval, l_int32 bval, l_int32 *pindex)
pixcmapAddNearestColor()
Definition: colormap.c:472
SARRAY * splitStringToParagraphs(char *textstr, l_int32 splitflag)
splitStringToParagraphs()
Definition: textops.c:1023
PIX * pixScaleByIntSampling(PIX *pixs, l_int32 factor)
pixScaleByIntSampling()
Definition: scale1.c:1445
l_ok bmfGetBaseline(L_BMF *bmf, char chr, l_int32 *pbaseline)
bmfGetBaseline()
Definition: bmf.c:276
SARRAY * sarrayCreateLinesFromString(const char *string, l_int32 blankflag)
sarrayCreateLinesFromString()
Definition: sarray1.c:276
Definition: pix.h:454
void numaDestroy(NUMA **pna)
numaDestroy()
Definition: numabasic.c:360
l_int32 vertlinesep
Definition: bmf.h:56
l_ok pixGetDimensions(const PIX *pix, l_int32 *pw, l_int32 *ph, l_int32 *pd)
pixGetDimensions()
Definition: pix1.c:1065
static l_int32 stringAllWhitespace(char *textstr, l_int32 *pval)
stringAllWhitespace()
Definition: textops.c:1073
l_int32 sarrayGetCount(SARRAY *sa)
sarrayGetCount()
Definition: sarray1.c:621
char * pixGetText(PIX *pix)
pixGetText()
Definition: pix1.c:1459
PIX * pixaGetPix(PIXA *pixa, l_int32 index, l_int32 accesstype)
pixaGetPix()
Definition: pixabasic.c:672
Definition: pix.h:718
Definition: pix.h:134
Definition: pix.h:719
#define PIX_SRC
Definition: pix.h:327
PIX * pixCopy(PIX *pixd, PIX *pixs)
pixCopy()
Definition: pix1.c:628
PIX * pixAddTextlines(PIX *pixs, L_BMF *bmf, const char *textstr, l_uint32 val, l_int32 location)
pixAddTextlines()
Definition: textops.c:270
l_ok composeRGBPixel(l_int32 rval, l_int32 gval, l_int32 bval, l_uint32 *ppixel)
composeRGBPixel()
Definition: pix2.c:2671
NUMA * bmfGetWordWidths(L_BMF *bmf, const char *textstr, SARRAY *sa)
bmfGetWordWidths()
Definition: textops.c:938
SARRAY * bmfGetLineStrings(L_BMF *bmf, const char *textstr, l_int32 maxw, l_int32 firstindent, l_int32 *ph)
bmfGetLineStrings()
Definition: textops.c:862
PIX * pixAddSingleTextblock(PIX *pixs, L_BMF *bmf, const char *textstr, l_uint32 val, l_int32 location, l_int32 *poverflow)
pixAddSingleTextblock()
Definition: textops.c:115
void extractRGBValues(l_uint32 pixel, l_int32 *prval, l_int32 *pgval, l_int32 *pbval)
extractRGBValues()
Definition: pix2.c:2737
l_int32 spacewidth
Definition: bmf.h:55
l_int32 pixaGetCount(PIXA *pixa)
pixaGetCount()
Definition: pixabasic.c:631
SARRAY * sarrayCreateWordsFromString(const char *string)
sarrayCreateWordsFromString()
Definition: sarray1.c:226
PIXA * pixaAddTextNumber(PIXA *pixas, L_BMF *bmf, NUMA *na, l_uint32 val, l_int32 location)
pixaAddTextNumber()
Definition: textops.c:641
void sarrayDestroy(SARRAY **psa)
sarrayDestroy()
Definition: sarray1.c:355
L_BMF * bmfCreate(const char *dir, l_int32 fontsize)
bmfCreate()
Definition: bmf.c:114