about summary refs log tree commit diff
path: root/converter/other/pamtosvg/pamtosvg.c
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2006-08-19 03:12:28 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2006-08-19 03:12:28 +0000
commit1fd361a1ea06e44286c213ca1f814f49306fdc43 (patch)
tree64c8c96cf54d8718847339a403e5e67b922e8c3f /converter/other/pamtosvg/pamtosvg.c
downloadnetpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.tar.gz
netpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.tar.xz
netpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.zip
Create Subversion repository
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@1 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'converter/other/pamtosvg/pamtosvg.c')
-rw-r--r--converter/other/pamtosvg/pamtosvg.c395
1 files changed, 395 insertions, 0 deletions
diff --git a/converter/other/pamtosvg/pamtosvg.c b/converter/other/pamtosvg/pamtosvg.c
new file mode 100644
index 00000000..31597a4a
--- /dev/null
+++ b/converter/other/pamtosvg/pamtosvg.c
@@ -0,0 +1,395 @@
+/* main.c: main driver for autotrace -- convert bitmaps to splines. */
+
+#include <string.h>
+#include <assert.h>
+#include <math.h>
+
+#include "mallocvar.h"
+#include "nstring.h"
+#include "shhopt.h"
+#include "pam.h"
+
+#include "autotrace.h"
+#include "message.h"
+#include "logreport.h"
+#include "output-svg.h"
+#include "bitmap.h"
+
+#define dot_printer_max_column 50
+#define dot_printer_char '|'
+
+
+
+static void
+readImageToBitmap(FILE *            const ifP,
+                  at_bitmap_type ** const bitmapPP) {
+
+    at_bitmap_type * bitmapP;
+    struct pam pam;
+    tuple ** tuples;
+    uint row;
+    tuple * row255;
+
+    MALLOCVAR_NOFAIL(bitmapP);
+
+    tuples = pnm_readpam(ifP, &pam, PAM_STRUCT_SIZE(tuple_type));
+
+    bitmapP->width  = pam.width;
+    bitmapP->height = pam.height;
+    bitmapP->np     = pam.depth;
+
+    MALLOCARRAY(bitmapP->bitmap, pam.width * pam.height * pam.depth);
+
+    row255 = pnm_allocpamrow(&pam);
+
+    for (row = 0; row < pam.height; ++row) {
+        unsigned int col;
+
+        pnm_scaletuplerow(&pam, row255, tuples[row], 255);
+        
+        for (col = 0; col < pam.width; ++col) {
+            unsigned int plane;
+
+            for (plane = 0; plane < pam.depth; ++plane) {
+                unsigned int const bitmapIndex = 
+                    (row * pam.width + col) * pam.depth + plane;
+                bitmapP->bitmap[bitmapIndex] = row255[col][plane];
+            }
+        }
+    }
+    pnm_freepamrow(row255);
+    pnm_freepamarray(tuples, &pam);
+    
+    *bitmapPP = bitmapP;
+}
+
+
+
+static void
+dotPrinter(float  const percentage,
+           void * const clientData) {
+
+    int * const currentP = (int *)clientData;
+    float const unit     = (float)1.0 / (float)(dot_printer_max_column) ;
+    int   const maximum  = (int)(percentage / unit);
+    
+    while (*currentP < maximum) {
+        fputc(dot_printer_char, stderr);
+        (*currentP)++;
+    }
+}
+
+
+
+static void
+exceptionHandler(const char * const msg,
+                 at_msg_type  const type,
+                 void *       const data) {
+
+    if (type == AT_MSG_FATAL)
+        pm_error("%s", msg);
+    else if (type == AT_MSG_WARNING)
+        pm_message("%s", msg);
+    else
+        exceptionHandler("Wrong type of msg", AT_MSG_FATAL, NULL);
+}
+
+
+
+struct cmdlineInfo {
+    const char * inputFileName;
+    float        align_threshold;
+    unsigned int backgroundSpec;
+    pixel        background_color;
+    unsigned int centerline;
+    float        corner_always_threshold;
+    unsigned int corner_surround;
+    float        corner_threshold;
+    unsigned int dpi;
+    float        error_threshold;
+    unsigned int filter_iterations;
+    float        line_reversion_threshold;
+    float        line_threshold;
+    unsigned int log;
+    unsigned int preserve_width;
+    unsigned int remove_adjacent_corners;
+    unsigned int tangent_surround;
+    unsigned int report_progress;
+    float        width_weight_factor;
+};
+
+
+static void 
+parseCommandLine(int argc, 
+                 char ** argv, 
+                 struct cmdlineInfo  * const cmdlineP) {
+/* --------------------------------------------------------------------------
+   Parse program command line described in Unix standard form by argc
+   and argv.  Return the information in the options as *cmdlineP.  
+
+   If command line is internally inconsistent (invalid options, etc.),
+   issue error message to stderr and abort program.
+
+   Note that the strings we return are stored in the storage that
+   was passed to us as the argv array.  We also trash *argv.
+--------------------------------------------------------------------------*/
+    optEntry *option_def;
+    /* Instructions to optParseOptions3 on how to parse our options. */
+    optStruct3 opt;
+
+    const char * background_colorOpt;
+  
+    unsigned int option_def_index;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENT3 */
+    OPTENT3(0, "align-threshold",     OPT_FLOAT,
+            &cmdlineP->align_threshold,  NULL,                              0);
+    OPTENT3(0, "background-color",    OPT_STRING,
+            &background_colorOpt,        &cmdlineP->backgroundSpec,         0);
+    OPTENT3(0, "centerline",          OPT_FLAG,
+            NULL,                        &cmdlineP->centerline,             0);
+    OPTENT3(0, "corner-always-threshold", OPT_FLOAT, 
+            &cmdlineP->corner_always_threshold, NULL,                       0);
+    OPTENT3(0, "corner-surround",     OPT_UINT,
+            &cmdlineP->corner_surround,  NULL,                              0);
+    OPTENT3(0, "corner-threshold",    OPT_FLOAT,
+            &cmdlineP->corner_threshold, NULL,                              0);
+    OPTENT3(0, "dpi",                 OPT_UINT,
+            &cmdlineP->dpi,              NULL,                              0);
+    OPTENT3(0, "error-threshold",     OPT_FLOAT,
+            &cmdlineP->error_threshold,  NULL,                              0);
+    OPTENT3(0, "filter-iterations",   OPT_UINT,
+            &cmdlineP->filter_iterations, NULL,                             0);
+    OPTENT3(0, "line-reversion-threshold", OPT_FLOAT,
+            &cmdlineP->line_reversion_threshold, NULL,                    0);
+    OPTENT3(0, "line-threshold",      OPT_FLOAT,
+            &cmdlineP->line_threshold, NULL,                                0);
+    OPTENT3(0, "log",                 OPT_FLAG,
+            NULL,                         &cmdlineP->log,                   0);
+    OPTENT3(0, "preserve-width",      OPT_FLAG,
+            NULL,                         &cmdlineP->preserve_width,        0);
+    OPTENT3(0, "remove-adjacent-corners", OPT_UINT,
+            NULL,                       &cmdlineP->remove_adjacent_corners, 0);
+    OPTENT3(0, "tangent-surround",    OPT_UINT,    
+            &cmdlineP->tangent_surround, NULL,                              0);
+    OPTENT3(0, "report-progress",     OPT_FLAG,
+            NULL,                       &cmdlineP->report_progress,         0);
+    OPTENT3(0, "width-weight-factor", OPT_FLOAT,    
+            &cmdlineP->width_weight_factor, NULL,                           0);
+
+
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = FALSE;   /* We have no parms that are negative numbers */
+
+    /* Set some defaults the lazy way (using multiple setting of variables) */
+
+    cmdlineP->corner_always_threshold  = 60.0;
+    cmdlineP->corner_surround          = 4;
+    cmdlineP->corner_threshold         = 100.0;
+    cmdlineP->error_threshold          = 2.0;
+    cmdlineP->filter_iterations        = 4;
+    cmdlineP->line_reversion_threshold = 0.01;
+    cmdlineP->line_threshold           = 1.0;
+    cmdlineP->tangent_surround         = 3;
+    cmdlineP->width_weight_factor      = 6.0;
+
+    optParseOptions3( &argc, argv, opt, sizeof(opt), 0 );
+    /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (cmdlineP->backgroundSpec)
+        cmdlineP->background_color = ppm_parsecolor(background_colorOpt, 255);
+
+    if (argc-1 < 1)
+        cmdlineP->inputFileName = "-";
+    else {
+        cmdlineP->inputFileName = argv[1];
+        
+        if (argc-1 > 1)
+            pm_error("Too many arguments (%u).  The only non-option argument "
+                     "is the input file name.", argc-1);
+    }
+}
+
+
+
+static void
+fitSplines(at_bitmap_type *             const bitmapP,
+           struct cmdlineInfo           const cmdline,
+           at_msg_func                        exceptionHandler,
+           at_progress_func                   progressFunc,
+           at_spline_list_array_type ** const splinesPP) {
+
+    unsigned int progressStat;
+    at_fitting_opts_type * fittingOptsP;
+
+    progressStat = 0;
+           
+    fittingOptsP = at_fitting_opts_new();
+
+    fittingOptsP->backgroundSpec           = cmdline.backgroundSpec;
+    fittingOptsP->background_color         = cmdline.background_color;
+    fittingOptsP->corner_always_threshold  = cmdline.corner_always_threshold;
+    fittingOptsP->corner_surround          = cmdline.corner_surround;
+    fittingOptsP->corner_threshold         = cmdline.corner_threshold;
+    fittingOptsP->error_threshold          = cmdline.error_threshold;
+    fittingOptsP->filter_iterations        = cmdline.filter_iterations;
+    fittingOptsP->line_reversion_threshold = cmdline.line_reversion_threshold;
+    fittingOptsP->line_threshold           = cmdline.line_threshold;
+    fittingOptsP->remove_adjacent_corners  = cmdline.remove_adjacent_corners;
+    fittingOptsP->tangent_surround         = cmdline.tangent_surround;
+    fittingOptsP->centerline               = cmdline.centerline;
+    fittingOptsP->preserve_width           = cmdline.preserve_width;
+    fittingOptsP->width_weight_factor      = cmdline.width_weight_factor;
+
+    *splinesPP = at_splines_new_full(bitmapP, fittingOptsP,
+                                     exceptionHandler, NULL,
+                                     progressFunc, &progressStat,
+                                     NULL, NULL);
+
+    at_fitting_opts_free(fittingOptsP);
+}
+  
+
+
+static void
+writeSplines(at_spline_list_array_type * const splinesP,
+             struct cmdlineInfo          const cmdline,
+             at_output_write_func              outputWriter,
+             FILE *                      const ofP,
+             at_msg_func                       exceptionHandler) {
+
+    at_output_opts_type * outputOptsP;
+
+    outputOptsP = at_output_opts_new();
+    outputOptsP->dpi = cmdline.dpi;
+    
+    at_splines_write(outputWriter, ofP, outputOptsP,
+                     splinesP, exceptionHandler, NULL);
+
+    at_output_opts_free(outputOptsP);
+}  
+
+
+
+static const char *
+filenameRoot(const char * const filename) {
+/*----------------------------------------------------------------------------
+   Return the root of the filename.  E.g. for /home/bryanh/foo.ppm,
+   return 'foo'.
+-----------------------------------------------------------------------------*/
+    char * buffer;
+    bool foundSlash;
+    unsigned int slashPos;
+    bool foundDot;
+    unsigned int dotPos;
+    unsigned int rootStart, rootEnd;
+    unsigned int i, j;
+
+    for (i = 0, foundSlash = FALSE; i < strlen(filename); ++i) {
+        if (filename[i] == '/') {
+            foundSlash = TRUE;
+            slashPos = i;
+        }
+    }
+
+    if (foundSlash)
+        rootStart = slashPos + 1;
+    else
+        rootStart = 0;
+
+    for (i = rootStart, foundDot = FALSE; i < strlen(filename); ++i) {
+        if (filename[i] == '.') {
+            foundDot = TRUE;
+            dotPos = i;
+        }
+    }
+
+    if (foundDot)
+        rootEnd = dotPos;
+    else
+        rootEnd = strlen(filename);
+
+    MALLOCARRAY(buffer, rootEnd - rootStart + 1);
+    
+    j = 0;
+    for (i = rootStart; i < rootEnd; ++i)
+        buffer[j++] = filename[i];
+
+    buffer[j] = '\0';
+    
+    return buffer;
+}
+
+
+
+static void
+openLogFile(FILE **      const logFileP,
+            const char * const inputRootName) {
+
+    const char * logfileName;
+
+    asprintfN(&logfileName, "%s.log", inputRootName);
+
+    *logFileP = pm_openw(logfileName);
+
+    strfree(logfileName);
+}
+    
+
+
+int
+main(int argc, char * argv[]) {
+
+    struct cmdlineInfo cmdline;
+    FILE * ifP;
+    at_bitmap_type * bitmapP;
+    at_spline_list_array_type * splinesP;
+    at_progress_func progressReporter;
+    const char * inputRootName;
+
+    pnm_init(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFileName);
+
+    inputRootName = filenameRoot(cmdline.inputFileName);
+    if (inputRootName == NULL)
+        pm_error("Can't find the root portion of file name '%s'",
+                 cmdline.inputFileName);
+    
+    if (cmdline.log)
+        openLogFile(&log_file, inputRootName);
+
+    readImageToBitmap(ifP, &bitmapP);
+    
+    if (cmdline.report_progress) {
+        progressReporter = dotPrinter;
+        fprintf(stderr, "%-15s", cmdline.inputFileName);
+    } else
+        progressReporter = NULL;
+
+    fitSplines(bitmapP, cmdline, exceptionHandler,
+               progressReporter, &splinesP);
+
+    writeSplines(splinesP, cmdline, output_svg_writer, stdout,
+                 exceptionHandler);
+
+    strfree(inputRootName);
+
+    pm_close(stdout);
+    pm_close(ifP);
+    if (cmdline.log)
+        pm_close(log_file);
+    
+    at_splines_free(splinesP);
+    at_bitmap_free(bitmapP);
+
+    if (cmdline.report_progress)
+        fputs("\n", stderr);
+    
+    return 0;
+}