src/textops.c
PIX *
pixAddSingleTextblock(PIX         *pixs,
                      L_BMF       *bmf,
                      const char  *textstr,
                      l_uint32     val,
                      l_int32      location,
                      l_int32     *poverflow)
{
char     *linestr;
l_int32   w, h, d, i, y, xstart, ystart, extra, spacer, rval, gval, bval;
l_int32   nlines, htext, ovf, overflow, offset, index;
l_uint32  textcolor;
PIX      *pixd;
PIXCMAP  *cmap, *cmapd;
SARRAY   *salines;

    PROCNAME("pixAddSingleTextblock");

    if (!pixs)
        return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
    if (!bmf)
        return (PIX *)ERROR_PTR("bmf not defined", procName, NULL);
    if (val < 0)
        return (PIX *)ERROR_PTR("val must be >= 0", procName, NULL);
    if (location != L_ADD_ABOVE && location != L_ADD_AT_TOP &&
        location != L_ADD_AT_BOTTOM && location != L_ADD_BELOW)
        return (PIX *)ERROR_PTR("invalid location", procName, NULL);

    if (!textstr)
        textstr = pixGetText(pixs);
    if (!textstr) {
        L_ERROR("no textstring defined", procName);
        return pixCopy(NULL, pixs);
    }

        /* Make sure the "color" value for the text will work
         * for the pix.  If the pix is not colormapped and the
         * value is out of range, set it to mid-range. */
    pixGetDimensions(pixs, &w, &h, &d);
    cmap = pixGetColormap(pixs);
    if (d == 1 && val > 1)
        val = 1;
    else if (d == 2 && val > 3 && !cmap)
        val = 2;
    else if (d == 4 && val > 15 && !cmap)
        val = 8;
    else if (d == 8 && val > 0xff && !cmap)
        val = 128;
    else if (d == 16 && val > 0xffff)
        val = 0x8000;
    else if (d == 32 && val < 256)
        val = 0x80808000;

    xstart = (l_int32)(0.1 * w);
    salines = bmfGetLineStrings(bmf, textstr, w - 2 * xstart, 0, &htext);
    if (!salines)
        return (PIX *)ERROR_PTR("line string sa not made", procName, NULL);
    nlines = sarrayGetCount(salines);

        /* Add white border if required */
    spacer = 10;  /* pixels away from image boundary or added border */
    if (location == L_ADD_ABOVE || location == L_ADD_BELOW) {
        extra = htext + 2 * spacer;
        pixd = pixCreate(w, h + extra, d);
        if (cmap) {
            cmapd = pixcmapCopy(cmap);
            pixSetColormap(pixd, cmapd);
        }
        pixSetBlackOrWhite(pixd, L_BRING_IN_WHITE);
        if (location == L_ADD_ABOVE)
            pixRasterop(pixd, 0, extra, w, h, PIX_SRC, pixs, 0, 0);
        else  /* add below */
            pixRasterop(pixd, 0, 0, w, h, PIX_SRC, pixs, 0, 0);
    }
    else
        pixd = pixCopy(NULL, pixs);
    cmapd = pixGetColormap(pixd);

        /* bmf->baselinetab[93] is the approximate distance from
         * the top of the tallest character to the baseline.  93 was chosen
         * at random, as all the baselines are essentially equal for
         * each character in a font. */
    offset = bmf->baselinetab[93];
    if (location == L_ADD_ABOVE || location == L_ADD_AT_TOP)
        ystart = offset + spacer;
    else if (location == L_ADD_AT_BOTTOM)
        ystart = h - htext - spacer + offset;
    else   /* add below */
        ystart = h + offset + spacer;

        /* If cmapped, add the color if necessary to the cmap.  If the
         * cmap is full, use the nearest color to the requested color. */
    if (cmapd) {
        extractRGBValues(val, &rval, &gval, &bval);
        pixcmapAddNearestColor(cmapd, rval, gval, bval, &index);
        pixcmapGetColor(cmapd, index, &rval, &gval, &bval);
        composeRGBPixel(rval, gval, bval, &textcolor);
    } else
        textcolor = val;

        /* Keep track of overflow condition on line width */
    overflow = 0;
    for (i = 0, y = ystart; i < nlines; i++) {
        linestr = sarrayGetString(salines, i, 0);
        pixSetTextline(pixd, bmf, linestr, textcolor,
                       xstart, y, NULL, &ovf);
        y += bmf->lineheight + bmf->vertlinesep;
        if (ovf)
            overflow = 1;
    }

       /* Also consider vertical overflow where there is too much text to
        * fit inside the image: the cases L_ADD_AT_TOP and L_ADD_AT_BOTTOM.
        *  The text requires a total of htext + 2 * spacer vertical pixels. */
    if (location == L_ADD_AT_TOP || location == L_ADD_AT_BOTTOM) {
        if (h < htext + 2 * spacer)
            overflow = 1;
    }
    if (poverflow)
        *poverflow = overflow;

    sarrayDestroy(&salines);
    return pixd;
}
/*!
 *  pixAddSingleTextblock()
 *
 *      Input:  pixs (input pix; colormap ok)
 *              bmf (bitmap font data)
 *              textstr (<optional> text string to be added)
 *              val (color to set the text)
 *              location (L_ADD_ABOVE, L_ADD_AT_TOP, L_ADD_AT_BOTTOM,
 *                        L_ADD_BELOW)
 *              &overflow (<optional return> 1 if text overflows
 *                         allocated region and is clipped; 0 otherwise)
 *      Return: pixd (new pix with rendered text), or null on error
 *
 *  Notes:
 *      (1) This function paints a set of lines of text over an image.
 *          If @location is L_ADD_ABOVE or L_ADD_BELOW, the pix size
 *          is expanded with a border and rendered over the border.
 *      (2) @val is the pixel value to be painted through the font mask.
 *          It should be chosen to agree with the depth of pixs.
 *          If it is out of bounds, an intermediate value is chosen.
 *          For RGB, use hex notation: 0xRRGGBB00, where RR is the
 *          hex representation of the red intensity, etc.
 *      (3) If textstr == NULL, use the text field in the pix.
 *      (4) If there is a colormap, this does the best it can to use
 *          the requested color, or something similar to it.
 *      (5) Typical usage is for labelling a pix with some text data.
 */


