/*!
 *  pixcmapAddNewColor()
 *
 *      Input:  cmap
 *              rval, gval, bval (colormap entry to be added; each number
 *                                is in range [0, ... 255])
 *              &index (<return> index of color)
 *      Return: 0 if OK, 1 on error; 2 if unable to add color
 *
 *  Notes:
 *      (1) This only adds color if not already there.
 *      (2) This returns the index of the new (or existing) color.
 *      (3) Returns 2 with a warning if unable to add this color;
 *          the caller should check the return value.
 */
l_int32
pixcmapAddNewColor(PIXCMAP  *cmap,
                   l_int32   rval,
                   l_int32   gval,
                   l_int32   bval,
                   l_int32  *pindex)
{
    PROCNAME("pixcmapAddNewColor");

    if (!pindex)
        return ERROR_INT("&index not defined", procName, 1);
    *pindex = 0;
    if (!cmap)
        return ERROR_INT("cmap not defined", procName, 1);

        /* Check if the color is already present. */
    if (!pixcmapGetIndex(cmap, rval, gval, bval, pindex))  /* found */
        return 0;

        /* We need to add the color.  Is there room? */
    if (cmap->n >= cmap->nalloc) {
        L_WARNING("no free color entries", procName);
        return 2;
    }

        /* There's room.  Add it. */
    pixcmapAddColor(cmap, rval, gval, bval);
    *pindex = pixcmapGetCount(cmap) - 1;
    return 0;
}
/*!
 *  pixcmapShiftIntensity()
 *
 *      Input:  colormap
 *              fraction (between -1.0 and +1.0)
 *      Return: 0 if OK; 1 on error
 *
 *  Notes:
 *      - in-place transform
 *      - This does a proportional shift of the intensity for each color.
 *      - If fraction < 0.0, it moves all colors towards (0,0,0).
 *        This darkens the image.
 *      - If fraction > 0.0, it moves all colors towards (255,255,255)
 *        This fades the image.
 *      - The equivalent transform can be accomplished with pixcmapGammaTRC(),
 *        but it is considerably more difficult (see numaGammaTRC()).
 */
l_int32
pixcmapShiftIntensity(PIXCMAP   *cmap,
                      l_float32  fraction)
{
l_int32   i, ncolors, rval, gval, bval;

    PROCNAME("pixcmapShiftIntensity");

    if (!cmap)
        return ERROR_INT("cmap not defined", procName, 1);
    if (fraction < -1.0 || fraction > 1.0)
        return ERROR_INT("fraction not in [-1.0, 1.0]", procName, 1);

    ncolors = pixcmapGetCount(cmap);
    for (i = 0; i < ncolors; i++) {
        pixcmapGetColor(cmap, i, &rval, &gval, &bval);
        if (fraction < 0.0)
            pixcmapResetColor(cmap, i,
                              (l_int32)((1.0 + fraction) * rval),
                              (l_int32)((1.0 + fraction) * gval),
                              (l_int32)((1.0 + fraction) * bval));
        else
            pixcmapResetColor(cmap, i,
                              rval + (l_int32)(fraction * (255 - rval)),
                              gval + (l_int32)(fraction * (255 - gval)),
                              bval + (l_int32)(fraction * (255 - bval)));
    }

    return 0;
}
示例#3
0
/*!
 *  pixcmapHasColor()
 *
 *      Input:  cmap
 *              &color (<return> TRUE if cmap has color; FALSE otherwise)
 *      Return: 0 if OK, 1 on error
 */
LEPTONICA_EXPORT l_int32
pixcmapHasColor(PIXCMAP  *cmap,
                l_int32  *pcolor)
{
l_int32   n, i;
l_int32  *rmap, *gmap, *bmap;

    PROCNAME("pixcmapHasColor");

    if (!pcolor)
        return ERROR_INT("&color not defined", procName, 1);
    *pcolor = FALSE;
    if (!cmap)
        return ERROR_INT("cmap not defined", procName, 1);

    if (pixcmapToArrays(cmap, &rmap, &gmap, &bmap))
        return ERROR_INT("colormap arrays not made", procName, 1);
    n = pixcmapGetCount(cmap);
    for (i = 0; i < n; i++) {
        if ((rmap[i] != gmap[i]) || (rmap[i] != bmap[i])) {
            *pcolor = TRUE;
            break;
        }
    }

    FREE(rmap);
    FREE(gmap);
    FREE(bmap);
    return 0;
}
/*!
 *  pixcmapGetRankIntensity()
 *
 *      Input:  cmap
 *              rankval (0.0 for darkest, 1.0 for lightest color)
 *              &index (<return> the index into the colormap that
 *                      corresponds to the rank intensity color)
 *      Return: 0 if OK, 1 on error
 */
l_int32
pixcmapGetRankIntensity(PIXCMAP    *cmap,
                        l_float32   rankval,
                        l_int32    *pindex)
{
l_int32  n, i, rval, gval, bval, rankindex;
NUMA    *na, *nasort;

    PROCNAME("pixcmapGetRankIntensity");

    if (!pindex)
        return ERROR_INT("&index not defined", procName, 1);
    *pindex = 0;
    if (!cmap)
        return ERROR_INT("cmap not defined", procName, 1);
    if (rankval < 0.0 || rankval > 1.0)
        return ERROR_INT("rankval not in [0.0 ... 1.0]", procName, 1);

    n = pixcmapGetCount(cmap);
    na = numaCreate(n);
    for (i = 0; i < n; i++) {
        pixcmapGetColor(cmap, i, &rval, &gval, &bval);
        numaAddNumber(na, rval + gval + bval);
    }
    nasort = numaGetSortIndex(na, L_SORT_INCREASING);
    rankindex = (l_int32)(rankval * (n - 1) + 0.5);
    numaGetIValue(nasort, rankindex, pindex);

    numaDestroy(&na);
    numaDestroy(&nasort);
    return 0;
}
/*!
 *  pixcmapContrastTRC()
 *
 *      Input:  colormap
 *              factor (generally between 0.0 (no enhancement)
 *                      and 1.0, but can be larger than 1.0)
 *      Return: 0 if OK; 1 on error
 *
 *  Notes:
 *      - in-place transform
 *      - see pixContrastTRC() and numaContrastTRC() in enhance.c for
 *        description and use of transform
 */
l_int32
pixcmapContrastTRC(PIXCMAP   *cmap,
                   l_float32  factor)
{
l_int32   i, ncolors, rval, gval, bval, trval, tgval, tbval;
NUMA     *nac;

    PROCNAME("pixcmapContrastTRC");

    if (!cmap)
        return ERROR_INT("cmap not defined", procName, 1);
    if (factor < 0.0) {
        L_WARNING("factor must be >= 0.0; setting to 0.0", procName);
        factor = 0.0;
    }

    if ((nac = numaContrastTRC(factor)) == NULL)
        return ERROR_INT("nac not made", procName, 1);

    ncolors = pixcmapGetCount(cmap);
    for (i = 0; i < ncolors; i++) {
        pixcmapGetColor(cmap, i, &rval, &gval, &bval);
        numaGetIValue(nac, rval, &trval);
        numaGetIValue(nac, gval, &tgval);
        numaGetIValue(nac, bval, &tbval);
        pixcmapResetColor(cmap, i, trval, tgval, tbval);
    }

    numaDestroy(&nac);
    return 0;
}
示例#6
0
文件: maptest.c 项目: chewi/leptonica
static void
DisplayMapHistogram(L_AMAP      *m,
                    PIXCMAP     *cmap,
                    const char  *rootname)
{
char      buf[128];
l_int32   i, n, ival;
l_uint32  val32;
NUMA     *na;
RB_TYPE   key;
RB_TYPE  *pval;

    n = pixcmapGetCount(cmap);
    na = numaCreate(n);
    for (i = 0; i < n; i++) {
        pixcmapGetColor32(cmap, i, &val32);
        key.utype = val32;
        pval = l_amapFind(m, key);
        if (pval) {
            ival = pval->itype;
            numaAddNumber(na, ival);
        }
    }
    gplotSimple1(na, GPLOT_PNG, rootname, NULL);
    snprintf(buf, sizeof(buf), "%s.png", rootname);
    l_fileDisplay(buf, 700, 0, 1.0);
    numaDestroy(&na);
    return;
}
/*!
 *  pixcmapToRGBTable()
 *
 *      Input:  colormap
 *              &tab (<return> table of rgba values for the colormap)
 *              &ncolors (<optional return> size of table)
 *      Return: 0 if OK; 1 on error
 */
l_int32
pixcmapToRGBTable(PIXCMAP    *cmap,
                  l_uint32  **ptab,
                  l_int32    *pncolors)
{
l_int32    i, ncolors, rval, gval, bval;
l_uint32  *tab;

    PROCNAME("pixcmapToRGBTable");

    if (!ptab)
        return ERROR_INT("&tab not defined", procName, 1);
    *ptab = NULL;
    if (!cmap)
        return ERROR_INT("cmap not defined", procName, 1);

    ncolors = pixcmapGetCount(cmap);
    if (pncolors)
        *pncolors = ncolors;
    if ((tab = (l_uint32 *)CALLOC(ncolors, sizeof(l_uint32))) == NULL)
        return ERROR_INT("tab not made", procName, 1);
    *ptab = tab;
   
    for (i = 0; i < ncolors; i++) {
        pixcmapGetColor(cmap, i, &rval, &gval, &bval);
        composeRGBPixel(rval, gval, bval, &tab[i]);
    }

/*    for (i = 0; i < ncolors; i++)
        fprintf(stderr, "Color[%d] = %x\n", i, tab[i]); */

    return 0;
}
示例#8
0
文件: maptest.c 项目: AAAyag/tess-two
static void
DisplayMapHistogram(L_AMAP      *m,
                    PIXCMAP     *cmap,
                    const char  *rootname)
{
l_int32   i, n, ival;
l_uint32  val32;
NUMA     *na;
RB_TYPE   key;
RB_TYPE  *pval;

    n = pixcmapGetCount(cmap);
    na = numaCreate(n);
    for (i = 0; i < n; i++) {
        pixcmapGetColor32(cmap, i, &val32);
        key.utype = val32;
        pval = l_amapFind(m, key);
        if (pval) {
            ival = pval->itype;
            numaAddNumber(na, ival);
        }
    }
/*    numaWrite("/tmp/lept/map/map.na", na); */
    gplotSimple1(na, GPLOT_X11, rootname, NULL);
    numaDestroy(&na);
    return;
}
/*!
 *  pixcmapGetIndex()
 *
 *      Input:  cmap
 *              rval, gval, bval (colormap colors to search for; each number
 *                                is in range [0, ... 255])
 *              &index (<return>)
 *      Return: 0 if found, 1 if not found (caller must check)
 */
