예제 #1
0
static void
mapTuple(struct pam *            const pamP,
         tuple                   const inTuple,
         tuple                   const defaultColor,
         tupletable              const colormap,
         struct colormapFinder * const colorFinderP,
         tuplehash               const colorhash, 
         bool *                  const usehashP,
         tuple                   const outTuple,
         bool *                  const missingP) {

    int colormapIndex;
        /* Index into the colormap of the replacement color, or -1 if
           there is no usable color in the color map.
        */

    lookupThroughHash(pamP, inTuple, !!defaultColor, colorFinderP, 
                      colorhash, &colormapIndex, usehashP);

    if (colormapIndex == -1) {
        *missingP = TRUE;

        assert(defaultColor);  /* Otherwise, lookup would have succeeded */

        pnm_assigntuple(pamP, outTuple, defaultColor);
    } else {
        *missingP = FALSE;
        pnm_assigntuple(pamP, outTuple, colormap[colormapIndex]->tuple);
    }
}
예제 #2
0
/* Draw a pair of guide boxes. */
static void
drawguides(int                const guidesize,
           const struct pam * const outPamP,
           double             const eyesep,
           unsigned int       const dpi,
           double             const depthOfField) {

    int const far = separation(0, eyesep, dpi, depthOfField);
    /* Space between the two guide boxes. */
    int const width = outPamP->width;    /* Width of the output image */

    tuple *outrow;             /* One row of output data */
    tuple blackTuple;
    int col;

    pnm_createBlackTuple(outPamP, &blackTuple);

    outrow = pnm_allocpamrow(outPamP);

    /* Leave some blank rows before the guides. */
    makeWhiteRow(outPamP, outrow);
    writeRowCopies(outPamP, outrow, guidesize);

    /* Draw the guides. */
    if ((width - far + guidesize)/2 < 0 ||
            (width + far - guidesize)/2 >= width)
        pm_message("warning: the guide boxes are completely out of bounds "
                   "at %d DPI", dpi);
    else if ((width - far - guidesize)/2 < 0 ||
             (width + far + guidesize)/2 >= width)
        pm_message("warning: the guide boxes are partially out of bounds "
                   "at %d DPI", dpi);

    for (col = (width - far - guidesize)/2;
            col < (width - far + guidesize)/2;
            ++col)
        if (col >= 0 && col < width)
            pnm_assigntuple(outPamP, outrow[col], blackTuple);

    for (col = (width + far - guidesize)/2;
            col < (width + far + guidesize)/2;
            ++col)
        if (col >= 0 && col < width)
            pnm_assigntuple(outPamP, outrow[col], blackTuple);

    writeRowCopies(outPamP,outrow, guidesize);

    /* Leave some blank rows after the guides. */
    makeWhiteRow(outPamP, outrow);
    writeRowCopies(outPamP, outrow, guidesize);

    pnm_freerow(outrow);
}
예제 #3
0
static void
determineBackgroundColor(struct pam * const pamP,
                         bool         const verbose,
                         tuple *      const bgColorP) {
/*----------------------------------------------------------------------------
   Determine what color is the background color of the image in the
   file represented by *pamP.

   Expect the file to be positioned to the start of the raster, and leave
   it positioned arbitrarily.
-----------------------------------------------------------------------------*/
    unsigned int row;
    tuple * tuplerow;
    tuple ul, ur, ll, lr;
        /* Color of upper left, upper right, lower left, lower right */

    tuplerow  = pnm_allocpamrow(pamP);
    ul = pnm_allocpamtuple(pamP);
    ur = pnm_allocpamtuple(pamP);
    ll = pnm_allocpamtuple(pamP);
    lr = pnm_allocpamtuple(pamP);

    pnm_readpamrow(pamP, tuplerow);

    pnm_assigntuple(pamP, ul, tuplerow[0]);
    pnm_assigntuple(pamP, ur, tuplerow[pamP->width-1]);

    for (row = 1; row < pamP->height; ++row)
        pnm_readpamrow(pamP, tuplerow);

    pnm_assigntuple(pamP, ll, tuplerow[0]);
    pnm_assigntuple(pamP, lr, tuplerow[pamP->width-1]);

    selectBackground(pamP, ul, ur, ll, lr, bgColorP);

    if (verbose) {
        int const hexokTrue = 1;
        const char * const colorname =
            pnm_colorname(pamP, *bgColorP, hexokTrue);
        pm_message("Background color is %s", colorname);

        strfree(colorname);
    }

    pnm_freepamtuple(lr);
    pnm_freepamtuple(ll);
    pnm_freepamtuple(ur);
    pnm_freepamtuple(ul);
    pnm_freepamrow(tuplerow);
}
예제 #4
0
static void
processMapFile(const char *   const mapFileName,
               struct pam *   const outpamCommonP,
               tupletable *   const colormapP,
               unsigned int * const colormapSizeP,
               tuple *        const firstColorP) {
/*----------------------------------------------------------------------------
   Read a color map from the file named 'mapFileName'.  It's a map that
   associates each color in that file with a unique whole number.  Return the
   map as *colormapP, with the number of entries in it as *colormapSizeP.

   Also determine the first color (top left) in the map file and return that
   as *firstColorP.
-----------------------------------------------------------------------------*/
    FILE * mapfile;
    struct pam mappam;
    tuple ** maptuples;
    tuple firstColor;

    mapfile = pm_openr(mapFileName);
    maptuples = pnm_readpam(mapfile, &mappam, PAM_STRUCT_SIZE(tuple_type));
    pm_close(mapfile);

    computeColorMapFromMap(&mappam, maptuples, colormapP, colormapSizeP);

    firstColor = pnm_allocpamtuple(&mappam);
    pnm_assigntuple(&mappam, firstColor, maptuples[0][0]);
    *firstColorP = firstColor;

    pnm_freepamarray(maptuples, &mappam);

    *outpamCommonP = mappam; 
    outpamCommonP->file = stdout;
}
예제 #5
0
void
pnm_addtuplefreqoccurrence(struct pam *   const pamP,
                           tuple          const value,
                           tuplehash      const tuplefreqhash,
                           int *          const firstOccurrenceP) {

    unsigned int const hashvalue = pnm_hashtuple(pamP, value);
            
    struct tupleint_list_item * p;

    for (p = tuplefreqhash[hashvalue]; 
         p && !pnm_tupleequal(pamP, p->tupleint.tuple, value);
         p = p->next);

    if (p) {
        /* It's in the hash; just tally one more occurence */
        ++p->tupleint.value;
        *firstOccurrenceP = FALSE;
    } else {
        struct tupleint_list_item * p;

        /* It's not in the hash yet, so add it */
        *firstOccurrenceP = TRUE;

        p = allocTupleIntListItem(pamP);
        if (p == NULL)
            pm_error("out of memory computing hash table");

        pnm_assigntuple(pamP, p->tupleint.tuple, value);
        p->tupleint.value = 1;
        p->next = tuplefreqhash[hashvalue];
        tuplefreqhash[hashvalue] = p;
    }
}
예제 #6
0
void
pnm_addtotuplehash(struct pam *   const pamP,
                   tuplehash      const tuplehash, 
                   tuple          const tupletoadd,
                   int            const value,
                   int *          const fitsP) {
/*----------------------------------------------------------------------------
   Add a tuple value to the hash -- assume it isn't already there.

   Allocate new space for the tuple value and the hash chain element.

   If we can't allocate space for the new hash chain element, don't
   change anything and return *fitsP = FALSE;
-----------------------------------------------------------------------------*/
    struct tupleint_list_item * const listItemP = allocTupleIntListItem(pamP);
    if (listItemP == NULL)
        *fitsP = FALSE;
    else {
        unsigned int const hashvalue = pnm_hashtuple(pamP, tupletoadd);
    
        *fitsP = TRUE;

        pnm_assigntuple(pamP, listItemP->tupleint.tuple, tupletoadd);
        listItemP->tupleint.value = value;
        listItemP->next = tuplehash[hashvalue];
        tuplehash[hashvalue] = listItemP;
    }
}
예제 #7
0
static tupletable
tuplehashtotable(const struct pam * const pamP,
                 tuplehash          const tuplehash,
                 unsigned int       const allocsize) {
/*----------------------------------------------------------------------------
   Create a tuple table containing the info from a tuple hash.  Allocate
   space in the table for 'allocsize' elements even if there aren't that
   many tuple values in the input hash.  That's so the caller has room
   for expansion.

   Caller must ensure that 'allocsize' is at least as many tuple values
   as there are in the input hash.

   We allocate new space for all the table contents; there are no pointers
   in the table to tuples or anything else in existing space.
-----------------------------------------------------------------------------*/
    tupletable tupletable;
    const char * error;

    alloctupletable(pamP, allocsize, &tupletable, &error);

    if (error) {
        pm_errormsg("%s", error);
        strfree(error);
        pm_longjmp();
    } else {
        unsigned int i, j;
        /* Loop through the hash table. */
        j = 0;
        for (i = 0; i < HASH_SIZE; ++i) {
            /* Walk this hash chain */
            struct tupleint_list_item * p;
            for (p = tuplehash[i]; p; p = p->next) {
                assert(j < allocsize);
                tupletable[j]->value = p->tupleint.value;
                pnm_assigntuple(pamP, tupletable[j]->tuple, p->tupleint.tuple);
                ++j;
            }
        }
    }
    return tupletable;
}
예제 #8
0
static void
composeRow(int              const originleft, 
           struct pam *     const underlayPamP,
           struct pam *     const overlayPamP,
           bool             const invertAlpha,
           float            const masterOpacity,
           struct pam *     const composedPamP,
           enum sampleScale const sampleScale,
           enum alphaMix    const alphaMix,
           const tuple *    const underlayTuplerow,
           const tuple *    const overlayTuplerow,
           const tuplen *   const alphaTuplerown,
           tuple *          const composedTuplerow) {
/*----------------------------------------------------------------------------
   Create a row of tuples ('composedTupleRow') which is the composition of
   row 'overlayTupleRow' laid over row 'underlayTupleRow', starting at
   column 'originLeft'.

   *underlayPamP and *overlayPamP describe the respective tuple rows.
-----------------------------------------------------------------------------*/
    unsigned int col;

    for (col = 0; col < composedPamP->width; ++col) {
        int const ovlcol = col - originleft;

        if (ovlcol >= 0 && ovlcol < overlayPamP->width) {
            tuplen const alphaTuplen = 
                alphaTuplerown ? alphaTuplerown[ovlcol] : NULL;

            overlayPixel(overlayTuplerow[ovlcol], overlayPamP,
                         underlayTuplerow[col], underlayPamP,
                         alphaTuplen, invertAlpha,
                         composedTuplerow[col], composedPamP,
                         masterOpacity, sampleScale, alphaMix);
        } else
            /* Overlay image does not touch this column. */
            pnm_assigntuple(composedPamP, composedTuplerow[col],
                            underlayTuplerow[col]);
    }
}
예제 #9
0
static void
addColorOccurrenceToHash(tuple          const color, 
                         tuplehash      const tuplefreqhash,
                         struct pam *   const pamP,
                         unsigned int   const maxsize,
                         unsigned int * const sizeP,
                         bool *         const fullP) {
               
    unsigned int const hashvalue = pnm_hashtuple(pamP, color);
            
    struct tupleint_list_item *p;

    for (p = tuplefreqhash[hashvalue]; 
         p && !pnm_tupleequal(pamP, p->tupleint.tuple, color);
         p = p->next);

    if (p) {
        /* It's in the hash; just tally one more occurence */
        ++p->tupleint.value;
        *fullP = FALSE;
    } else {
        /* It's not in the hash yet, so add it (if allowed) */
        ++(*sizeP);
        if (maxsize > 0 && *sizeP > maxsize) 
            *fullP = TRUE;
        else {
            *fullP = FALSE;
            p = allocTupleIntListItem(pamP);
            if (p == NULL)
                pm_error("out of memory computing hash table");
            pnm_assigntuple(pamP, p->tupleint.tuple, color);
            p->tupleint.value = 1;
            p->next = tuplefreqhash[hashvalue];
            tuplefreqhash[hashvalue] = p;
        }
    }
}
예제 #10
0
static void
ditherRow(struct pam *           const inpamP,
          const tuple *          const inrow,
          const scaler *         const scalerP,
          unsigned int **        const ditherMatrix,
          unsigned int           const ditherMatrixArea,
          struct colorResolution const colorRes,
          unsigned int           const row,
          unsigned int           const modMask,
          struct pam *           const outpamP,
          tuple *                const outrow) {

    unsigned int col;

    for (col = 0; col < inpamP->width; ++col) {
        unsigned int const d =
            ditherMatrix[row & modMask][(inpamP->width-col-1) & modMask];

        unsigned int dithered[3];
        unsigned int plane;

        assert(inpamP->depth >= 3);

        for (plane = 0; plane < 3; ++plane)
            dithered[plane] =
                dither(inrow[col][plane], inpamP->maxval, d,
                       colorRes.c[plane]-1, ditherMatrixArea);

        pnm_assigntuple(outpamP,
                        outrow[col],
                        scaler_scale(scalerP,
                                     dithered[PAM_RED_PLANE],
                                     dithered[PAM_GRN_PLANE],
                                     dithered[PAM_BLU_PLANE]));
    }
}
예제 #11
0
static void
selectBackground(struct pam * const pamP,
                 tuple        const ul,
                 tuple        const ur,
                 tuple        const lr,
                 tuple        const ll,
                 tuple *      const bgColorP) {

    tuple bg;  /* Reference to one of ul, ur, ll, lr */

    if (pnm_tupleequal(pamP, ul, ur) &&
        (pnm_tupleequal(pamP, ul, ll) ||
         pnm_tupleequal(pamP, ul, lr)))
        bg = ul;
    else if (pnm_tupleequal(pamP, ll, lr) &&
             pnm_tupleequal(pamP, lr, ul))
        bg = ll;
    else {
        /* No 3 corners are same color; look for 2 corners */
        if (pnm_tupleequal(pamP, ul, ur))  /* top edge */
            bg = ul;
        else if (pnm_tupleequal(pamP, ul, ll)) /* left edge */
            bg = ul;
        else if (pnm_tupleequal(pamP, ur, lr)) /* right edge */
            bg = ur;
        else if (pnm_tupleequal(pamP, ll, lr)) /* bottom edge */
            bg = ll;
        else {
            /* No two corners are same color; just use upper left corner */
            bg = ul;
        }
    }
    
    *bgColorP = pnm_allocpamtuple(pamP);
    pnm_assigntuple(pamP, *bgColorP, bg);
}
예제 #12
0
파일: pamcomp.c 프로젝트: moseymosey/netpbm
static void
composite(int          const originleft, 
          int          const origintop, 
          struct pam * const underlayPamP,
          struct pam * const overlayPamP,
          struct pam * const alphaPamP,
          bool         const invertAlpha,
          float        const masterOpacity,
          struct pam * const composedPamP,
          bool         const assumeLinear) {
/*----------------------------------------------------------------------------
   Overlay the overlay image in the array 'overlayImage', described by
   *overlayPamP, onto the underlying image from the input image file
   as described by *underlayPamP, output the composite to the image
   file as described by *composedPamP.

   Apply the overlay image with transparency described by the array
   'alpha' and *alphaPamP.

   The underlying image is positioned after its header.

   'originleft' and 'origintop' are the coordinates in the underlying
   image plane where the top left corner of the overlay image is to
   go.  It is not necessarily inside the underlying image (in fact,
   may be negative).  Only the part of the overlay that actually
   intersects the underlying image, if any, gets into the output.
-----------------------------------------------------------------------------*/
    enum sampleScale const sampleScale = 
        assumeLinear ? INTENSITY_SAMPLE : GAMMA_SAMPLE;

    int underlayRow;  /* NB may be negative */
    int overlayRow;   /* NB may be negative */
    tuple * composedTuplerow;
    tuple * underlayTuplerow;
    tuple * overlayTuplerow;
    tuplen * alphaTuplerown;
    bool overlayHasOpacity;
    unsigned int opacityPlane;

    pnm_getopacity(overlayPamP, &overlayHasOpacity, &opacityPlane);

    composedTuplerow = pnm_allocpamrow(composedPamP);
    underlayTuplerow = pnm_allocpamrow(underlayPamP);
    overlayTuplerow  = pnm_allocpamrow(overlayPamP);
    if (alphaPamP)
        alphaTuplerown = pnm_allocpamrown(alphaPamP);

    pnm_writepaminit(composedPamP);

    for (underlayRow = MIN(0, origintop), overlayRow = MIN(0, -origintop);
         underlayRow < MAX(underlayPamP->height, 
                           origintop + overlayPamP->height);
         ++underlayRow, ++overlayRow) {

        if (overlayRow >= 0 && overlayRow < overlayPamP->height) {
            pnm_readpamrow(overlayPamP, overlayTuplerow);
            adaptRowToOutputFormat(overlayPamP, overlayTuplerow, composedPamP);
            if (alphaPamP)
                pnm_readpamrown(alphaPamP, alphaTuplerown);
        }
        if (underlayRow >= 0 && underlayRow < underlayPamP->height) {
            pnm_readpamrow(underlayPamP, underlayTuplerow);
            adaptRowToOutputFormat(underlayPamP, underlayTuplerow, 
                                   composedPamP);

            if (underlayRow < origintop || 
                underlayRow >= origintop + overlayPamP->height) {
            
                /* Overlay image does not touch this underlay row. */

                pnm_writepamrow(composedPamP, underlayTuplerow);
            } else {
                unsigned int col;
                for (col = 0; col < composedPamP->width; ++col) {
                    int const ovlcol = col - originleft;

                    if (ovlcol >= 0 && ovlcol < overlayPamP->width) {
                        tuplen const alphaTuplen = 
                            alphaPamP ? alphaTuplerown[ovlcol] : NULL;

                        overlayPixel(overlayTuplerow[ovlcol], overlayPamP,
                                     underlayTuplerow[col], underlayPamP,
                                     alphaTuplen, invertAlpha,
                                     overlayHasOpacity, opacityPlane,
                                     composedTuplerow[col], composedPamP,
                                     masterOpacity, sampleScale);
                    } else
                        /* Overlay image does not touch this column. */
                        pnm_assigntuple(composedPamP, composedTuplerow[col],
                                        underlayTuplerow[col]);
                }
                pnm_writepamrow(composedPamP, composedTuplerow);
            }
        }
    }
    pnm_freepamrow(composedTuplerow);
    pnm_freepamrow(underlayTuplerow);
    pnm_freepamrow(overlayTuplerow);
    if (alphaPamP)
        pnm_freepamrown(alphaTuplerown);
}