(1) This function paints a set of lines of text over an image.
If @location is L_ADD_ABOVE or L_ADD_BELOW, the pix size
is expanded with a border and rendered over the border.
(2) @val is the pixel value to be painted through the font mask.
It should be chosen to agree with the depth of pixs.
If it is out of bounds, an intermediate value is chosen.
For RGB, use hex notation: 0xRRGGBB00, where RR is the
hex representation of the red intensity, etc.
(3) If textstr == NULL, use the text field in the pix.
(4) If there is a colormap, this does the best it can to use
the requested color, or something similar to it.
(5) Typical usage is for labelling a pix with some text data.
( 1 ) This function paints a set of lines of text over an image . If @location is L_ADD_ABOVE or L_ADD_BELOW the pix size is expanded with a border and rendered over the border . ( 2 ) @val is the pixel value to be painted through the font mask . It should be chosen to agree with the depth of pixs . If it is out of bounds an intermediate value is chosen . For RGB use hex notation : 0xRRGGBB00 where RR is the hex representation of the red intensity etc . ( 3 ) If textstr == NULL use the text field in the pix . ( 4 ) If there is a colormap this does the best it can to use the requested color or something similar to it . ( 5 ) Typical usage is for labelling a pix with some text data .
PIX *
pixAddSingleTextblock(PIX         *pixs,
                      L_BMF       *bmf,
                      const char  *textstr,
                      l_uint32     val,
                      l_int32      location,
                      l_int32     *poverflow)
{
char     *linestr;
l_int32   w, h, d, i, y, xstart, ystart, extra, spacer, rval, gval, bval;
l_int32   nlines, htext, ovf, overflow, offset, index;
l_uint32  textcolor;
PIX      *pixd;
PIXCMAP  *cmap, *cmapd;
SARRAY   *salines;
    PROCNAME("pixAddSingleTextblock");
    if (!pixs)
        return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
    if (!bmf)
        return (PIX *)ERROR_PTR("bmf not defined", procName, NULL);
    if (val < 0)
        return (PIX *)ERROR_PTR("val must be >= 0", procName, NULL);
    if (location != L_ADD_ABOVE && location != L_ADD_AT_TOP &&
        location != L_ADD_AT_BOTTOM && location != L_ADD_BELOW)
        return (PIX *)ERROR_PTR("invalid location", procName, NULL);
    if (!textstr)
        textstr = pixGetText(pixs);
    if (!textstr) {
        L_ERROR("no textstring defined", procName);
        return pixCopy(NULL, pixs);
    }
    pixGetDimensions(pixs, &w, &h, &d);
    cmap = pixGetColormap(pixs);
    if (d == 1 && val > 1)
        val = 1;
    else if (d == 2 && val > 3 && !cmap)
        val = 2;
    else if (d == 4 && val > 15 && !cmap)
        val = 8;
    else if (d == 8 && val > 0xff && !cmap)
        val = 128;
    else if (d == 16 && val > 0xffff)
        val = 0x8000;
    else if (d == 32 && val < 256)
        val = 0x80808000;
    xstart = (l_int32)(0.1 * w);
    salines = bmfGetLineStrings(bmf, textstr, w - 2 * xstart, 0, &htext);
    if (!salines)
        return (PIX *)ERROR_PTR("line string sa not made", procName, NULL);
    nlines = sarrayGetCount(salines);
    spacer = 10;  
    if (location == L_ADD_ABOVE || location == L_ADD_BELOW) {
        extra = htext + 2 * spacer;
        pixd = pixCreate(w, h + extra, d);
        if (cmap) {
            cmapd = pixcmapCopy(cmap);
            pixSetColormap(pixd, cmapd);
        }
        pixSetBlackOrWhite(pixd, L_BRING_IN_WHITE);
        if (location == L_ADD_ABOVE)
            pixRasterop(pixd, 0, extra, w, h, PIX_SRC, pixs, 0, 0);
        else  
            pixRasterop(pixd, 0, 0, w, h, PIX_SRC, pixs, 0, 0);
    }
    else
        pixd = pixCopy(NULL, pixs);
    cmapd = pixGetColormap(pixd);
    offset = bmf->baselinetab[93];
    if (location == L_ADD_ABOVE || location == L_ADD_AT_TOP)
        ystart = offset + spacer;
    else if (location == L_ADD_AT_BOTTOM)
        ystart = h - htext - spacer + offset;
    else   
        ystart = h + offset + spacer;
    if (cmapd) {
        extractRGBValues(val, &rval, &gval, &bval);
        pixcmapAddNearestColor(cmapd, rval, gval, bval, &index);
        pixcmapGetColor(cmapd, index, &rval, &gval, &bval);
        composeRGBPixel(rval, gval, bval, &textcolor);
    } else
        textcolor = val;
    overflow = 0;
    for (i = 0, y = ystart; i < nlines; i++) {
        linestr = sarrayGetString(salines, i, 0);
        pixSetTextline(pixd, bmf, linestr, textcolor,
                       xstart, y, NULL, &ovf);
        y += bmf->lineheight + bmf->vertlinesep;
        if (ovf)
            overflow = 1;
    }
    if (location == L_ADD_AT_TOP || location == L_ADD_AT_BOTTOM) {
        if (h < htext + 2 * spacer)
            overflow = 1;
    }
    if (poverflow)
        *poverflow = overflow;
    sarrayDestroy(&salines);
    return pixd;
}
PIX * pixAddSingleTextblock ( PIX * pixs , L_BMF * bmf , const char * textstr , l_uint32 val , l_int32 location , l_int32 * poverflow ) { char * linestr ; l_int32 w , h , d , i , y , xstart , ystart , extra , spacer , rval , gval , bval ; l_int32 nlines , htext , ovf , overflow , offset , index ; l_uint32 textcolor ; PIX * pixd ; PIXCMAP * cmap , * cmapd ; SARRAY * salines ; PROCNAME ( " " ) ; if ( ! pixs ) return ( PIX * ) ERROR_PTR ( " " , procName , NULL ) ; if ( ! bmf ) return ( PIX * ) ERROR_PTR ( " " , procName , NULL ) ; if ( val < 0 ) return ( PIX * ) ERROR_PTR ( " " , procName , NULL ) ; if ( location != L_ADD_ABOVE && location != L_ADD_AT_TOP && location != L_ADD_AT_BOTTOM && location != L_ADD_BELOW ) return ( PIX * ) ERROR_PTR ( " " , procName , NULL ) ; if ( ! textstr ) textstr = pixGetText ( pixs ) ; if ( ! textstr ) { L_ERROR ( " " , procName ) ; return pixCopy ( NULL , pixs ) ; } pixGetDimensions ( pixs , & w , & h , & d ) ; cmap = pixGetColormap ( pixs ) ; if ( d == 1 && val > 1 ) val = 1 ; else if ( d == 2 && val > 3 && ! cmap ) val = 2 ; else if ( d == 4 && val > 15 && ! cmap ) val = 8 ; else if ( d == 8 && val > 0xff && ! cmap ) val = 128 ; else if ( d == 16 && val > 0xffff ) val = 0x8000 ; else if ( d == 32 && val < 256 ) val = 0x80808000 ; xstart = ( l_int32 ) ( 0.1 * w ) ; salines = bmfGetLineStrings ( bmf , textstr , w - 2 * xstart , 0 , & htext ) ; if ( ! salines ) return ( PIX * ) ERROR_PTR ( " " , procName , NULL ) ; nlines = sarrayGetCount ( salines ) ; spacer = 10 ; if ( location == L_ADD_ABOVE || location == L_ADD_BELOW ) { extra = htext + 2 * spacer ; pixd = pixCreate ( w , h + extra , d ) ; if ( cmap ) { cmapd = pixcmapCopy ( cmap ) ; pixSetColormap ( pixd , cmapd ) ; } pixSetBlackOrWhite ( pixd , L_BRING_IN_WHITE ) ; if ( location == L_ADD_ABOVE ) pixRasterop ( pixd , 0 , extra , w , h , PIX_SRC , pixs , 0 , 0 ) ; else pixRasterop ( pixd , 0 , 0 , w , h , PIX_SRC , pixs , 0 , 0 ) ; } else pixd = pixCopy ( NULL , pixs ) ; cmapd = pixGetColormap ( pixd ) ; offset = bmf -> baselinetab [ 93 ] ; if ( location == L_ADD_ABOVE || location == L_ADD_AT_TOP ) ystart = offset + spacer ; else if ( location == L_ADD_AT_BOTTOM ) ystart = h - htext - spacer + offset ; else ystart = h + offset + spacer ; if ( cmapd ) { extractRGBValues ( val , & rval , & gval , & bval ) ; pixcmapAddNearestColor ( cmapd , rval , gval , bval , & index ) ; pixcmapGetColor ( cmapd , index , & rval , & gval , & bval ) ; composeRGBPixel ( rval , gval , bval , & textcolor ) ; } else textcolor = val ; overflow = 0 ; for ( i = 0 , y = ystart ; i < nlines ; i ++ ) { linestr = sarrayGetString ( salines , i , 0 ) ; pixSetTextline ( pixd , bmf , linestr , textcolor , xstart , y , NULL , & ovf ) ; y += bmf -> lineheight + bmf -> vertlinesep ; if ( ovf ) overflow = 1 ; } if ( location == L_ADD_AT_TOP || location == L_ADD_AT_BOTTOM ) { if ( h < htext + 2 * spacer ) overflow = 1 ; } if ( poverflow ) * poverflow = overflow ; sarrayDestroy ( & salines ) ; return pixd ; }
pixAddSingleTextblock()
      Input:  pixs (input pix; colormap ok)
              bmf (bitmap font data)
              textstr (<optional> text string to be added)
              val (color to set the text)
              location (L_ADD_ABOVE, L_ADD_AT_TOP, L_ADD_AT_BOTTOM,
                        L_ADD_BELOW)
              &overflow (<optional return> 1 if text overflows
                         allocated region and is clipped; 0 otherwise)
      Return: pixd (new pix with rendered text), or null on error
pixAddSingleTextblock () Input : pixs ( input pix ; colormap ok ) bmf ( bitmap font data ) textstr ( <optional > text string to be added ) val ( color to set the text ) location ( L_ADD_ABOVE L_ADD_AT_TOP L_ADD_AT_BOTTOM L_ADD_BELOW ) &overflow ( <optional return > 1 if text overflows allocated region and is clipped ; 0 otherwise ) Return : pixd ( new pix with rendered text ) or null on error
/* Make sure the "color" value for the text will work
         * for the pix.  If the pix is not colormapped and the
         * value is out of range, set it to mid-range. */ /* Add white border if required */ /* pixels away from image boundary or added border */ /* add below */ /* bmf->baselinetab[93] is the approximate distance from
         * the top of the tallest character to the baseline.  93 was chosen
         * at random, as all the baselines are essentially equal for
         * each character in a font. */ /* add below */ /* If cmapped, add the color if necessary to the cmap.  If the
         * cmap is full, use the nearest color to the requested color. */ /* Keep track of overflow condition on line width */ /* Also consider vertical overflow where there is too much text to
        * fit inside the image: the cases L_ADD_AT_TOP and L_ADD_AT_BOTTOM.
        *  The text requires a total of htext + 2 * spacer vertical pixels. */