about summary refs log tree commit diff
path: root/converter/other/pamtoxvmini.c
diff options
context:
space:
mode:
Diffstat (limited to 'converter/other/pamtoxvmini.c')
-rw-r--r--converter/other/pamtoxvmini.c250
1 files changed, 250 insertions, 0 deletions
diff --git a/converter/other/pamtoxvmini.c b/converter/other/pamtoxvmini.c
new file mode 100644
index 00000000..dc56e912
--- /dev/null
+++ b/converter/other/pamtoxvmini.c
@@ -0,0 +1,250 @@
+/*=============================================================================
+                                    pamtoxvmini
+===============================================================================
+   Convert Netpbm image to XV mini thumbnail.
+
+   Written by Bryan Henderson in April 2006 and contributed to the public
+   domain.
+=============================================================================*/
+
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+
+#include "pm_c_util.h"
+#include "nstring.h"
+#include "pam.h"
+#include "pammap.h"
+
+typedef struct xvPalette {
+    unsigned int red[256];
+    unsigned int grn[256];
+    unsigned int blu[256];
+} xvPalette;
+
+
+struct cmdlineInfo {
+    const char * inputFileName;
+};
+
+
+
+static void
+parseCommandLine(int const argc,
+                 char *    argv[],
+                 struct cmdlineInfo * const cmdlineP) {
+
+    if (argc-1 < 1)
+        cmdlineP->inputFileName = "-";
+    else {
+        cmdlineP->inputFileName = argv[1];
+
+        if (argc-1 > 1)
+            pm_error("Too many arguments: %u.  Only argument is optional "
+                     "input file name.", argc-1);
+    }
+}
+
+
+
+static void
+makeXvPalette(xvPalette * const xvPaletteP) {
+
+    unsigned int paletteIndex;
+    unsigned int r;
+
+    paletteIndex = 0;
+
+    for (r = 0; r < 8; ++r) {
+        unsigned int g;
+        for (g = 0; g < 8; ++g) {
+            unsigned int b;
+            for (b = 0; b < 4; ++b) {
+                xvPaletteP->red[paletteIndex] = (r*255)/7;
+                xvPaletteP->grn[paletteIndex] = (g*255)/7;
+                xvPaletteP->blu[paletteIndex] = (b*255)/3;
+                ++paletteIndex;
+            }
+        }
+    }
+
+}
+
+
+
+static void
+writeXvHeader(FILE *       const ofP,
+              unsigned int const cols,
+              unsigned int const rows,
+              unsigned int const maxval) {
+           
+    fprintf(ofP, "P7 332\n");
+
+    fprintf(ofP, "# Created by Pamtoxvmini\n");
+    fprintf(ofP, "#END_OF_COMMENTS\n");
+
+    fprintf(ofP, "%u %u %u\n", cols, rows, maxval);
+}
+
+
+
+static void
+findClosestColor(struct pam *      const pamP,
+                 tuple             const tuple, 
+                 const xvPalette * const xvPaletteP,
+                 unsigned int *    const paletteIndexP) {
+/*----------------------------------------------------------------------------
+   Find the color in the palette *xvPaletteP that is closest to the color
+   'tuple' and return its index in the palette.
+-----------------------------------------------------------------------------*/
+    unsigned int paletteIndex;
+    unsigned int bestPaletteIndex;
+    unsigned int bestDistanceSoFar;
+
+    /* An entry condition is that the tuple have the same form as the
+       colors in the XV palette:
+    */
+    assert(pamP->depth >= 3);
+    assert(pamP->maxval = 255);
+
+    bestPaletteIndex = 0;
+    bestDistanceSoFar = UINT_MAX;
+
+    for (paletteIndex = 0; paletteIndex < 256; ++paletteIndex) {
+        unsigned int const tupleRed = tuple[PAM_RED_PLANE];
+        unsigned int const tupleGrn = tuple[PAM_GRN_PLANE];
+        unsigned int const tupleBlu = tuple[PAM_BLU_PLANE];
+        
+        unsigned int const paletteRed = xvPaletteP->red[paletteIndex];
+        unsigned int const paletteGrn = xvPaletteP->grn[paletteIndex];
+        unsigned int const paletteBlu = xvPaletteP->blu[paletteIndex];
+
+        unsigned int const distance = 
+            SQR((int)tupleRed - (int)paletteRed) +
+            SQR((int)tupleGrn - (int)paletteGrn) +
+            SQR((int)tupleBlu - (int)paletteBlu);
+
+        if (distance < bestDistanceSoFar) {
+            bestDistanceSoFar = distance;
+            bestPaletteIndex = paletteIndex;
+        }
+    }
+    *paletteIndexP = bestPaletteIndex;
+}
+
+
+
+static void
+getPaletteIndexThroughCache(struct pam *      const pamP,
+                            tuple             const tuple,
+                            const xvPalette * const xvPaletteP,
+                            tuplehash         const paletteHash,
+                            unsigned int *    const paletteIndexP) {
+/*----------------------------------------------------------------------------
+   Return as *paletteIndexP the index into the palette *xvPaletteP of
+   the color that most closely resembles the color 'tuple'.
+
+   Use the hash table *paletteIndexP as a cache to speed up the search.
+   If the tuple-index association is in *paletteIndexP, use it.  If not,
+   find it the hard way and add it to *palettedIndexP for the next guy.
+-----------------------------------------------------------------------------*/
+    bool found;
+    int paletteIndex;
+
+    pnm_lookuptuple(pamP, paletteHash, tuple, &found, &paletteIndex);
+    if (found)
+        *paletteIndexP = paletteIndex;
+    else {
+        bool fits;
+        findClosestColor(pamP, tuple, xvPaletteP, paletteIndexP);
+        
+        pnm_addtotuplehash(pamP, paletteHash, tuple, *paletteIndexP, &fits);
+        
+        if (!fits)
+            pm_error("Can't get memory for palette hash.");
+    }
+}
+
+    
+
+static void
+writeXvRaster(struct pam * const pamP,
+              xvPalette *  const xvPaletteP,
+              FILE *       const ofP) {
+/*----------------------------------------------------------------------------
+   Write out the XV image, from the Netpbm input file ifP, which is
+   positioned to the raster.
+
+   The XV raster contains palette indices into the palette *xvPaletteP.
+
+   If there is any color in the image which is not in the palette, we
+   fail the program.  We really should use the closest color in the palette
+   instead.
+-----------------------------------------------------------------------------*/
+    tuplehash paletteHash;
+    tuple * tuplerow;
+    unsigned int row;
+    unsigned char * xvrow;
+
+    paletteHash = pnm_createtuplehash();
+
+    tuplerow = pnm_allocpamrow(pamP);
+    xvrow = (unsigned char*)pm_allocrow(pamP->width, 1);
+
+    for (row = 0; row < pamP->height; ++row) {
+        unsigned int col;
+
+        pnm_readpamrow(pamP, tuplerow);
+        pnm_scaletuplerow(pamP, tuplerow, tuplerow, 255);
+        pnm_makerowrgb(pamP, tuplerow);
+
+        for (col = 0; col < pamP->width; ++col) {
+            unsigned int paletteIndex;
+
+            getPaletteIndexThroughCache(pamP, tuplerow[col], xvPaletteP,
+                                        paletteHash, &paletteIndex);
+
+            assert(paletteIndex < 256);
+
+            xvrow[col] = paletteIndex;
+        }
+        fwrite(xvrow, 1, pamP->width, ofP);
+    }
+
+    pm_freerow((char*)xvrow);
+    pnm_freepamrow(pamP);
+
+    pnm_destroytuplehash(paletteHash);
+}
+
+
+
+int 
+main(int    argc,
+     char * argv[]) {
+
+    struct cmdlineInfo cmdline;
+    FILE * ifP;
+    struct pam pam;
+    xvPalette xvPalette;
+ 
+    ppm_init(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFileName);
+
+    makeXvPalette(&xvPalette);
+
+    pnm_readpaminit(ifP, &pam, PAM_STRUCT_SIZE(allocation_depth));
+
+    pnm_setminallocationdepth(&pam, 3);
+
+    writeXvHeader(stdout, pam.width, pam.height, pam.maxval);
+    
+    writeXvRaster(&pam, &xvPalette, stdout);
+
+    pm_close(ifP);
+
+    return 0;
+}