l_int32
pixcmapGetIndex(PIXCMAP  *cmap,
                l_int32   rval,
                l_int32   gval,
                l_int32   bval,
                l_int32  *pindex)
{
l_int32     n, i;
RGBA_QUAD  *cta;

    PROCNAME("pixcmapGetIndex");

    if (!pindex)
        return ERROR_INT("&index not defined", procName, 1);
    *pindex = 0;
    if (!cmap)
        return ERROR_INT("cmap not defined", procName, 1);
    n = pixcmapGetCount(cmap);

    cta = (RGBA_QUAD *)cmap->array;
    for (i = 0; i < n; i++) {
        if (rval == cta[i].red && gval == cta[i].green && bval == cta[i].blue) {
            *pindex = i;
            return 0;
        }
    }

    return 1;
}
示例#10
0
/*!
 *  pixcmapCountGrayColors()
 *
 *      Input:  cmap
 *              &ngray (<return> number of gray colors)
 *      Return: 0 if OK, 1 on error
 *
 *  Notes:
 *      (1) This counts the unique gray colors, including black and white.
 */
l_int32
pixcmapCountGrayColors(PIXCMAP  *cmap,
                       l_int32  *pngray)
{
l_int32   n, i, rval, gval, bval, count;
l_int32  *array;

    PROCNAME("pixcmapCountGrayColors");

    if (!pngray)
        return ERROR_INT("&ngray not defined", procName, 1);
    *pngray = 0;
    if (!cmap)
        return ERROR_INT("cmap not defined", procName, 1);

    array = (l_int32 *)CALLOC(256, sizeof(l_int32));
    n = pixcmapGetCount(cmap);
    count = 0;
    for (i = 0; i < n; i++) {
        pixcmapGetColor(cmap, i, &rval, &gval, &bval);
        if ((rval == gval) && (rval == bval) && (array[rval] == 0)) {
            array[rval] = 1;
            count++;
        }
    }

    FREE(array);
    *pngray = count;
    return 0;
}
示例#11
0
void
CmapEqual(PIXCMAP *cmap1, PIXCMAP *cmap2, l_int32 *pequal)
{
l_int32  n1, n2, i, rval1, gval1, bval1, aval1, rval2, gval2, bval2, aval2;

    *pequal = FALSE;
    n1 = pixcmapGetCount(cmap1);
    n2 = pixcmapGetCount(cmap1);
    if (n1 != n2) return;

    for (i = 0; i < n1; i++) {
        pixcmapGetRGBA(cmap1, i, &rval1, &gval1, &bval1, &aval1);
        pixcmapGetRGBA(cmap2, i, &rval2, &gval2, &bval2, &aval2);
        if ((rval1 != rval2) || (gval1 != gval2) ||
            (bval1 != bval2) || (aval1 != aval2))
            return;
    }
    *pequal = TRUE;
    return;
}
示例#12
0
/*!
 * \brief   pixColorSegmentCluster()
 *
 * \param[in]    pixs  32 bpp; 24-bit color
 * \param[in]    maxdist max euclidean dist to existing cluster
 * \param[in]    maxcolors max number of colors allowed in first pass
 * \param[in]    debugflag  1 for debug output; 0 otherwise
 * \return  pixd 8 bit with colormap, or NULL on error
 *
 * <pre>
 * Notes:
 *      (1) This is phase 1.  See description in pixColorSegment().
 *      (2) Greedy unsupervised classification.  If the limit 'maxcolors'
 *          is exceeded, the computation is repeated with a larger
 *          allowed cluster size.
 *      (3) On each successive iteration, 'maxdist' is increased by a
 *          constant factor.  See comments in pixColorSegment() for
 *          a guideline on parameter selection.
 *          Note that the diagonal of the 8-bit rgb color cube is about
 *          440, so for 'maxdist' = 440, you are guaranteed to get 1 color!
 * </pre>
 */
PIX *
pixColorSegmentCluster(PIX     *pixs,
                       l_int32  maxdist,
                       l_int32  maxcolors,
                       l_int32  debugflag)
{
l_int32   w, h, newmaxdist, ret, niters, ncolors, success;
PIX      *pixd;
PIXCMAP  *cmap;

    PROCNAME("pixColorSegmentCluster");

    if (!pixs)
        return (PIX *)ERROR_PTR("pixs not defined", procName, NULL);
    if (pixGetDepth(pixs) != 32)
        return (PIX *)ERROR_PTR("must be rgb color", procName, NULL);

    pixGetDimensions(pixs, &w, &h, NULL);
    if ((pixd = pixCreate(w, h, 8)) == NULL)
        return (PIX *)ERROR_PTR("pixd not made", procName, NULL);
    cmap = pixcmapCreate(8);
    pixSetColormap(pixd, cmap);
    pixCopyResolution(pixd, pixs);

    newmaxdist = maxdist;
    niters = 0;
    success = TRUE;
    while (1) {
        ret = pixColorSegmentTryCluster(pixd, pixs, newmaxdist,
                                        maxcolors, debugflag);
        niters++;
        if (!ret) {
            ncolors = pixcmapGetCount(cmap);
            if (debugflag)
                L_INFO("Success with %d colors after %d iters\n", procName,
                       ncolors, niters);
            break;
        }
        if (niters == MAX_ALLOWED_ITERATIONS) {
            L_WARNING("too many iters; newmaxdist = %d\n",
                      procName, newmaxdist);
            success = FALSE;
            break;
        }
        newmaxdist = (l_int32)(DIST_EXPAND_FACT * (l_float32)newmaxdist);
    }

    if (!success) {
        pixDestroy(&pixd);
        return (PIX *)ERROR_PTR("failure in phase 1", procName, NULL);
    }

    return pixd;
}
示例#13
0
l_int32 main(int    argc,
             char **argv)
{
l_uint32     *colors;
l_int32       ncolors;
PIX          *pix1, *pix2, *pix3;
L_REGPARAMS  *rp;

    if (regTestSetup(argc, argv, &rp))
        return 1;

        /* Find the most populated colors */
    pix1 = pixRead("fish24.jpg");
    pixGetMostPopulatedColors(pix1, 2, 3, 10, &colors, NULL);
    pix2 = pixDisplayColorArray(colors, 10, 190, 5, 1);
    pixDisplayWithTitle(pix2, 0, 0, NULL, rp->display);
    regTestWritePixAndCheck(rp, pix2, IFF_PNG);  /* 0 */
    lept_free(colors);
    pixDestroy(&pix2);

        /* Do a simple color quantization with sigbits = 2 */
    pix2 = pixSimpleColorQuantize(pix1, 2, 3, 10);
    pixDisplayWithTitle(pix2, 0, 400, NULL, rp->display);
    regTestWritePixAndCheck(rp, pix2, IFF_PNG);  /* 1 */
    pix3 = pixRemoveColormap(pix2, REMOVE_CMAP_TO_FULL_COLOR);
    regTestComparePix(rp, pix2, pix3);  /* 2 */
    pixNumColors(pix3, 1, &ncolors);
    regTestCompareValues(rp, ncolors, 10, 0.0);  /* 3 */
    pixDestroy(&pix1);
    pixDestroy(&pix2);
    pixDestroy(&pix3);

        /* Do a simple color quantization with sigbits = 3 */
    pix1 = pixRead("wyom.jpg");
    pixNumColors(pix1, 1, &ncolors);  /* >255, so should give 0 */
    regTestCompareValues(rp, ncolors, 0, 0.0);  /* 4 */
    pix2 = pixSimpleColorQuantize(pix1, 3, 3, 20);
    pixDisplayWithTitle(pix2, 1000, 0, NULL, rp->display);
    regTestWritePixAndCheck(rp, pix2, IFF_PNG);  /* 5 */
    ncolors = pixcmapGetCount(pixGetColormap(pix2));
    regTestCompareValues(rp, ncolors, 20, 0.0);  /* 6 */
    pixDestroy(&pix1);
    pixDestroy(&pix2);

        /* Find the number of perceptually significant gray intensities */
    pix1 = pixRead("marge.jpg");
    pix2 = pixConvertTo8(pix1, 0);
    pixNumSignificantGrayColors(pix2, 20, 236, 0.0001, 1, &ncolors);
    regTestCompareValues(rp, ncolors, 219, 0.0);  /* 7 */
    pixDestroy(&pix1);
    pixDestroy(&pix2);

    return regTestCleanup(rp);
}
示例#14
0
/*!
 * \brief   pixColorSegmentClean()
 *
 * \param[in]    pixs  8 bpp, colormapped
 * \param[in]    selsize for closing
 * \param[in]    countarray ptr to array containing the number of pixels
 *                          found in each color in the colormap
 * \return  0 if OK, 1 on error
 *
 * <pre>
 * Notes:
 *      (1) This operation is in-place.
 *      (2) This is phase 3 of color segmentation.  It is the first
 *          part of a two-step noise removal process.  Colors with a
 *          large population are closed first; this operation absorbs
 *          small sets of intercolated pixels of a different color.
 * </pre>
 */
