diff options
author | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2006-08-19 03:12:28 +0000 |
---|---|---|
committer | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2006-08-19 03:12:28 +0000 |
commit | 1fd361a1ea06e44286c213ca1f814f49306fdc43 (patch) | |
tree | 64c8c96cf54d8718847339a403e5e67b922e8c3f /converter/other/pamtosvg/pamtosvg.c | |
download | netpbm-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.c | 395 |
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; +} |