diff options
Diffstat (limited to 'src/pnmcurve.c')
| -rw-r--r-- | src/pnmcurve.c | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/src/pnmcurve.c b/src/pnmcurve.c new file mode 100644 index 0000000..e170f36 --- /dev/null +++ b/src/pnmcurve.c @@ -0,0 +1,168 @@ +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <math.h> + +#include <gsl/gsl_spline.h> + +#include "pnm.h" + +typedef struct { + int n; + short value[1]; +} table_t; + +static int +pam_transform(FILE *in_fp, FILE *out_fp, + const struct pnm *in_pnm, table_t **tables); + +static table_t* +buildCurve(const char *ctrl_points, int resolution); + +#define RED 0x1 +#define GREEN 0x2 +#define BLUE 0x4 + +int +main(int argc, char **argv) { + int c, i; + char *curve = NULL; + struct pnm in_pnm; + int channels = 0; + table_t *gTable[3]; + + while ((c = getopt(argc, argv, "rgbC:h")) != EOF) { + switch (c) { + case 'r': + channels |= RED; + break; + case 'g': + channels |= GREEN; + break; + case 'b': + channels |= BLUE; + break; + case 'C': + curve = optarg; + break; + + default: + break; + } + } + + if (readPnmHeader(stdin, &in_pnm) != 0) { + exit(1); + } + + if (in_pnm.maxval == 255) { + } else if (in_pnm.maxval == 65535) { + } else { + fprintf(stderr, "unsupported PNM maxval %d\n", in_pnm.maxval); + exit(1); + } + + if (curve) { + table_t *table; + + if (channels == 0) channels = RED | GREEN | BLUE; + + table = buildCurve(curve, 256); + + gTable[0] = channels & RED?table:NULL; + gTable[1] = channels & GREEN?table:NULL; + gTable[2] = channels & BLUE?table:NULL; + + } + + writePnmHeader(stdout, &in_pnm); + + pam_transform(stdin, stdout, &in_pnm, gTable); + + return 0; +} + +static int +pam_transform(FILE *in_fp, FILE *out_fp, + const struct pnm *in_pnm, table_t **tables) { + int row, col; + int nbytes = in_pnm->maxval == 65535?2:1; + char *buf = malloc(in_pnm->width * nbytes * 3); + + for (row = 0; row < in_pnm->height; row++) { + fread(buf, in_pnm->width, nbytes * 3, in_fp); + + for (i = 0; i < in_pnm->width; i++) { + for (c = 0; c < in_pnm->depth; c++) { + if (tables[c]) { + int val = (unsigned char) buf[(i * in_pnm->depth + c) * nbytes]; + if (nbytes == 2) { + val = (val << 8) | + (uchar) buf[(i * in_pnm->depth + c) * nbytes + 1]; + } + + bud + + } + } + } + + fwrite(buf, in_pnm->width, nbytes * 3, out_fp); + } + + free(buf); + return 0; +} + +#define MAX_CTRL 256 + +static table_t* +buildCurve(const char *ctrl_points, int resolution) { + table_t *table; + char *pstr, *buf = strdup(ctrl_points); + int i, n = 0; + double X[MAX_CTRL], Y[MAX_CTRL]; + gsl_interp_accel *acc; + gsl_spline *spline; + + while (pstr = strsep(&buf, ",")) { + if (n == MAX_CTRL) { + fprintf(stderr, "Maximum number of control points (%d) reached.\n", + MAX_CTRL); + break; + } + + if (sscanf(pstr, "%lf:%lf", &X[n], &Y[n]) != 2 || + X[n] < 0.0 || X[n] > 1.0 || Y[n] < 0.0 || Y[n] > 1.0) { + fprintf(stderr, "Could not parse control point %s.\n", pstr); + free(buf); + return NULL; + } + + n++; + } + + free(buf); + + table = (table_t*) malloc(sizeof(table_t) + resolution * sizeof(short)); + table->n = resolution; + + acc = gsl_interp_accel_alloc(); + spline = gsl_spline_alloc(gsl_interp_cspline, n); + gsl_spline_init (spline, X, Y, n); + + for (i = 0; i < resolution; i++) { + double _x = (double) i / (resolution - 1); + double _y = gsl_spline_eval(spline, _x, acc); + double dval = _y * 65535.0 + .5; + if (dval > 65535.) dval = 65535.0; + if (dval < 0) dval = 0; + + table->value[i] = (short) floor(dval); + } + + gsl_spline_free(spline); + gsl_interp_accel_free(acc); + + return table; +} |