l_ok
pixColorSegmentClean(PIX      *pixs,
                     l_int32   selsize,
                     l_int32  *countarray)
{
l_int32    i, ncolors, val;
l_uint32   val32;
NUMA      *na, *nasi;
PIX       *pixt1, *pixt2;
PIXCMAP   *cmap;

    PROCNAME("pixColorSegmentClean");

    if (!pixs)
        return ERROR_INT("pixs not defined", procName, 1);
    if (pixGetDepth(pixs) != 8)
        return ERROR_INT("pixs not 8 bpp", procName, 1);
    if ((cmap = pixGetColormap(pixs)) == NULL)
        return ERROR_INT("cmap not found", procName, 1);
    if (!countarray)
        return ERROR_INT("countarray not defined", procName, 1);
    if (selsize <= 1)
        return 0;  /* nothing to do */

        /* Sort colormap indices in decreasing order of pixel population */
    ncolors = pixcmapGetCount(cmap);
    na = numaCreate(ncolors);
    for (i = 0; i < ncolors; i++)
        numaAddNumber(na, countarray[i]);
    nasi = numaGetSortIndex(na, L_SORT_DECREASING);
    numaDestroy(&na);
    if (!nasi)
        return ERROR_INT("nasi not made", procName, 1);

        /* For each color, in order of decreasing population,
         * do a closing and absorb the added pixels.  Note that
         * if the closing removes pixels at the border, they'll
         * still appear in the xor and will be properly (re)set. */
    for (i = 0; i < ncolors; i++) {
        numaGetIValue(nasi, i, &val);
        pixt1 = pixGenerateMaskByValue(pixs, val, 1);
        pixt2 = pixCloseSafeCompBrick(NULL, pixt1, selsize, selsize);
        pixXor(pixt2, pixt2, pixt1);  /* pixels to be added to type 'val' */
        pixcmapGetColor32(cmap, val, &val32);
        pixSetMasked(pixs, pixt2, val32);  /* add them */
        pixDestroy(&pixt1);
        pixDestroy(&pixt2);
    }
    numaDestroy(&nasi);
    return 0;
}
示例#15
0
/*!
 *  pixcmapGetExtremeValue()
 *
 *      Input:  cmap
 *              type (L_SELECT_MIN or L_SELECT_MAX)
 *              &rval (<optional return> red component)
 *              &gval (<optional return> green component)
 *              &bval (<optional return> blue component)
 *      Return: 0 if OK, 1 on error
 *
 *  Notes:
 *      (1) Returns for selected components the extreme value
 *          (either min or max) of the color component that is
 *          found in the colormap.
 */
l_int32
pixcmapGetExtremeValue(PIXCMAP  *cmap,
                       l_int32   type,
                       l_int32  *prval,
                       l_int32  *pgval,
                       l_int32  *pbval)
{
l_int32  i, n, rval, gval, bval, extrval, extgval, extbval;

    PROCNAME("pixcmapGetExtremeValue");

    if (!prval && !pgval && !pbval)
        return ERROR_INT("no result requested for return", procName, 1);
    if (prval) *prval = 0;
    if (pgval) *pgval = 0;
    if (pbval) *pbval = 0;
    if (!cmap)
        return ERROR_INT("cmap not defined", procName, 1);
    if (type != L_SELECT_MIN && type != L_SELECT_MAX)
        return ERROR_INT("invalid type", procName, 1);

    if (type == L_SELECT_MIN) {
        extrval = 100000;
        extgval = 100000;
        extbval = 100000;
    }
    else {
        extrval = 0;
        extgval = 0;
        extbval = 0;
    }

    n = pixcmapGetCount(cmap);
    for (i = 0; i < n; i++) {
        pixcmapGetColor(cmap, i, &rval, &gval, &bval);
        if ((type == L_SELECT_MIN && rval < extrval) ||
            (type == L_SELECT_MAX && rval > extrval))
            extrval = rval;
        if ((type == L_SELECT_MIN && gval < extgval) ||
            (type == L_SELECT_MAX && gval > extgval))
            extgval = gval;
        if ((type == L_SELECT_MIN && bval < extbval) ||
            (type == L_SELECT_MAX && bval > extbval))
            extbval = bval;
    }
    if (prval) *prval = extrval;
    if (pgval) *pgval = extgval;
    if (pbval) *pbval = extbval;
    return 0;
}
示例#16
0
/*!
 *  setColormap(LPBITMAPINFO pbmi, PIXCMAP *cmap)
 *
 *      Input:  pbmi (pointer to a BITMAPINFO describing a DIB)
 *              cmap (leptonica colormap)
 *      Return: number of colors in cmap
 */
static int
setColormap(LPBITMAPINFO  pbmi,
            PIXCMAP      *cmap)
{
l_int32  i, nColors, rval, gval, bval;

    nColors = pixcmapGetCount(cmap);
    for (i = 0; i < nColors; i++) {
        pixcmapGetColor(cmap, i, &rval, &gval, &bval);
        pbmi->bmiColors[i].rgbRed = rval;
        pbmi->bmiColors[i].rgbGreen = gval;
        pbmi->bmiColors[i].rgbBlue = bval;
        pbmi->bmiColors[i].rgbReserved = 0;
    }
    pbmi->bmiHeader.biClrUsed = nColors;
    return nColors;
}
示例#17
0
/*!
 *  pixcmapConvertHSVToRGB()
 *
 *      Input:  colormap
 *      Return: 0 if OK; 1 on error
 *
 *  Notes:
 *      - in-place transform
 *      - See convertRGBToHSV() for def'n of HSV space.
 *      - replaces: h --> r, s --> g, v --> b
 */
l_int32
pixcmapConvertHSVToRGB(PIXCMAP  *cmap)
{
l_int32   i, ncolors, rval, gval, bval, hval, sval, vval;

    PROCNAME("pixcmapConvertHSVToRGB");

    if (!cmap)
        return ERROR_INT("cmap not defined", procName, 1);

    ncolors = pixcmapGetCount(cmap);
    for (i = 0; i < ncolors; i++) {
        pixcmapGetColor(cmap, i, &hval, &sval, &vval);
        convertHSVToRGB(hval, sval, vval, &rval, &gval, &bval);
        pixcmapResetColor(cmap, i, rval, gval, bval);
    }
    return 0;
}
示例#18
0
/*!
 *  pixcmapColorToGray()
 *
 *      Input:  cmap
 *              rwt, gwt, bwt  (non-negative; these should add to 1.0)
 *      Return: cmap (gray), or null on error
 *
 *  Notes:
 *      (1) This creates a gray colormap from an arbitrary colormap.
 *      (2) In use, attach the output gray colormap to the pix
 *          (or a copy of it) that provided the input colormap.
 */
PIXCMAP *
pixcmapColorToGray(PIXCMAP   *cmaps,
                   l_float32  rwt,
                   l_float32  gwt,
                   l_float32  bwt)
{
l_int32    i, n, rval, gval, bval, val;
l_float32  sum;
PIXCMAP   *cmapd;

    PROCNAME("pixcmapColorToGray");

    if (!cmaps)
        return (PIXCMAP *)ERROR_PTR("cmaps not defined", procName, NULL);
    if (rwt < 0.0 || gwt < 0.0 || bwt < 0.0)
        return (PIXCMAP *)ERROR_PTR("weights not all >= 0.0", procName, NULL);

        /* Make sure the sum of weights is 1.0; otherwise, you can get
         * overflow in the gray value. */
    sum = rwt + gwt + bwt;
    if (sum == 0.0) {
        L_WARNING("all weights zero; setting equal to 1/3", procName);
        rwt = gwt = bwt = 0.33333;
        sum = 1.0;
    }
    if (L_ABS(sum - 1.0) > 0.0001) {  /* maintain ratios with sum == 1.0 */
        L_WARNING("weights don't sum to 1; maintaining ratios", procName);
        rwt = rwt / sum;
        gwt = gwt / sum;
        bwt = bwt / sum;
    }

    cmapd = pixcmapCopy(cmaps);
    n = pixcmapGetCount(cmapd);
    for (i = 0; i < n; i++) {
        pixcmapGetColor(cmapd, i, &rval, &gval, &bval);
        val = (l_int32)(rwt * rval + gwt * gval + bwt * bval + 0.5);
        pixcmapResetColor(cmapd, i, val, val, val);
    }
        
    return cmapd;
}
示例#19
0
/*!
 *  pixcmapGetNearestIndex()
 *
 *      Input:  cmap
 *              rval, gval, bval (colormap colors to search for; each number
 *                                is in range [0, ... 255])
 *              &index (<return> the index of the nearest color)
 *      Return: 0 if OK, 1 on error (caller must check)
 *
 *  Notes:
 *      (1) Returns the index of the exact color if possible, otherwise the
 *          index of the color closest to the target color.
 *      (2) Nearest color is that which is the least sum-of-squares distance
 *          from the target color.
 */
l_int32
pixcmapGetNearestIndex(PIXCMAP  *cmap,
                       l_int32   rval,
                       l_int32   gval,
                       l_int32   bval,
                       l_int32  *pindex)
{
l_int32     i, n, delta, dist, mindist;
RGBA_QUAD  *cta;

    PROCNAME("pixcmapGetNearestIndex");

    if (!pindex)
        return ERROR_INT("&index not defined", procName, 1);
    *pindex = UNDEF;
    if (!cmap)
        return ERROR_INT("cmap not defined", procName, 1);

    if ((cta = (RGBA_QUAD *)cmap->array) == NULL)
        return ERROR_INT("cta not defined(!)", procName, 1);
    n = pixcmapGetCount(cmap);

    mindist = 3 * 255 * 255 + 1;
    for (i = 0; i < n; i++) {
        delta = cta[i].red - rval;
        dist = delta * delta;
        delta = cta[i].green - gval;
        dist += delta * delta;
        delta = cta[i].blue - bval;
        dist += delta * delta;
        if (dist < mindist) {
            *pindex = i; 
            if (dist == 0)
                break;
            mindist = dist;
        }
    }

    return 0;
}
示例#20
0
/*!
 *  pixcmapSerializeToMemory()
 *
 *      Input:  colormap
 *              cpc (components/color: 3 for rgb, 4 for rgba)
 *              &ncolors (<return> number of colors in table)
 *              &data (<return> binary string, 3 or 4 bytes per color)
 *              &nbytes (<return> size of data)
 *      Return: 0 if OK; 1 on error
 *
 *  Notes:
 *      (1) If @cpc == 4, we leave room for the alpha channel
 *          value in each color entry, but it is set to 0.
 */
