Example #1
0
static void 
writeRleRun(FILE *       const ofP, 
            struct pam * const pamP,
            tuple        const color, 
            int          const count,
            tuplehash    const colorhash,
            tuple        const transcolor) {
/*----------------------------------------------------------------------------
  Write one DjVu Color RLE run to the file 'ofP'.  The run is 
  'count' pixels of color 'color', using the color index given by
  'colorhash' and assuming 'transcolor' is the transparent color.
  
  'transcolor' is a 3-deep tuple with the same maxval as the image.
-----------------------------------------------------------------------------*/
    uint32n rlevalue;         /* RLE-encoded color/valuex */
    int index;

    if (count > 0) {
        if (colorEqual(color, pamP->depth, transcolor))
            index = 0xFFF;
        else {
            int found;
            pnm_lookuptuple(pamP, colorhash, color, &found, &index);
            assert(found);
        }
        rlevalue = (index << 20) | count;
      
        pm_writebiglong(ofP, rlevalue);
    }
}
Example #2
0
static void
lookupThroughHash(struct pam *            const pamP, 
                  tuple                   const tuple, 
                  bool                    const needExactMatch,
                  struct colormapFinder * const colorFinderP,
                  tuplehash               const colorhash,       
                  int *                   const colormapIndexP,
                  bool *                  const usehashP) {
/*----------------------------------------------------------------------------
   Look up the color of tuple 'tuple' in the color map indicated by
   'colorFinderP' and, if it's in there, return its index as
   *colormapIndexP.  If not, return *colormapIndexP == -1.

   Both the tuple 'tuple' and the colors in color map 'colormap' are
   described by *pamP.

   If 'needExactMatch' isn't true, we find the closest color in the color map,
   and never return *colormapIndex == -1.

   lookaside at the hash table 'colorhash' to possibly avoid the cost of
   a full lookup.  If we do a full lookup, we add the result to 'colorhash'
   unless *usehashP is false, and if that makes 'colorhash' full, we set
   *usehashP false.
-----------------------------------------------------------------------------*/
    int found;

    /* Check hash table to see if we have already matched this color. */
    pnm_lookuptuple(pamP, colorhash, tuple, &found, colormapIndexP);
    if (!found) {
        /* No, have to do a full lookup */
        if (needExactMatch) {
            bool found;

            searchColormapExact(pamP, colorFinderP, tuple,
                                colormapIndexP, &found);
            if (!found)
                *colormapIndexP = -1;
        } else 
            searchColormapClose(pamP, tuple, colorFinderP, colormapIndexP);
        if (*usehashP) {
            int fits;
            pnm_addtotuplehash(pamP, colorhash, tuple, *colormapIndexP, 
                               &fits);
            if (!fits) {
                pm_message("out of memory adding to hash table; "
                           "proceeding without it");
                *usehashP = FALSE;
            }
        }
    }
}
Example #3
0
static void
doUnlookup(struct pam * const inpamP,
           tuplehash    const lookupHash,
           sample       const maxIndex,
           FILE *       const ofP) {

    struct pam outpam;
    unsigned int row;
    tuple * inrow;
    tuple * outrow;

    inrow = pnm_allocpamrow(inpamP);

    outpam.size = sizeof(outpam);
    outpam.len = PAM_STRUCT_SIZE(tuple_type);
    outpam.file = ofP;
    outpam.format = PAM_FORMAT;
    outpam.height = inpamP->height;
    outpam.width = inpamP->width;
    outpam.depth = 1;
    outpam.maxval = maxIndex + 1;  /* +1 for missing color */
    strcpy(outpam.tuple_type, "INDEX");

    pnm_writepaminit(&outpam);

    outrow = pnm_allocpamrow(&outpam);

    for (row = 0; row < inpamP->height; ++row) {
        unsigned int col;
        
        pnm_readpamrow(inpamP, inrow);

        for (col = 0; col < inpamP->width; ++col) {
            int found;
            int index;
            pnm_lookuptuple(inpamP, lookupHash, inrow[col], &found, &index);

            if (found) {
                assert(index <= outpam.maxval);
                outrow[col][0] = index;
            } else
                outrow[col][0] = maxIndex + 1;
        }
        pnm_writepamrow(&outpam, outrow);
    }

    pnm_freepamrow(outrow);
    pnm_freepamrow(inrow);
}
Example #4
0
static void
putPixel(struct pam *          const pamP,
         tuple                 const tuple, 
         enum TGAbaseImageType const imgType, 
         bool                  const withAlpha,
         tuplehash             const cht) {
/*----------------------------------------------------------------------------
   Write a single pixel of the TGA raster to Standard Output.  The
   pixel is to have color 'tuple'.  The raster has format 'imgType'.
   The color palette from which the specified color is to be drawn, if
   'imgType' indicates use of a color palette, is 'cht'.
-----------------------------------------------------------------------------*/
    if (imgType == TGA_MAP_TYPE) {
        int retval;
        int found;

        pnm_lookuptuple(pamP, cht, tuple, &found, &retval);
        if (!found)
            pm_error("Internal error: color not found in map that was "
                     "generated from all the colors in the image");
        putchar(retval);
    } else {
        if (imgType == TGA_RGB_TYPE && pamP->depth < 3) {
            /* Make RGB pixel out of a single input plane */
            unsigned int plane;
            
            for (plane = 0; plane < 3; ++plane) 
                putchar(pnm_scalesample(tuple[0], 
                                        pamP->maxval, TGA_MAXVAL));
        } else if (imgType == TGA_MONO_TYPE)
            putchar(pnm_scalesample(tuple[0], 
                                    pamP->maxval, TGA_MAXVAL));
        else {
            putchar(pnm_scalesample(tuple[PAM_BLU_PLANE], 
                                    pamP->maxval, TGA_MAXVAL));
            putchar(pnm_scalesample(tuple[PAM_GRN_PLANE], 
                                    pamP->maxval, TGA_MAXVAL));
            putchar(pnm_scalesample(tuple[PAM_RED_PLANE], 
                                    pamP->maxval, TGA_MAXVAL));
            if (withAlpha)
                putchar(pnm_scalesample(tuple[PAM_TRN_PLANE], 
                                        pamP->maxval, TGA_MAXVAL));
        }
    }
}
Example #5
0
static void
makeReverseLookupHash(struct pam * const lookuppamP,
                      tuple **     const lookup,
                      tuplehash *  const hashP) {
/*----------------------------------------------------------------------------
   Create a tuple hash that maps each tuple values in the first row of
   'lookup' to the number of the column in which it appears.

   Abort the program with an error if the same tuple value occurs in two
   columns of the first row.
-----------------------------------------------------------------------------*/
    tuplehash hash;
    unsigned int col;

    hash = pnm_createtuplehash();

    for (col = 0; col < lookuppamP->width; ++col) {
        tuple const thisValue = lookup[0][col];
        
        int found;
        int priorValue;

        pnm_lookuptuple(lookuppamP, hash, thisValue, &found, &priorValue);

        if (found)
            pm_error("Same tuple value occurs in both Column %u and "
                     "Column %u of the lookup image", priorValue, col);
        else {
            int fits;
            pnm_addtotuplehash(lookuppamP, hash, lookup[0][col], col, &fits);

            if (!fits)
                pm_error("Out of memory constructing hash of lookup table");
        }
    }

    *hashP = hash;
}
Example #6
0
static void
writeScanLines(struct pam *   const pamP,
               TIFF *         const tif, 
               tuplehash      const cht,
               unsigned short const tiffMaxval,
               unsigned short const bitspersample, 
               unsigned short const photometric,
               int            const bytesperrow, 
               int            const fillorder) {
/*----------------------------------------------------------------------------
   Write out the raster for the input image described by 'pamP', whose
   file is positioned to the raster of the image.
-----------------------------------------------------------------------------*/
    tuple * tuplerow;  /* malloc'ed */
    unsigned char * buf; /* malloc'ed */
    int row;

    /* The man page for TIFFWriteScanLine doesn't tell the format of
       it's 'buf' parameter, but here it is: Its format depends on the
       bits per pixel of the TIFF image.  If it's 16, 'buf' is an
       array of short (16 bit) integers, one per raster column.  If
       it's 8, 'buf' is an array of characters (8 bit integers), one
       per image column.  If it's less than 8, it's an array of characters,
       each of which represents 1-8 raster columns, packed
       into it in the order specified by the TIFF image's fill order,
       with don't-care bits on the right such that each byte contains only
       whole pixels.

       In all cases, the array elements are in order left to right going
       from low array indices to high array indices.
    */
    MALLOCARRAY(buf, bytesperrow);

    if (buf == NULL)
        pm_error("can't allocate memory for row buffer");

    tuplerow = pnm_allocpamrow(pamP);
    
    for (row = 0; row < pamP->height; ++row) {
        int col;

        pnm_readpamrow(pamP, tuplerow);

        if (cht == NULL) {
            /* It's a direct, non-colormapped raster */

            if (bitspersample == 8 || bitspersample == 16)
                fillRowOfWholeBytePixels(pamP, tuplerow, buf, photometric,
                                         tiffMaxval, bitspersample);
            else
                fillRowOfSubBytePixels(pamP, tuplerow, buf,
                                       tiffMaxval, photometric,
                                       fillorder, bitspersample, NULL);
        } else {
            /* It's a colormapped raster */
            if (bitspersample == 8) {
                for (col = 0; col < pamP->width; ++col) {
                    int si;
                    int found;
                    
                    pnm_lookuptuple(pamP, cht, tuplerow[col], &found, &si);
                    
                    if (!found)
                        pm_error("INTERNAL ERROR.  We made a color map, and a "
                                 "color map we need is not in it!  "
                                 "col=%d  r=%lu g=%lu b=%lu",
                                 col, tuplerow[col][0], tuplerow[col][1],
                                 tuplerow[col][2]);
                    buf[col] = (unsigned char) si;
                }
            } else {
                fillRowOfSubBytePixels(pamP, tuplerow, buf, 0, 0, fillorder,
                                       bitspersample, cht);
            }
        }
        if (TIFFWriteScanline(tif, buf, row, 0) < 0)
            pm_error("failed a scanline write on row %d", row);
    }
    pnm_freepamrow(tuplerow);
    free(buf);
}
Example #7
0
static void
fillRowOfSubBytePixels(struct pam *    const pamP,
                       const tuple *   const tuplerow,
                       unsigned char * const buf,
                       unsigned short  const tiff_maxval,
                       unsigned short  const photometric,
                       int             const fillorder,
                       int             const bitspersample,
                       tuplehash       const cht) {
/*----------------------------------------------------------------------------
  This subroutine deals with cases where multiple pixels are packed into
  a single byte of the Tiff output image, i.e. bits per pixel < 8.
-----------------------------------------------------------------------------*/
    int col;
    int bitshift;
        /* The number of bits we have to shift a pixel value left to line
           it up with where the current pixel goes in the current byte of
           the output buffer.  
        */
    int const firstbitshift = 
        (fillorder == FILLORDER_MSB2LSB) ? 8 - bitspersample : 0;
        /* The value of 'bitshift' for the first pixel into a
           byte of the output buffer.  (MSB2LSB is normal).
        */
    sample s;
        /* The value of the current sample */
    unsigned char* tP;
        /* The address of the byte in the output buffer in which
           the current pixel goes.
        */
    unsigned char byte;
        /* The under-construction value of the byte pointed to by
           tP, above.
        */
                
    bitshift = firstbitshift;
    byte = 0;
    for (col = 0, tP = buf; col < pamP->width; ++col) {
        if (cht == NULL) {
            /* It's grayscale */
            s = tuplerow[col][0];
            if (pamP->maxval != tiff_maxval )
                s = (long) s * tiff_maxval / pamP->maxval;
 
            if (photometric == PHOTOMETRIC_MINISWHITE)
                s = tiff_maxval - s;
        } else {
            /* It's a colormapped raster */
            int si;
            int found;
            pnm_lookuptuple(pamP, cht, tuplerow[col], &found, &si);
            if (!found)
                pm_error("INTERNAL ERROR.  We made a color map, and a "
                         "color map we need is not in it!.  "
                         "col=%d  r=%lu g=%lu b=%lu",
                         col, tuplerow[col][0], tuplerow[col][1],
                         tuplerow[col][2]);
            s = (unsigned char) si;
        }
        byte |= s << bitshift;
        if (fillorder == FILLORDER_MSB2LSB)
            bitshift -= bitspersample;  /* normal case */
        else
            bitshift += bitspersample;
        if (bitshift < 0 || bitshift > 7) {
            *tP++ = byte;
            bitshift = firstbitshift;
            byte = 0;
        }
    }
    if (bitshift != firstbitshift)
        *tP++ = byte;
}