l_int32
pixcmapSerializeToMemory(PIXCMAP   *cmap,
                         l_int32    cpc,
                         l_int32   *pncolors,
                         l_uint8  **pdata,
                         l_int32   *pnbytes)
{
l_int32   i, ncolors, rval, gval, bval;
l_uint8  *data;

    PROCNAME("pixcmapSerializeToMemory");

    if (!pdata)
        return ERROR_INT("&data not defined", procName, 1);
    *pdata = NULL;
    if (!pncolors || !pnbytes)
        return ERROR_INT("&ncolors and &nbytes not defined", procName, 1);
    *pncolors = *pnbytes = 0;
    if (!cmap)
        return ERROR_INT("cmap not defined", procName, 1);
    if (cpc != 3 && cpc != 4)
        return ERROR_INT("cpc not 3 or 4", procName, 1);

    ncolors = pixcmapGetCount(cmap);
    *pncolors = ncolors;
    *pnbytes = cpc * ncolors;
    if ((data = (l_uint8 *)CALLOC(cpc * ncolors, sizeof(l_uint8))) == NULL)
        return ERROR_INT("data not made", procName, 1);
    *pdata = data;

    for (i = 0; i < ncolors; i++) {
        pixcmapGetColor(cmap, i, &rval, &gval, &bval);
        data[cpc * i] = rval;
        data[cpc * i + 1] = gval;
        data[cpc * i + 2] = bval;
    }
    return 0;
}
示例#21
0
/*!
 *  pixcmapGammaTRC()
 *
 *      Input:  colormap
 *              gamma (gamma correction; must be > 0.0)
 *              minval  (input value that gives 0 for output; can be < 0)
 *              maxval  (input value that gives 255 for output; can be > 255)
 *      Return: 0 if OK; 1 on error
 *
 *  Notes:
 *      - in-place transform
 *      - see pixGammaTRC() and numaGammaTRC() in enhance.c for
 *        description and use of transform
 */
l_int32
pixcmapGammaTRC(PIXCMAP   *cmap,
                l_float32  gamma,
                l_int32    minval,
                l_int32    maxval)
{
l_int32   rval, gval, bval, trval, tgval, tbval, i, ncolors;
NUMA     *nag;

    PROCNAME("pixcmapGammaTRC");

    if (!cmap)
        return ERROR_INT("cmap not defined", procName, 1);
    if (gamma <= 0.0) {
        L_WARNING("gamma must be > 0.0; setting to 1.0", procName);
        gamma = 1.0;
    }
    if (minval >= maxval)
        return ERROR_INT("minval not < maxval", procName, 1);

    if (gamma == 1.0 && minval == 0 && maxval == 255)  /* no-op */
        return 0;

    if ((nag = numaGammaTRC(gamma, minval, maxval)) == NULL)
        return ERROR_INT("nag not made", procName, 1);

    ncolors = pixcmapGetCount(cmap);
    for (i = 0; i < ncolors; i++) {
        pixcmapGetColor(cmap, i, &rval, &gval, &bval);
        numaGetIValue(nag, rval, &trval);
        numaGetIValue(nag, gval, &tgval);
        numaGetIValue(nag, bval, &tbval);
        pixcmapResetColor(cmap, i, trval, tgval, tbval);
    }

    numaDestroy(&nag);
    return 0;
}
示例#22
0
static PIX *
ReconstructByValue(L_REGPARAMS  *rp,
                   const char   *fname)
{
l_int32   i, n, rval, gval, bval;
PIX      *pixs, *pixm, *pixd;
PIXCMAP  *cmap;

    pixs = pixRead(fname);
    cmap = pixGetColormap(pixs);
    n = pixcmapGetCount(cmap);
    pixd = pixCreateTemplate(pixs);
    for (i = 0; i < n; i++) {
        pixm = pixGenerateMaskByValue(pixs, i, 1);
        pixcmapGetColor(cmap, i, &rval, &gval, &bval);
        pixSetMaskedCmap(pixd, pixm, 0, 0, rval, gval, bval);
        pixDestroy(&pixm);
    }

    regTestComparePix(rp, pixs, pixd);
    pixDestroy(&pixs);
    return pixd;
}
示例#23
0
static PIX *
FakeReconstructByBand(L_REGPARAMS  *rp,
                      const char   *fname)
{
l_int32   i, jlow, jup, n, nbands;
l_int32   rval1, gval1, bval1, rval2, gval2, bval2, rval, gval, bval;
PIX      *pixs, *pixm, *pixd;
PIXCMAP  *cmaps, *cmapd;

    pixs = pixRead(fname);
    cmaps = pixGetColormap(pixs);
    n = pixcmapGetCount(cmaps);
    nbands = (n + 1) / 2;
    pixd = pixCreateTemplate(pixs);
    cmapd = pixcmapCreate(pixGetDepth(pixs));
    pixSetColormap(pixd, cmapd);
    for (i = 0; i < nbands; i++) {
        jlow = 2 * i;
        jup = L_MIN(jlow + 1, n - 1);
        pixm = pixGenerateMaskByBand(pixs, jlow, jup, 1, 1);

            /* Get average color in the band */
        pixcmapGetColor(cmaps, jlow, &rval1, &gval1, &bval1);
        pixcmapGetColor(cmaps, jup, &rval2, &gval2, &bval2);
        rval = (rval1 + rval2) / 2;
        gval = (gval1 + gval2) / 2;
        bval = (bval1 + bval2) / 2;

        pixcmapAddColor(cmapd, rval, gval, bval);
        pixSetMaskedCmap(pixd, pixm, 0, 0, rval, gval, bval);
        pixDestroy(&pixm);
    }

    pixDestroy(&pixs);
    return pixd;
}
示例#24
0
/*!
 *  pixcmapGetMinDepth()
 *
 *      Input:  cmap
 *              &mindepth (<return> minimum depth to support the colormap)
 *      Return: 0 if OK, 1 on error
 *
 *  Notes:
 *      (1) On error, &mindepth is returned as 0.
 */
l_int32
pixcmapGetMinDepth(PIXCMAP  *cmap,
                   l_int32  *pmindepth)
{
l_int32  ncolors;

    PROCNAME("pixcmapGetMinDepth");

    if (!pmindepth)
        return ERROR_INT("&mindepth not defined", procName, 1);
    *pmindepth = 0;
    if (!cmap)
        return ERROR_INT("cmap not defined", procName, 1);

    ncolors = pixcmapGetCount(cmap);
    if (ncolors <= 4)
        *pmindepth = 2;
    else if (ncolors <= 16)
        *pmindepth = 4;
    else  /* ncolors > 16 */
        *pmindepth = 8;

    return 0;
}
示例#25
0
/*!
 *  pixcmapGetNearestGrayIndex()
 *
 *      Input:  cmap
 *              val (gray value to search for; in range [0, ... 255])
 *              &index (<return> the index of the nearest color)
 *      Return: 0 if OK, 1 on error (caller must check)
 *
 *  Notes:
 *      (1) This should be used on gray colormaps.  It uses only the
 *          green value of the colormap.
 *      (2) Returns the index of the exact color if possible, otherwise the
 *          index of the color closest to the target color.
 */
l_int32
pixcmapGetNearestGrayIndex(PIXCMAP  *cmap,
                           l_int32   val,
                           l_int32  *pindex)
{
l_int32     i, n, dist, mindist;
RGBA_QUAD  *cta;

    PROCNAME("pixcmapGetNearestGrayIndex");

    if (!pindex)
        return ERROR_INT("&index not defined", procName, 1);
    *pindex = 0;
    if (!cmap)
        return ERROR_INT("cmap not defined", procName, 1);
    if (val < 0 || val > 255)
        return ERROR_INT("val not in [0 ... 255]", procName, 1);

    if ((cta = (RGBA_QUAD *)cmap->array) == NULL)
        return ERROR_INT("cta not defined(!)", procName, 1);
    n = pixcmapGetCount(cmap);

    mindist = 256;
    for (i = 0; i < n; i++) {
        dist = cta[i].green - val;
        dist = L_ABS(dist);
        if (dist < mindist) {
            *pindex = i;
            if (dist == 0)
                break;
            mindist = dist;
        }
    }

    return 0;
}
示例#26
0
/*!
 *  pixcmapToArrays()
 *
 *      Input:  colormap
 *              &rmap, &gmap, &bmap  (<return> colormap arrays)
 *      Return: 0 if OK; 1 on error
 */
LEPTONICA_EXPORT l_int32
pixcmapToArrays(PIXCMAP   *cmap,
                l_int32  **prmap,
                l_int32  **pgmap,
                l_int32  **pbmap)
{
l_int32    *rmap, *gmap, *bmap;
l_int32     i, ncolors;
RGBA_QUAD  *cta;

    PROCNAME("pixcmapToArrays");

    if (!prmap || !pgmap || !pbmap)
        return ERROR_INT("&rmap, &gmap, &bmap not all defined", procName, 1);
    *prmap = *pgmap = *pbmap = NULL;
    if (!cmap)
        return ERROR_INT("cmap not defined", procName, 1);

    ncolors = pixcmapGetCount(cmap);
    if (((rmap = (l_int32 *)CALLOC(ncolors, sizeof(l_int32))) == NULL) ||
        ((gmap = (l_int32 *)CALLOC(ncolors, sizeof(l_int32))) == NULL) ||
        ((bmap = (l_int32 *)CALLOC(ncolors, sizeof(l_int32))) == NULL))
            return ERROR_INT("calloc fail for *map", procName, 1);
    *prmap = rmap;
    *pgmap = gmap;
    *pbmap = bmap;

    cta = (RGBA_QUAD *)cmap->array;
    for (i = 0; i < ncolors; i++) {
        rmap[i] = cta[i].red;
        gmap[i] = cta[i].green;
        bmap[i] = cta[i].blue;
    }

    return 0;
}
示例#27
0
int main(int    argc,
         char **argv)
{
l_uint8      *data;
l_int32       w, h, n1, n2, n, i, minval, maxval;
l_int32       ncolors, rval, gval, bval, equal;
l_int32      *rmap, *gmap, *bmap;
l_uint32      color;
l_float32     gamma;
BOX          *box;
FILE         *fp;
PIX          *pix1, *pix2, *pix3, *pix4, *pix5, *pix6;
PIX          *pixs, *pixb, *pixg, *pixc, *pixd;
PIX          *pixg2, *pixcs1, *pixcs2, *pixd1, *pixd2;
PIXA         *pixa, *pixa2, *pixa3;
PIXCMAP      *cmap, *cmap2;
RGBA_QUAD    *cta;
L_REGPARAMS  *rp;

    if (regTestSetup(argc, argv, &rp))
        return 1;

    /* ------------------------ (1) ----------------------------*/
        /* Blend with a white background */
    pix1 = pixRead("books_logo.png");
    pixDisplayWithTitle(pix1, 100, 0, NULL, rp->display);
    pix2 = pixAlphaBlendUniform(pix1, 0xffffff00);
    pixDisplayWithTitle(pix2, 100, 150, NULL, rp->display);
    regTestWritePixAndCheck(rp, pix1, IFF_PNG);  /* 0 */
    regTestWritePixAndCheck(rp, pix2, IFF_PNG);  /* 1 */

        /* Generate an alpha layer based on the white background */
    pix3 = pixSetAlphaOverWhite(pix2);
    pixSetSpp(pix3, 3);
    pixWrite("/tmp/alphaops.2.png", pix3, IFF_PNG);  /* without alpha */
    regTestCheckFile(rp, "/tmp/alphaops.2.png");   /* 2 */
    pixSetSpp(pix3, 4);
    regTestWritePixAndCheck(rp, pix3, IFF_PNG);  /* 3, with alpha */
    pixDisplayWithTitle(pix3, 100, 300, NULL, rp->display);

        /* Render on a light yellow background */
    pix4 = pixAlphaBlendUniform(pix3, 0xffffe000);
    regTestWritePixAndCheck(rp, pix4, IFF_PNG);  /* 4 */
    pixDisplayWithTitle(pix4, 100, 450, NULL, rp->display);
    pixDestroy(&pix1);
    pixDestroy(&pix2);
    pixDestroy(&pix3);
    pixDestroy(&pix4);

    /* ------------------------ (2) ----------------------------*/
    lept_rmdir("alpha");
    lept_mkdir("alpha");
        /* Make the transparency (alpha) layer.
         * pixs is the mask.  We turn it into a transparency (alpha)
         * layer by converting to 8 bpp.  A small convolution fuzzes
         * the mask edges so that you don't see the pixels. */
    pixs = pixRead("feyn-fract.tif");
    pixGetDimensions(pixs, &w, &h, NULL);
    pixg = pixConvert1To8(NULL, pixs, 0, 255);
    pixg2 = pixBlockconvGray(pixg, NULL, 1, 1);
    regTestWritePixAndCheck(rp, pixg2, IFF_JFIF_JPEG);  /* 5 */
    pixDisplayWithTitle(pixg2, 0, 0, "alpha", rp->display);

        /* Make the viewable image.
         * pixc is the image that we see where the alpha layer is
         * opaque -- i.e., greater than 0.  Scale it to the same
         * size as the mask.  To visualize what this will look like
         * when displayed over a black background, create the black
         * background image, pixb, and do the blending with pixcs1
         * explicitly using the alpha layer pixg2. */
    pixc = pixRead("tetons.jpg");
    pixcs1 = pixScaleToSize(pixc, w, h);
    regTestWritePixAndCheck(rp, pixcs1, IFF_JFIF_JPEG);  /* 6 */
    pixDisplayWithTitle(pixcs1, 300, 0, "viewable", rp->display);
    pixb = pixCreateTemplate(pixcs1);  /* black */
    pixd1 = pixBlendWithGrayMask(pixb, pixcs1, pixg2, 0, 0);
    regTestWritePixAndCheck(rp, pixd1, IFF_JFIF_JPEG);  /* 7 */
    pixDisplayWithTitle(pixd1, 600, 0, "alpha-blended 1", rp->display);

        /* Embed the alpha layer pixg2 into the color image pixc.
         * Write it out as is.  Then clean pixcs1 (to 0) under the fully
         * transparent part of the alpha layer, and write that result
         * out as well. */
    pixSetRGBComponent(pixcs1, pixg2, L_ALPHA_CHANNEL);
    pixWrite("/tmp/alpha/pixcs1.png", pixcs1, IFF_PNG);
    pixcs2 = pixSetUnderTransparency(pixcs1, 0, 0);
    pixWrite("/tmp/alpha/pixcs2.png", pixcs2, IFF_PNG);

        /* What will this look like over a black background?
         * Do the blending explicitly and display.  It should
         * look identical to the blended result pixd1 before cleaning. */
    pixd2 = pixBlendWithGrayMask(pixb, pixcs2, pixg2, 0, 0);
    regTestWritePixAndCheck(rp, pixd2, IFF_JFIF_JPEG);  /* 8 */
    pixDisplayWithTitle(pixd2, 0, 400, "alpha blended 2", rp->display);

        /* Read the two images back, ignoring the transparency layer.
         * The uncleaned image will come back identical to pixcs1.
         * However, the cleaned image will be black wherever
         * the alpha layer was fully transparent.  It will
         * look the same when viewed through the alpha layer,
         * but have much better compression. */
    pix1 = pixRead("/tmp/alpha/pixcs1.png");  /* just pixcs1 */
    pix2 = pixRead("/tmp/alpha/pixcs2.png");  /* cleaned under transparent */
    n1 = nbytesInFile("/tmp/alpha/pixcs1.png");
    n2 = nbytesInFile("/tmp/alpha/pixcs2.png");
    fprintf(stderr, " Original: %d bytes\n Cleaned: %d bytes\n", n1, n2);
    regTestWritePixAndCheck(rp, pix1, IFF_JFIF_JPEG);  /* 9 */
    regTestWritePixAndCheck(rp, pix2, IFF_JFIF_JPEG);  /* 10 */
    pixDisplayWithTitle(pix1, 300, 400, "without alpha", rp->display);
    pixDisplayWithTitle(pix2, 600, 400, "cleaned under transparent",
                        rp->display);

    pixa = pixaCreate(0);
    pixSaveTiled(pixg2, pixa, 1.0, 1, 20, 32);
    pixSaveTiled(pixcs1, pixa, 1.0, 1, 20, 0);
    pixSaveTiled(pix1, pixa, 1.0, 0, 20, 0);
    pixSaveTiled(pixd1, pixa, 1.0, 1, 20, 0);
    pixSaveTiled(pixd2, pixa, 1.0, 0, 20, 0);
    pixSaveTiled(pix2, pixa, 1.0, 1, 20, 0);
    pixd = pixaDisplay(pixa, 0, 0);
    regTestWritePixAndCheck(rp, pixd, IFF_JFIF_JPEG);  /* 11 */
    pixDisplayWithTitle(pixd, 200, 200, "composite", rp->display);
    pixWrite("/tmp/alpha/alpha.png", pixd, IFF_JFIF_JPEG);
    pixDestroy(&pixd);
    pixaDestroy(&pixa);
    pixDestroy(&pixs);
    pixDestroy(&pixb);
    pixDestroy(&pixg);
    pixDestroy(&pixg2);
    pixDestroy(&pixc);
    pixDestroy(&pixcs1);
    pixDestroy(&pixcs2);
    pixDestroy(&pixd);
    pixDestroy(&pixd1);
    pixDestroy(&pixd2);
    pixDestroy(&pix1);
    pixDestroy(&pix2);

    /* ------------------------ (3) ----------------------------*/
    color = 0xffffa000;
    gamma = 1.0;
    minval = 0;
    maxval = 200;
    box = boxCreate(0, 85, 600, 100);
    pixa = pixaCreate(6);
    pix1 = pixRead("blend-green1.jpg");
    pixaAddPix(pixa, pix1, L_INSERT);
    pix1 = pixRead("blend-green2.png");
    pixaAddPix(pixa, pix1, L_INSERT);
    pix1 = pixRead("blend-green3.png");
    pixaAddPix(pixa, pix1, L_INSERT);
    pix1 = pixRead("blend-orange.jpg");
    pixaAddPix(pixa, pix1, L_INSERT);
    pix1 = pixRead("blend-yellow.jpg");
    pixaAddPix(pixa, pix1, L_INSERT);
    pix1 = pixRead("blend-red.png");
    pixaAddPix(pixa, pix1, L_INSERT);
    n = pixaGetCount(pixa);
    pixa2 = pixaCreate(n);
    pixa3 = pixaCreate(n);
    for (i = 0; i < n; i++) {
        pix1 = pixaGetPix(pixa, i, L_CLONE);
        pix2 = DoBlendTest(pix1, box, color, gamma, minval, maxval, 1);
        regTestWritePixAndCheck(rp, pix2, IFF_JFIF_JPEG);  /* 12, 14, ... 22 */
        pixDisplayWithTitle(pix2, 150 * i, 0, NULL, rp->display);
        pixaAddPix(pixa2, pix2, L_INSERT);
        pix2 = DoBlendTest(pix1, box, color, gamma, minval, maxval, 2);
        regTestWritePixAndCheck(rp, pix2, IFF_JFIF_JPEG);  /* 13, 15, ... 23 */
        pixDisplayWithTitle(pix2, 150 * i, 200, NULL, rp->display);
        pixaAddPix(pixa3, pix2, L_INSERT);
        pixDestroy(&pix1);
    }
    if (rp->display) {
        pixaConvertToPdf(pixa2, 0, 0.75, L_FLATE_ENCODE, 0, "blend 1 test",
                         "/tmp/alpha/blending1.pdf");
        pixaConvertToPdf(pixa3, 0, 0.75, L_FLATE_ENCODE, 0, "blend 2 test",
                         "/tmp/alpha/blending2.pdf");
    }
    pixaDestroy(&pixa);
    pixaDestroy(&pixa2);
    pixaDestroy(&pixa3);
    boxDestroy(&box);

    /* ------------------------ (4) ----------------------------*/
        /* Use one image as the alpha component for a second image */
    pix1 = pixRead("test24.jpg");
    pix2 = pixRead("marge.jpg");
    pix3 = pixScale(pix2, 1.9, 2.2);
    pix4 = pixConvertTo8(pix3, 0);
    pixSetRGBComponent(pix1, pix4, L_ALPHA_CHANNEL);
    regTestWritePixAndCheck(rp, pix1, IFF_PNG);  /* 24 */
    pixDisplayWithTitle(pix1, 600, 0, NULL, rp->display);

        /* Set the alpha value in a colormap to bval */
    pix5 = pixOctreeColorQuant(pix1, 128, 0);
    cmap = pixGetColormap(pix5);
    pixcmapToArrays(cmap, &rmap, &gmap, &bmap, NULL);
    n = pixcmapGetCount(cmap);
    for (i = 0; i < n; i++) {
        pixcmapGetColor(cmap, i, &rval, &gval, &bval);
        cta = (RGBA_QUAD *)cmap->array;
        cta[i].alpha = bval;
    }

        /* Test binary serialization/deserialization of colormap with alpha */
    pixcmapSerializeToMemory(cmap, 4, &ncolors, &data);
    cmap2 = pixcmapDeserializeFromMemory(data, 4, ncolors);
    CmapEqual(cmap, cmap2, &equal);
    regTestCompareValues(rp, TRUE, equal, 0.0);  /* 25 */
    pixcmapDestroy(&cmap2);
    lept_free(data);

        /* Test ascii serialization/deserialization of colormap with alpha */
    fp = fopenWriteStream("/tmp/alpha/cmap.4", "w");
    pixcmapWriteStream(fp, cmap);
    fclose(fp);
    fp = fopenReadStream("/tmp/alpha/cmap.4");
    cmap2 = pixcmapReadStream(fp);
    fclose(fp);
    CmapEqual(cmap, cmap2, &equal);
    regTestCompareValues(rp, TRUE, equal, 0.0);  /* 26 */
    pixcmapDestroy(&cmap2);

        /* Test r/w for cmapped pix with non-opaque alpha */
    pixDisplayWithTitle(pix5, 900, 0, NULL, rp->display);
    regTestWritePixAndCheck(rp, pix5, IFF_PNG);  /* 27 */
    pixWrite("/tmp/alpha/fourcomp.png", pix5, IFF_PNG);
    pix6 = pixRead("/tmp/alpha/fourcomp.png");
    regTestComparePix(rp, pix5, pix6);  /* 28 */
    pixDestroy(&pix1);
    pixDestroy(&pix2);
    pixDestroy(&pix3);
    pixDestroy(&pix4);
    pixDestroy(&pix5);
    pixDestroy(&pix6);
    lept_free(rmap);
    lept_free(gmap);
    lept_free(bmap);
    return regTestCleanup(rp);
}
示例#28
0
/*!
 * \brief   pixWriteMemBmp()
 *
 * \param[out]   pfdata   data of bmp formatted image
 * \param[out]   pfsize    size of returned data
 * \param[in]    pixs      1, 2, 4, 8, 16, 32 bpp
 * \return  0 if OK, 1 on error
 *
 * <pre>
 * Notes:
 *      (1) 2 bpp bmp files are not valid in the spec, and are
 *          written as 8 bpp.
 *      (2) pix with depth <= 8 bpp are written with a colormap.
 *          16 bpp gray and 32 bpp rgb pix are written without a colormap.
 *      (3) The transparency component in an rgb pix is ignored.
 *          All 32 bpp pix have the bmp alpha component set to 255 (opaque).
 *      (4) The bmp colormap entries, RGBA_QUAD, are the same as
 *          the ones used for colormaps in leptonica.  This allows
 *          a simple memcpy for bmp output.
 * </pre>
 */
l_int32
pixWriteMemBmp(l_uint8  **pfdata,
               size_t    *pfsize,
               PIX       *pixs)
{
l_uint8     pel[4];
l_uint8    *cta = NULL;     /* address of the bmp color table array */
l_uint8    *fdata, *data, *fmdata;
l_int32     cmaplen;      /* number of bytes in the bmp colormap */
l_int32     ncolors, val, stepsize;
l_int32     w, h, d, fdepth, xres, yres;
l_int32     pixWpl, pixBpl, extrabytes, fBpl, fWpl, i, j, k;
l_int32     heapcm;  /* extra copy of cta on the heap ? 1 : 0 */
l_uint32    offbytes, fimagebytes;
l_uint32   *line, *pword;
size_t      fsize;
BMP_FH     *bmpfh;
BMP_IH     *bmpih;
PIX        *pix;
PIXCMAP    *cmap;
RGBA_QUAD  *pquad;

    PROCNAME("pixWriteMemBmp");

    if (pfdata) *pfdata = NULL;
    if (pfsize) *pfsize = 0;
    if (!pfdata)
        return ERROR_INT("&fdata not defined", procName, 1 );
    if (!pfsize)
        return ERROR_INT("&fsize not defined", procName, 1 );
    if (!pixs)
        return ERROR_INT("pixs not defined", procName, 1);

    pixGetDimensions(pixs, &w, &h, &d);
    if (d == 2) {
        L_WARNING("2 bpp files can't be read; converting to 8 bpp\n", procName);
        pix = pixConvert2To8(pixs, 0, 85, 170, 255, 1);
        d = 8;
    } else {
        pix = pixCopy(NULL, pixs);
    }
    fdepth = (d == 32) ? 24 : d;

        /* Resolution is given in pixels/meter */
    xres = (l_int32)(39.37 * (l_float32)pixGetXRes(pix) + 0.5);
    yres = (l_int32)(39.37 * (l_float32)pixGetYRes(pix) + 0.5);

    pixWpl = pixGetWpl(pix);
    pixBpl = 4 * pixWpl;
    fWpl = (w * fdepth + 31) / 32;
    fBpl = 4 * fWpl;
    fimagebytes = h * fBpl;
    if (fimagebytes > 4LL * L_MAX_ALLOWED_PIXELS) {
        pixDestroy(&pix);
        return ERROR_INT("image data is too large", procName, 1);
    }

        /* If not rgb or 16 bpp, the bmp data is required to have a colormap */
    heapcm = 0;
    if (d == 32 || d == 16) {   /* 24 bpp rgb or 16 bpp: no colormap */
        ncolors = 0;
        cmaplen = 0;
    } else if ((cmap = pixGetColormap(pix))) {   /* existing colormap */
        ncolors = pixcmapGetCount(cmap);
        cmaplen = ncolors * sizeof(RGBA_QUAD);
        cta = (l_uint8 *)cmap->array;
    } else {   /* no existing colormap; d <= 8; make a binary or gray one */
        if (d == 1) {
            cmaplen  = sizeof(bwmap);
            ncolors = 2;
            cta = (l_uint8 *)bwmap;
        } else {   /* d = 2,4,8; use a grayscale output colormap */
            ncolors = 1 << fdepth;
            cmaplen = ncolors * sizeof(RGBA_QUAD);
            heapcm = 1;
            cta = (l_uint8 *)LEPT_CALLOC(cmaplen, 1);
            stepsize = 255 / (ncolors - 1);
            for (i = 0, val = 0, pquad = (RGBA_QUAD *)cta;
                 i < ncolors;
                 i++, val += stepsize, pquad++) {
                pquad->blue = pquad->green = pquad->red = val;
                pquad->alpha = 255;  /* opaque */
            }
        }
    }

#if DEBUG
    {l_uint8  *pcmptr;
        pcmptr = (l_uint8 *)pixGetColormap(pix)->array;
        fprintf(stderr, "Pix colormap[0] = %c%c%c%d\n",
            pcmptr[0], pcmptr[1], pcmptr[2], pcmptr[3]);
        fprintf(stderr, "Pix colormap[1] = %c%c%c%d\n",
            pcmptr[4], pcmptr[5], pcmptr[6], pcmptr[7]);
    }
#endif  /* DEBUG */

    offbytes = BMP_FHBYTES + BMP_IHBYTES + cmaplen;
    fsize = offbytes + fimagebytes;
    fdata = (l_uint8 *)LEPT_CALLOC(fsize, 1);
    *pfdata = fdata;
    *pfsize = fsize;

        /* Convert to little-endian and write the file header data */
    bmpfh = (BMP_FH *)fdata;
    bmpfh->bfType = convertOnBigEnd16(BMP_ID);
    bmpfh->bfSize = convertOnBigEnd16(fsize & 0x0000ffff);
    bmpfh->bfFill1 = convertOnBigEnd16((fsize >> 16) & 0x0000ffff);
    bmpfh->bfOffBits = convertOnBigEnd16(offbytes & 0x0000ffff);
    bmpfh->bfFill2 = convertOnBigEnd16((offbytes >> 16) & 0x0000ffff);

        /* Convert to little-endian and write the info header data */
    bmpih = (BMP_IH *)(fdata + BMP_FHBYTES);
    bmpih->biSize = convertOnBigEnd32(BMP_IHBYTES);
    bmpih->biWidth = convertOnBigEnd32(w);
    bmpih->biHeight = convertOnBigEnd32(h);
    bmpih->biPlanes = convertOnBigEnd16(1);
    bmpih->biBitCount = convertOnBigEnd16(fdepth);
    bmpih->biSizeImage = convertOnBigEnd32(fimagebytes);
    bmpih->biXPelsPerMeter = convertOnBigEnd32(xres);
    bmpih->biYPelsPerMeter = convertOnBigEnd32(yres);
    bmpih->biClrUsed = convertOnBigEnd32(ncolors);
    bmpih->biClrImportant = convertOnBigEnd32(ncolors);

        /* Copy the colormap data and free the cta if necessary */
    if (ncolors > 0) {
        memcpy(fdata + BMP_FHBYTES + BMP_IHBYTES, cta, cmaplen);
        if (heapcm) LEPT_FREE(cta);
    }

        /* When you write a binary image with a colormap
         * that sets BLACK to 0, you must invert the data */
    if (fdepth == 1 && cmap && ((l_uint8 *)(cmap->array))[0] == 0x0) {
        pixInvert(pix, pix);
    }

        /* An endian byte swap is also required */
    pixEndianByteSwap(pix);

        /* Transfer the image data.  Image origin for bmp is at lower right. */
    fmdata = fdata + offbytes;
    if (fdepth != 24) {   /* typ 1 or 8 bpp */
        data = (l_uint8 *)pixGetData(pix) + pixBpl * (h - 1);
        for (i = 0; i < h; i++) {
            memcpy(fmdata, data, fBpl);
            data -= pixBpl;
            fmdata += fBpl;
        }
    } else {  /* 32 bpp pix; 24 bpp file
             * See the comments in pixReadStreamBmp() to
             * understand the logic behind the pixel ordering below.
             * Note that we have again done an endian swap on
             * little endian machines before arriving here, so that
             * the bytes are ordered on both platforms as:
                        Red         Green        Blue         --
                    |-----------|------------|-----------|-----------|
             */
        extrabytes = fBpl - 3 * w;
        line = pixGetData(pix) + pixWpl * (h - 1);
        for (i = 0; i < h; i++) {
            for (j = 0; j < w; j++) {
                pword = line + j;
                pel[2] = *((l_uint8 *)pword + COLOR_RED);
                pel[1] = *((l_uint8 *)pword + COLOR_GREEN);
                pel[0] = *((l_uint8 *)pword + COLOR_BLUE);
                memcpy(fmdata, &pel, 3);
                fmdata += 3;
            }
            if (extrabytes) {
                for (k = 0; k < extrabytes; k++) {
                    memcpy(fmdata, &pel, 1);
                    fmdata++;
                }
            }
            line -= pixWpl;
        }
    }

    pixDestroy(&pix);
    return 0;
}
示例#29
0
/*!
 * \brief   pixToGif()
 *
 * \param[in]    pix 1, 2, 4, 8, 16 or 32 bpp
 * \param[in]    gif  opened gif stream
 * \return  0 if OK, 1 on error
 *
 * <pre>
 * Notes:
 *      (1) This encodes the pix to the gif stream. The stream is not
 *          closes by this function.
 *      (2) It is static to make this function private.
 * </pre>
 */
static l_int32
pixToGif(PIX *pix, GifFileType *gif)
{
char            *text;
l_int32          wpl, i, j, w, h, d, ncolor, rval, gval, bval;
l_int32          gif_ncolor = 0;
l_uint32        *data, *line;
PIX             *pixd;
PIXCMAP         *cmap;
ColorMapObject  *gif_cmap;
GifByteType     *gif_line;
#if (GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1) || GIFLIB_MAJOR > 5
int              giferr;
#endif  /* 5.1 and beyond */

    PROCNAME("pixToGif");

    if (!pix)
        return ERROR_INT("pix not defined", procName, 1);
    if (!gif)
        return ERROR_INT("gif not defined", procName, 1);

    d = pixGetDepth(pix);
    if (d == 32) {
        pixd = pixConvertRGBToColormap(pix, 1);
    } else if (d > 1) {
        pixd = pixConvertTo8(pix, TRUE);
    } else {  /* d == 1; make sure there's a colormap */
        pixd = pixClone(pix);
        if (!pixGetColormap(pixd)) {
            cmap = pixcmapCreate(1);
            pixcmapAddColor(cmap, 255, 255, 255);
            pixcmapAddColor(cmap, 0, 0, 0);
            pixSetColormap(pixd, cmap);
        }
    }

    if (!pixd)
        return ERROR_INT("failed to convert image to indexed", procName, 1);
    d = pixGetDepth(pixd);

    if ((cmap = pixGetColormap(pixd)) == NULL) {
        pixDestroy(&pixd);
        return ERROR_INT("cmap is missing", procName, 1);
    }

        /* 'Round' the number of gif colors up to a power of 2 */
    ncolor = pixcmapGetCount(cmap);
    for (i = 0; i <= 8; i++) {
        if ((1 << i) >= ncolor) {
            gif_ncolor = (1 << i);
            break;
        }
    }
    if (gif_ncolor < 1) {
        pixDestroy(&pixd);
        return ERROR_INT("number of colors is invalid", procName, 1);
    }

        /* Save the cmap colors in a gif_cmap */
    if ((gif_cmap = GifMakeMapObject(gif_ncolor, NULL)) == NULL) {
        pixDestroy(&pixd);
        return ERROR_INT("failed to create GIF color map", procName, 1);
    }
    for (i = 0; i < gif_ncolor; i++) {
        rval = gval = bval = 0;
        if (ncolor > 0) {
            if (pixcmapGetColor(cmap, i, &rval, &gval, &bval) != 0) {
                pixDestroy(&pixd);
                GifFreeMapObject(gif_cmap);
                return ERROR_INT("failed to get color from color map",
                                 procName, 1);
            }
            ncolor--;
        }
        gif_cmap->Colors[i].Red = rval;
        gif_cmap->Colors[i].Green = gval;
        gif_cmap->Colors[i].Blue = bval;
    }

    pixGetDimensions(pixd, &w, &h, NULL);
    if (EGifPutScreenDesc(gif, w, h, gif_cmap->BitsPerPixel, 0, gif_cmap)
        != GIF_OK) {
        pixDestroy(&pixd);
        GifFreeMapObject(gif_cmap);
        return ERROR_INT("failed to write screen description", procName, 1);
    }
    GifFreeMapObject(gif_cmap); /* not needed after this point */

    if (EGifPutImageDesc(gif, 0, 0, w, h, FALSE, NULL) != GIF_OK) {
        pixDestroy(&pixd);
        return ERROR_INT("failed to image screen description", procName, 1);
    }

    data = pixGetData(pixd);
    wpl = pixGetWpl(pixd);
    if (d != 1 && d != 2 && d != 4 && d != 8) {
        pixDestroy(&pixd);
        return ERROR_INT("image depth is not in {1, 2, 4, 8}", procName, 1);
    }

    if ((gif_line = (GifByteType *)LEPT_CALLOC(sizeof(GifByteType), w))
        == NULL) {
        pixDestroy(&pixd);
        return ERROR_INT("mem alloc fail for data line", procName, 1);
    }

    for (i = 0; i < h; i++) {
        line = data + i * wpl;
            /* Gif's way of setting the raster line up for compression */
        for (j = 0; j < w; j++) {
            switch(d)
            {
            case 8:
                gif_line[j] = GET_DATA_BYTE(line, j);
                break;
            case 4:
                gif_line[j] = GET_DATA_QBIT(line, j);
                break;
            case 2:
                gif_line[j] = GET_DATA_DIBIT(line, j);
                break;
            case 1:
                gif_line[j] = GET_DATA_BIT(line, j);
                break;
            }
        }

            /* Compress and save the line */
        if (EGifPutLine(gif, gif_line, w) != GIF_OK) {
            LEPT_FREE(gif_line);
            pixDestroy(&pixd);
            return ERROR_INT("failed to write data line into GIF", procName, 1);
        }
    }

        /* Write a text comment.  This must be placed after writing the
         * data (!!)  Note that because libgif does not provide a function
         * for reading comments from file, you will need another way
         * to read comments. */
    if ((text = pixGetText(pix)) != NULL) {
        if (EGifPutComment(gif, text) != GIF_OK)
            L_WARNING("gif comment not written\n", procName);
    }

    LEPT_FREE(gif_line);
    pixDestroy(&pixd);
    return 0;
}
示例#30
0
文件: pngio.c 项目: 0xkasun/Dummy_Tes
/*!
 *  pixWriteStreamPng()
 *
 *      Input:  stream
 *              pix
 *              gamma (use 0.0 if gamma is not defined)
 *      Return: 0 if OK; 1 on error
 *
 *  Notes:
 *      (1) If called from pixWriteStream(), the stream is positioned
 *          at the beginning of the file.
 *      (2) To do sequential writes of png format images to a stream,
 *          use pixWriteStreamPng() directly.
 *      (3) gamma is an optional png chunk.  If no gamma value is to be
 *          placed into the file, use gamma = 0.0.  Otherwise, if
 *          gamma > 0.0, its value is written into the header.
 *      (4) The use of gamma in png is highly problematic.  For an illuminating
 *          discussion, see:  http://hsivonen.iki.fi/png-gamma/
 *      (5) What is the effect/meaning of gamma in the png file?  This
 *          gamma, which we can call the 'source' gamma, is the
 *          inverse of the gamma that was used in enhance.c to brighten
 *          or darken images.  The 'source' gamma is supposed to indicate
 *          the intensity mapping that was done at the time the
 *          image was captured.  Display programs typically apply a
 *          'display' gamma of 2.2 to the output, which is intended
 *          to linearize the intensity based on the response of
 *          thermionic tubes (CRTs).  Flat panel LCDs have typically
 *          been designed to give a similar response as CRTs (call it
 *          "backward compatibility").  The 'display' gamma is
 *          in some sense the inverse of the 'source' gamma.
 *          jpeg encoders attached to scanners and cameras will lighten
 *          the pixels, applying a gamma corresponding to approximately
 *          a square-root relation of output vs input:
 *                output = input^(gamma)
 *          where gamma is often set near 0.4545  (1/gamma is 2.2).
 *          This is stored in the image file.  Then if the display
 *          program reads the gamma, it will apply a display gamma,
 *          typically about 2.2; the product is 1.0, and the
 *          display program produces a linear output.  This works because
 *          the dark colors were appropriately boosted by the scanner,
 *          as described by the 'source' gamma, so they should not
 *          be further boosted by the display program.
 *      (6) As an example, with xv and display, if no gamma is stored,
 *          the program acts as if gamma were 0.4545, multiplies this by 2.2,
 *          and does a linear rendering.  Taking this as a baseline
 *          brightness, if the stored gamma is:
 *              > 0.4545, the image is rendered lighter than baseline
 *              < 0.4545, the image is rendered darker than baseline
 *          In contrast, gqview seems to ignore the gamma chunk in png.
 *      (7) The only valid pixel depths in leptonica are 1, 2, 4, 8, 16
 *          and 32.  However, it is possible, and in some cases desirable,
 *          to write out a png file using an rgb pix that has 24 bpp.
 *          For example, the open source xpdf SplashBitmap class generates
 *          24 bpp rgb images.  Consequently, we anble writing 24 bpp pix.
 *          To generate such a pix, you can make a 24 bpp pix without data
 *          and assign the data array to the pix; e.g.,
 *              pix = pixCreateHeader(w, h, 24);
 *              pixSetData(pix, rgbdata);
 *          See pixConvert32To24() for an example, where we get rgbdata
 *          from the 32 bpp pix.  Caution: do not call pixSetPadBits(),
 *          because the alignment is wrong and you may erase part of the
 *          last pixel on each line.
 */
l_int32
pixWriteStreamPng(FILE      *fp,
                  PIX       *pix,
                  l_float32  gamma)
{
char         commentstring[] = "Comment";
l_int32      i, j, k;
l_int32      wpl, d, cmflag;
l_int32      ncolors;
l_int32     *rmap, *gmap, *bmap;
l_uint32    *data, *ppixel;
png_byte     bit_depth, color_type;
png_uint_32  w, h;
png_uint_32  xres, yres;
png_bytep   *row_pointers;
png_bytep    rowbuffer;
png_structp  png_ptr;
png_infop    info_ptr;
png_colorp   palette;
PIX         *pixt;
PIXCMAP     *cmap;
char        *text;

    PROCNAME("pixWriteStreamPng");

    if (!fp)
        return ERROR_INT("stream not open", procName, 1);
    if (!pix)
        return ERROR_INT("pix not defined", procName, 1);

        /* Allocate the 2 data structures */
    if ((png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
                   (png_voidp)NULL, NULL, NULL)) == NULL)
        return ERROR_INT("png_ptr not made", procName, 1);

    if ((info_ptr = png_create_info_struct(png_ptr)) == NULL) {
        png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
        return ERROR_INT("info_ptr not made", procName, 1);
    }

        /* Set up png setjmp error handling */
    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_write_struct(&png_ptr, &info_ptr);
        return ERROR_INT("internal png error", procName, 1);
    }

    png_init_io(png_ptr, fp);

        /* With best zlib compression (9), get between 1 and 10% improvement
         * over default (5), but the compression is 3 to 10 times slower.
         * Our default compression is the zlib default (5). */
    png_set_compression_level(png_ptr, var_ZLIB_COMPRESSION);

    w = pixGetWidth(pix);
    h = pixGetHeight(pix);
    d = pixGetDepth(pix);
    if ((cmap = pixGetColormap(pix)))
        cmflag = 1;
    else
        cmflag = 0;

        /* Set the color type and bit depth. */
    if (d == 32 && var_PNG_WRITE_ALPHA == 1) {
        bit_depth = 8;
        color_type = PNG_COLOR_TYPE_RGBA;   /* 6 */
        cmflag = 0;  /* ignore if it exists */
    }
    else if (d == 24 || d == 32) {
        bit_depth = 8;
        color_type = PNG_COLOR_TYPE_RGB;   /* 2 */
        cmflag = 0;  /* ignore if it exists */
    }
    else {
        bit_depth = d;
        color_type = PNG_COLOR_TYPE_GRAY;  /* 0 */
    }
    if (cmflag)
        color_type = PNG_COLOR_TYPE_PALETTE;  /* 3 */

#if  DEBUG
    fprintf(stderr, "cmflag = %d, bit_depth = %d, color_type = %d\n",
            cmflag, bit_depth, color_type);
#endif  /* DEBUG */

    png_set_IHDR(png_ptr, info_ptr, w, h, bit_depth, color_type,
                 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
                 PNG_FILTER_TYPE_BASE);

        /* Store resolution in ppm, if known */
    xres = (png_uint_32)(39.37 * (l_float32)pixGetXRes(pix) + 0.5);
    yres = (png_uint_32)(39.37 * (l_float32)pixGetYRes(pix) + 0.5);
    if ((xres == 0) || (yres == 0))
        png_set_pHYs(png_ptr, info_ptr, 0, 0, PNG_RESOLUTION_UNKNOWN);
    else
        png_set_pHYs(png_ptr, info_ptr, xres, yres, PNG_RESOLUTION_METER);

    if (cmflag) {
        pixcmapToArrays(cmap, &rmap, &gmap, &bmap);
        ncolors = pixcmapGetCount(cmap);

            /* Make and save the palette */
        if ((palette = (png_colorp)(CALLOC(ncolors, sizeof(png_color))))
                == NULL)
            return ERROR_INT("palette not made", procName, 1);

        for (i = 0; i < ncolors; i++) {
            palette[i].red = (png_byte)rmap[i];
            palette[i].green = (png_byte)gmap[i];
            palette[i].blue = (png_byte)bmap[i];
        }

        png_set_PLTE(png_ptr, info_ptr, palette, (int)ncolors);
        FREE(rmap);
        FREE(gmap);
        FREE(bmap);
    }

        /* 0.4545 is treated as the default by some image
         * display programs (not gqview).  A value > 0.4545 will
         * lighten an image as displayed by xv, display, etc. */
    if (gamma > 0.0)
        png_set_gAMA(png_ptr, info_ptr, (l_float64)gamma);

    if ((text = pixGetText(pix))) {
        png_text text_chunk;
        text_chunk.compression = PNG_TEXT_COMPRESSION_NONE;
        text_chunk.key = commentstring;
        text_chunk.text = text;
        text_chunk.text_length = strlen(text);
#ifdef PNG_ITXT_SUPPORTED
        text_chunk.itxt_length = 0;
        text_chunk.lang = NULL;
        text_chunk.lang_key = NULL;
#endif
        png_set_text(png_ptr, info_ptr, &text_chunk, 1);
    }

        /* Write header and palette info */
    png_write_info(png_ptr, info_ptr);

    if ((d != 32) && (d != 24)) {  /* not rgb color */
            /* Generate a temporary pix with bytes swapped.
             * For a binary image, there are two conditions in
             * which you must first invert the data for writing png:
             *    (a) no colormap
             *    (b) colormap with BLACK set to 0
             * png writes binary with BLACK = 0, unless contradicted
             * by a colormap.  If the colormap has BLACK = "1"
             * (typ. about 255), do not invert the data.  If there
             * is no colormap, you must invert the data to store
             * in default BLACK = 0 state.  */
        if (d == 1 &&
            (!cmap || (cmap && ((l_uint8 *)(cmap->array))[0] == 0x0))) {
            pixt = pixInvert(NULL, pix);
            pixEndianByteSwap(pixt);
        }
        else
            pixt = pixEndianByteSwapNew(pix);
        if (!pixt) {
            png_destroy_write_struct(&png_ptr, &info_ptr);
            return ERROR_INT("pixt not made", procName, 1);
        }

            /* Make and assign array of image row pointers */
        if ((row_pointers = (png_bytep *)CALLOC(h, sizeof(png_bytep))) == NULL)
            return ERROR_INT("row-pointers not made", procName, 1);
        wpl = pixGetWpl(pixt);
        data = pixGetData(pixt);
        for (i = 0; i < h; i++)
            row_pointers[i] = (png_bytep)(data + i * wpl);
        png_set_rows(png_ptr, info_ptr, row_pointers);

            /* Transfer the data */
        png_write_image(png_ptr, row_pointers);
        png_write_end(png_ptr, info_ptr);

        if (cmflag)
            FREE(palette);
        FREE(row_pointers);
        pixDestroy(&pixt);
        png_destroy_write_struct(&png_ptr, &info_ptr);
        return 0;
    }

        /* For rgb, compose and write a row at a time */
    data = pixGetData(pix);
    wpl = pixGetWpl(pix);
    if (d == 24) {  /* See note 7 above: special case of 24 bpp rgb */
        for (i = 0; i < h; i++) {
            ppixel = data + i * wpl;
            png_write_rows(png_ptr, (png_bytepp)&ppixel, 1);
        }
    }
    else {  /* 32 bpp rgb and rgba */
        if ((rowbuffer = (png_bytep)CALLOC(w, 4)) == NULL)
            return ERROR_INT("rowbuffer not made", procName, 1);
        for (i = 0; i < h; i++) {
            ppixel = data + i * wpl;
            for (j = k = 0; j < w; j++) {
                rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_RED);
                rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_GREEN);
                rowbuffer[k++] = GET_DATA_BYTE(ppixel, COLOR_BLUE);
                if (var_PNG_WRITE_ALPHA == 1)
                    rowbuffer[k++] = GET_DATA_BYTE(ppixel, L_ALPHA_CHANNEL);
                ppixel++;
            }

            png_write_rows(png_ptr, &rowbuffer, 1);
        }
        FREE(rowbuffer);
    }

    png_write_end(png_ptr, info_ptr);

    if (cmflag)
        FREE(palette);
    png_destroy_write_struct(&png_ptr, &info_ptr);
    return 0;

}