00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027 #include <gimp-print/gimp-print.h>
00028 #include "gimp-print-internal.h"
00029 #include <gimp-print/gimp-print-intl-internal.h>
00030 #include <math.h>
00031 #include <string.h>
00032 #include <stdlib.h>
00033 #include <limits.h>
00034 #include <unistd.h>
00035 #include <sys/types.h>
00036 #include <sys/stat.h>
00037
00038 #ifdef __GNUC__
00039 #define inline __inline__
00040 #endif
00041
00042
00043 static const int curve_point_limit = 1048576;
00044
00045 struct stp_curve
00046 {
00047 stp_curve_type_t curve_type;
00048 stp_curve_wrap_mode_t wrap_mode;
00049 int recompute_interval;
00050 double gamma;
00051 stp_sequence_t *seq;
00052 double *interval;
00053
00054
00055 };
00056
00057 static const char *const stpi_curve_type_names[] =
00058 {
00059 "linear",
00060 "spline",
00061 };
00062
00063 static const int stpi_curve_type_count =
00064 (sizeof(stpi_curve_type_names) / sizeof(const char *));
00065
00066 static const char *const stpi_wrap_mode_names[] =
00067 {
00068 "nowrap",
00069 "wrap"
00070 };
00071
00072 static const int stpi_wrap_mode_count =
00073 (sizeof(stpi_wrap_mode_names) / sizeof(const char *));
00074
00075
00076
00077
00078 static void
00079 check_curve(const stp_curve_t *curve)
00080 {
00081 if (curve == NULL)
00082 {
00083 stp_erprintf("Null curve! Please report this bug.\n");
00084 stp_abort();
00085 }
00086 if (curve->seq == NULL)
00087 {
00088 stp_erprintf("Bad curve (seq == NULL)! Please report this bug.\n");
00089 stp_abort();
00090 }
00091 }
00092
00093
00094
00095
00096 static size_t
00097 get_real_point_count(const stp_curve_t *curve)
00098 {
00099 return stp_sequence_get_size(curve->seq);
00100 }
00101
00102
00103
00104
00105
00106
00107 static size_t
00108 get_point_count(const stp_curve_t *curve)
00109 {
00110 size_t count;
00111
00112 count = stp_sequence_get_size(curve->seq);
00113 if (curve->wrap_mode == STP_CURVE_WRAP_AROUND)
00114 count -= 1;
00115
00116 return count;
00117 }
00118
00119 static void
00120 invalidate_auxiliary_data(stp_curve_t *curve)
00121 {
00122 if (curve->interval)
00123 {
00124 stp_free(curve->interval);
00125 curve->interval = NULL;
00126 }
00127 }
00128
00129 static void
00130 clear_curve_data(stp_curve_t *curve)
00131 {
00132 if (curve->seq)
00133 stp_sequence_set_size(curve->seq, 0);
00134 curve->recompute_interval = 0;
00135 invalidate_auxiliary_data(curve);
00136 }
00137
00138 static void
00139 compute_linear_deltas(stp_curve_t *curve)
00140 {
00141 int i;
00142 size_t delta_count;
00143 size_t seq_point_count;
00144 const double *data;
00145
00146 stp_sequence_get_data(curve->seq, &seq_point_count, &data);
00147 if (data == NULL)
00148 return;
00149
00150 delta_count = get_real_point_count(curve);
00151
00152 if (delta_count <= 1)
00153 return;
00154 delta_count--;
00155
00156
00157 curve->interval = stp_malloc(sizeof(double) * delta_count);
00158 for (i = 0; i < delta_count; i++)
00159 curve->interval[i] = data[i + 1] - data[i];
00160 }
00161
00162 static void
00163 compute_spline_deltas(stp_curve_t *curve)
00164 {
00165 int i;
00166 int k;
00167 double *u;
00168 double *y2;
00169 const double *y;
00170 size_t point_count;
00171 size_t real_point_count;
00172 double sig;
00173 double p;
00174
00175 point_count = get_point_count(curve);
00176
00177 stp_sequence_get_data(curve->seq, &real_point_count, &y);
00178 u = stp_malloc(sizeof(double) * real_point_count);
00179 y2 = stp_malloc(sizeof(double) * real_point_count);
00180
00181 if (curve->wrap_mode == STP_CURVE_WRAP_AROUND)
00182 {
00183 int reps = 3;
00184 int count = reps * real_point_count;
00185 double *y2a = stp_malloc(sizeof(double) * count);
00186 double *ua = stp_malloc(sizeof(double) * count);
00187 y2a[0] = 0.0;
00188 ua[0] = 0.0;
00189 for (i = 1; i < count - 1; i++)
00190 {
00191 int im1 = (i - 1);
00192 int ip1 = (i + 1);
00193 int im1a = im1 % point_count;
00194 int ia = i % point_count;
00195 int ip1a = ip1 % point_count;
00196
00197 sig = (i - im1) / (ip1 - im1);
00198 p = sig * y2a[im1] + 2.0;
00199 y2a[i] = (sig - 1.0) / p;
00200
00201 ua[i] = y[ip1a] - 2 * y[ia] + y[im1a];
00202 ua[i] = 3.0 * ua[i] - sig * ua[im1] / p;
00203 }
00204 y2a[count - 1] = 0.0;
00205 for (k = count - 2 ; k >= 0; k--)
00206 y2a[k] = y2a[k] * y2a[k + 1] + ua[k];
00207 memcpy(u, ua + ((reps / 2) * point_count),
00208 sizeof(double) * real_point_count);
00209 memcpy(y2, y2a + ((reps / 2) * point_count),
00210 sizeof(double) * real_point_count);
00211 stp_free(y2a);
00212 stp_free(ua);
00213 }
00214 else
00215 {
00216 int count = real_point_count - 1;
00217
00218 y2[0] = 0;
00219 u[0] = 2 * (y[1] - y[0]);
00220 for (i = 1; i < count; i++)
00221 {
00222 int im1 = (i - 1);
00223 int ip1 = (i + 1);
00224
00225 sig = (i - im1) / (ip1 - im1);
00226 p = sig * y2[im1] + 2.0;
00227 y2[i] = (sig - 1.0) / p;
00228
00229 u[i] = y[ip1] - 2 * y[i] + y[im1];
00230 u[i] = 3.0 * u[i] - sig * u[im1] / p;
00231 }
00232
00233 u[count] = 2 * (y[count] - y[count - 1]);
00234 y2[count] = 0.0;
00235
00236 u[count] = 0.0;
00237 for (k = real_point_count - 2; k >= 0; k--)
00238 y2[k] = y2[k] * y2[k + 1] + u[k];
00239 }
00240
00241 curve->interval = y2;
00242 stp_free(u);
00243 }
00244
00245
00246
00247
00248
00249
00250 static void
00251 compute_intervals(stp_curve_t *curve)
00252 {
00253 if (curve->interval)
00254 {
00255 stp_free(curve->interval);
00256 curve->interval = NULL;
00257 }
00258 if (stp_sequence_get_size(curve->seq) > 0)
00259 {
00260 switch (curve->curve_type)
00261 {
00262 case STP_CURVE_TYPE_SPLINE:
00263 compute_spline_deltas(curve);
00264 break;
00265 case STP_CURVE_TYPE_LINEAR:
00266 compute_linear_deltas(curve);
00267 break;
00268 }
00269 }
00270 curve->recompute_interval = 0;
00271 }
00272
00273 static int
00274 stpi_curve_set_points(stp_curve_t *curve, size_t points)
00275 {
00276 if (points < 2)
00277 return 0;
00278 if (points > curve_point_limit ||
00279 (curve->wrap_mode == STP_CURVE_WRAP_AROUND &&
00280 points > curve_point_limit - 1))
00281 return 0;
00282 clear_curve_data(curve);
00283 if (curve->wrap_mode == STP_CURVE_WRAP_AROUND)
00284 points++;
00285 if ((stp_sequence_set_size(curve->seq, points)) == 0)
00286 return 0;
00287 return 1;
00288 }
00289
00290
00291
00292
00293 static void
00294 stpi_curve_ctor(stp_curve_t *curve, stp_curve_wrap_mode_t wrap_mode)
00295 {
00296 curve->seq = stp_sequence_create();
00297 stp_sequence_set_bounds(curve->seq, 0.0, 1.0);
00298 curve->curve_type = STP_CURVE_TYPE_LINEAR;
00299 curve->wrap_mode = wrap_mode;
00300 stpi_curve_set_points(curve, 2);
00301 curve->recompute_interval = 1;
00302 if (wrap_mode == STP_CURVE_WRAP_NONE)
00303 curve->gamma = 1.0;
00304 stp_sequence_set_point(curve->seq, 0, 0);
00305 stp_sequence_set_point(curve->seq, 1, 1);
00306 }
00307
00308 stp_curve_t *
00309 stp_curve_create(stp_curve_wrap_mode_t wrap_mode)
00310 {
00311 stp_curve_t *ret;
00312 if (wrap_mode != STP_CURVE_WRAP_NONE && wrap_mode != STP_CURVE_WRAP_AROUND)
00313 return NULL;
00314 ret = stp_zalloc(sizeof(stp_curve_t));
00315 stpi_curve_ctor(ret, wrap_mode);
00316 return ret;
00317 }
00318
00319 static void
00320 curve_dtor(stp_curve_t *curve)
00321 {
00322 check_curve(curve);
00323 clear_curve_data(curve);
00324 if (curve->seq)
00325 stp_sequence_destroy(curve->seq);
00326 memset(curve, 0, sizeof(stp_curve_t));
00327 curve->curve_type = -1;
00328 }
00329
00330 void
00331 stp_curve_destroy(stp_curve_t *curve)
00332 {
00333 curve_dtor(curve);
00334 stp_free(curve);
00335 }
00336
00337 void
00338 stp_curve_copy(stp_curve_t *dest, const stp_curve_t *source)
00339 {
00340 check_curve(dest);
00341 check_curve(source);
00342 curve_dtor(dest);
00343 dest->curve_type = source->curve_type;
00344 dest->wrap_mode = source->wrap_mode;
00345 dest->gamma = source->gamma;
00346 dest->seq = stp_sequence_create_copy(source->seq);
00347 dest->recompute_interval = 1;
00348 }
00349
00350 stp_curve_t *
00351 stp_curve_create_copy(const stp_curve_t *curve)
00352 {
00353 stp_curve_t *ret;
00354 check_curve(curve);
00355 ret = stp_curve_create(curve->wrap_mode);
00356 stp_curve_copy(ret, curve);
00357 return ret;
00358 }
00359
00360 int
00361 stp_curve_set_bounds(stp_curve_t *curve, double low, double high)
00362 {
00363 check_curve(curve);
00364 return stp_sequence_set_bounds(curve->seq, low, high);
00365 }
00366
00367 void
00368 stp_curve_get_bounds(const stp_curve_t *curve, double *low, double *high)
00369 {
00370 check_curve(curve);
00371 stp_sequence_get_bounds(curve->seq, low, high);
00372 }
00373
00374
00375
00376
00377
00378
00379
00380 void
00381 stp_curve_get_range(const stp_curve_t *curve, double *low, double *high)
00382 {
00383 check_curve(curve);
00384 stp_sequence_get_range(curve->seq, low, high);
00385 }
00386
00387 size_t
00388 stp_curve_count_points(const stp_curve_t *curve)
00389 {
00390 check_curve(curve);
00391 return get_point_count(curve);
00392 }
00393
00394 stp_curve_wrap_mode_t
00395 stp_curve_get_wrap(const stp_curve_t *curve)
00396 {
00397 check_curve(curve);
00398 return curve->wrap_mode;
00399 }
00400
00401 int
00402 stp_curve_set_interpolation_type(stp_curve_t *curve, stp_curve_type_t itype)
00403 {
00404 check_curve(curve);
00405 if (itype < 0 || itype >= stpi_curve_type_count)
00406 return 0;
00407 curve->curve_type = itype;
00408 return 1;
00409 }
00410
00411 stp_curve_type_t
00412 stp_curve_get_interpolation_type(const stp_curve_t *curve)
00413 {
00414 check_curve(curve);
00415 return curve->curve_type;
00416 }
00417
00418 int
00419 stp_curve_set_gamma(stp_curve_t *curve, double fgamma)
00420 {
00421 check_curve(curve);
00422 if (curve->wrap_mode || ! finite(fgamma) || fgamma == 0.0)
00423 return 0;
00424 clear_curve_data(curve);
00425 curve->gamma = fgamma;
00426 stp_curve_resample(curve, 2);
00427 return 1;
00428 }
00429
00430 double
00431 stp_curve_get_gamma(const stp_curve_t *curve)
00432 {
00433 check_curve(curve);
00434 return curve->gamma;
00435 }
00436
00437 int
00438 stp_curve_set_data(stp_curve_t *curve, size_t count, const double *data)
00439 {
00440 size_t i;
00441 size_t real_count = count;
00442 double low, high;
00443 check_curve(curve);
00444 if (count < 2)
00445 return 0;
00446 if (curve->wrap_mode == STP_CURVE_WRAP_AROUND)
00447 real_count++;
00448 if (real_count > curve_point_limit)
00449 return 0;
00450
00451
00452 stp_sequence_get_bounds(curve->seq, &low, &high);
00453 for (i = 0; i < count; i++)
00454 if (! finite(data[i]) || data[i] < low || data[i] > high)
00455 {
00456 stp_erprintf("stp_curve_set_data: datum out of bounds: "
00457 "%g (require %g <= x <= %g), n = %d\n",
00458 data[i], low, high, i);
00459 return 0;
00460 }
00461
00462 stpi_curve_set_points(curve, count);
00463 curve->gamma = 0.0;
00464 stp_sequence_set_subrange(curve->seq, 0, count, data);
00465
00466 if (curve->wrap_mode == STP_CURVE_WRAP_AROUND)
00467 stp_sequence_set_point(curve->seq, count, data[0]);
00468 curve->recompute_interval = 1;
00469
00470 return 1;
00471 }
00472
00473
00474
00475
00476
00477
00478
00479 const double *
00480 stp_curve_get_data(const stp_curve_t *curve, size_t *count)
00481 {
00482 const double *ret;
00483 check_curve(curve);
00484 stp_sequence_get_data(curve->seq, count, &ret);
00485 *count = get_point_count(curve);
00486 return ret;
00487 }
00488
00489
00490
00491
00492 #define DEFINE_DATA_SETTER(t, name) \
00493 int \
00494 stp_curve_set_##name##_data(stp_curve_t *curve, size_t count, const t *data) \
00495 { \
00496 double *tmp_data; \
00497 size_t i; \
00498 int status; \
00499 size_t real_count = count; \
00500 \
00501 check_curve(curve); \
00502 if (count < 2) \
00503 return 0; \
00504 if (curve->wrap_mode == STP_CURVE_WRAP_AROUND) \
00505 real_count++; \
00506 if (real_count > curve_point_limit) \
00507 return 0; \
00508 tmp_data = stp_malloc(count * sizeof(double)); \
00509 for (i = 0; i < count; i++) \
00510 tmp_data[i] = (double) data[i]; \
00511 status = stp_curve_set_data(curve, count, tmp_data); \
00512 stp_free(tmp_data); \
00513 return status; \
00514 }
00515
00516 DEFINE_DATA_SETTER(float, float)
00517 DEFINE_DATA_SETTER(long, long)
00518 DEFINE_DATA_SETTER(unsigned long, ulong)
00519 DEFINE_DATA_SETTER(int, int)
00520 DEFINE_DATA_SETTER(unsigned int, uint)
00521 DEFINE_DATA_SETTER(short, short)
00522 DEFINE_DATA_SETTER(unsigned short, ushort)
00523
00524
00525 #define DEFINE_DATA_ACCESSOR(t, name) \
00526 const t * \
00527 stp_curve_get_##name##_data(const stp_curve_t *curve, size_t *count) \
00528 { \
00529 return stp_sequence_get_##name##_data(curve->seq, count); \
00530 }
00531
00532 DEFINE_DATA_ACCESSOR(float, float)
00533 DEFINE_DATA_ACCESSOR(long, long)
00534 DEFINE_DATA_ACCESSOR(unsigned long, ulong)
00535 DEFINE_DATA_ACCESSOR(int, int)
00536 DEFINE_DATA_ACCESSOR(unsigned int, uint)
00537 DEFINE_DATA_ACCESSOR(short, short)
00538 DEFINE_DATA_ACCESSOR(unsigned short, ushort)
00539
00540
00541 stp_curve_t *
00542 stp_curve_get_subrange(const stp_curve_t *curve, size_t start, size_t count)
00543 {
00544 stp_curve_t *retval;
00545 size_t ncount;
00546 double blo, bhi;
00547 const double *data;
00548 if (start + count > stp_curve_count_points(curve) || count < 2)
00549 return NULL;
00550 retval = stp_curve_create(STP_CURVE_WRAP_NONE);
00551 stp_curve_get_bounds(curve, &blo, &bhi);
00552 stp_curve_set_bounds(retval, blo, bhi);
00553 data = stp_curve_get_data(curve, &ncount);
00554 if (! stp_curve_set_data(retval, count, data + start))
00555 {
00556 stp_curve_destroy(retval);
00557 return NULL;
00558 }
00559 return retval;
00560 }
00561
00562 int
00563 stp_curve_set_subrange(stp_curve_t *curve, const stp_curve_t *range,
00564 size_t start)
00565 {
00566 double blo, bhi;
00567 double rlo, rhi;
00568 const double *data;
00569 size_t count;
00570 check_curve(curve);
00571 if (start + stp_curve_count_points(range) > stp_curve_count_points(curve))
00572 return 0;
00573 stp_sequence_get_bounds(curve->seq, &blo, &bhi);
00574 stp_sequence_get_range(curve->seq, &rlo, &rhi);
00575 if (rlo < blo || rhi > bhi)
00576 return 0;
00577 stp_sequence_get_data(curve->seq, &count, &data);
00578 curve->recompute_interval = 1;
00579 curve->gamma = 0.0;
00580 invalidate_auxiliary_data(curve);
00581 stp_sequence_set_subrange(curve->seq, start, count, data);
00582 return 1;
00583 }
00584
00585
00586 int
00587 stp_curve_set_point(stp_curve_t *curve, size_t where, double data)
00588 {
00589 check_curve(curve);
00590 if (where >= get_point_count(curve))
00591 return 0;
00592 curve->gamma = 0.0;
00593
00594 if ((stp_sequence_set_point(curve->seq, where, data)) == 0)
00595 return 0;
00596 if (where == 0 && curve->wrap_mode == STP_CURVE_WRAP_AROUND)
00597 if ((stp_sequence_set_point(curve->seq,
00598 get_point_count(curve), data)) == 0)
00599 return 0;
00600 invalidate_auxiliary_data(curve);
00601 return 1;
00602 }
00603
00604 int
00605 stp_curve_get_point(const stp_curve_t *curve, size_t where, double *data)
00606 {
00607 check_curve(curve);
00608 if (where >= get_point_count(curve))
00609 return 0;
00610 return stp_sequence_get_point(curve->seq, where, data);
00611 }
00612
00613 const stp_sequence_t *
00614 stp_curve_get_sequence(const stp_curve_t *curve)
00615 {
00616 check_curve(curve);
00617 return curve->seq;
00618 }
00619
00620 int
00621 stp_curve_rescale(stp_curve_t *curve, double scale,
00622 stp_curve_compose_t mode, stp_curve_bounds_t bounds_mode)
00623 {
00624 size_t real_point_count;
00625 int i;
00626 double nblo;
00627 double nbhi;
00628 size_t count;
00629
00630 check_curve(curve);
00631
00632 real_point_count = get_real_point_count(curve);
00633
00634 stp_sequence_get_bounds(curve->seq, &nblo, &nbhi);
00635 if (bounds_mode == STP_CURVE_BOUNDS_RESCALE)
00636 {
00637 switch (mode)
00638 {
00639 case STP_CURVE_COMPOSE_ADD:
00640 nblo += scale;
00641 nbhi += scale;
00642 break;
00643 case STP_CURVE_COMPOSE_MULTIPLY:
00644 if (scale < 0)
00645 {
00646 double tmp = nblo * scale;
00647 nblo = nbhi * scale;
00648 nbhi = tmp;
00649 }
00650 else
00651 {
00652 nblo *= scale;
00653 nbhi *= scale;
00654 }
00655 break;
00656 case STP_CURVE_COMPOSE_EXPONENTIATE:
00657 if (scale == 0.0)
00658 return 0;
00659 if (nblo < 0)
00660 return 0;
00661 nblo = pow(nblo, scale);
00662 nbhi = pow(nbhi, scale);
00663 break;
00664 default:
00665 return 0;
00666 }
00667 }
00668
00669 if (! finite(nbhi) || ! finite(nblo))
00670 return 0;
00671
00672 count = get_point_count(curve);
00673 if (count)
00674 {
00675 double *tmp;
00676 size_t scount;
00677 const double *data;
00678 stp_sequence_get_data(curve->seq, &scount, &data);
00679 tmp = stp_malloc(sizeof(double) * scount);
00680 for (i = 0; i < scount; i++)
00681 {
00682 switch (mode)
00683 {
00684 case STP_CURVE_COMPOSE_ADD:
00685 tmp[i] = *(data+i) + scale;
00686 break;
00687 case STP_CURVE_COMPOSE_MULTIPLY:
00688 tmp[i] = *(data+i) * scale;
00689 break;
00690 case STP_CURVE_COMPOSE_EXPONENTIATE:
00691 tmp[i] = pow(*(data+i), scale);
00692 break;
00693 }
00694 if (tmp[i] > nbhi || tmp[i] < nblo)
00695 {
00696 if (bounds_mode == STP_CURVE_BOUNDS_ERROR)
00697 {
00698 stp_free(tmp);
00699 return(0);
00700 }
00701 else if (tmp[i] > nbhi)
00702 tmp[i] = nbhi;
00703 else
00704 tmp[i] = nblo;
00705 }
00706 }
00707 stp_sequence_set_bounds(curve->seq, nblo, nbhi);
00708 curve->gamma = 0.0;
00709 stpi_curve_set_points(curve, count);
00710 stp_sequence_set_subrange(curve->seq, 0, real_point_count, tmp);
00711 stp_free(tmp);
00712 curve->recompute_interval = 1;
00713 invalidate_auxiliary_data(curve);
00714 }
00715 return 1;
00716 }
00717
00718 static int
00719 stpi_curve_check_parameters(stp_curve_t *curve, size_t points)
00720 {
00721 double blo, bhi;
00722 if (curve->gamma && curve->wrap_mode)
00723 {
00724 #ifdef DEBUG
00725 stp_erprintf("curve sets both gamma and wrap_mode\n");
00726 #endif
00727 return 0;
00728 }
00729 stp_sequence_get_bounds(curve->seq, &blo, &bhi);
00730 if (blo > bhi)
00731 {
00732 #ifdef DEBUG
00733 stp_erprintf("curve low bound is greater than high bound\n");
00734 #endif
00735 return 0;
00736 }
00737 return 1;
00738 }
00739
00740 static inline double
00741 interpolate_gamma_internal(const stp_curve_t *curve, double where)
00742 {
00743 double fgamma = curve->gamma;
00744 double blo, bhi;
00745 size_t real_point_count;
00746
00747 real_point_count = get_real_point_count(curve);;
00748
00749 if (real_point_count)
00750 where /= (real_point_count - 1);
00751 if (fgamma < 0)
00752 {
00753 where = 1.0 - where;
00754 fgamma = -fgamma;
00755 }
00756 stp_sequence_get_bounds(curve->seq, &blo, &bhi);
00757 #ifdef DEBUG
00758 stp_erprintf("interpolate_gamma %f %f %f %f %f\n", where, fgamma,
00759 blo, bhi, pow(where, fgamma));
00760 #endif
00761 return blo + (bhi - blo) * pow(where, fgamma);
00762 }
00763
00764 static inline double
00765 interpolate_point_internal(stp_curve_t *curve, double where)
00766 {
00767 int integer = where;
00768 double frac = where - (double) integer;
00769 double bhi, blo;
00770
00771 if (frac == 0.0)
00772 {
00773 double val;
00774 if ((stp_sequence_get_point(curve->seq, integer, &val)) == 0)
00775 return HUGE_VAL;
00776 return val;
00777 }
00778 if (curve->recompute_interval)
00779 compute_intervals(curve);
00780 if (curve->curve_type == STP_CURVE_TYPE_LINEAR)
00781 {
00782 double val;
00783 if ((stp_sequence_get_point(curve->seq, integer, &val)) == 0)
00784 return HUGE_VAL;
00785 return val + frac * curve->interval[integer];
00786 }
00787 else
00788 {
00789 size_t point_count;
00790 double a = 1.0 - frac;
00791 double b = frac;
00792 double ival, ip1val;
00793 double retval;
00794 int i = integer;
00795 int ip1 = integer + 1;
00796
00797 point_count = get_point_count(curve);
00798
00799 if (ip1 >= point_count)
00800 ip1 -= point_count;
00801 retval = ((a * a * a - a) * curve->interval[i] +
00802 (b * b * b - b) * curve->interval[ip1]);
00803
00804 if ((stp_sequence_get_point(curve->seq, i, &ival)) == 0 ||
00805 (stp_sequence_get_point(curve->seq, ip1, &ip1val)) == 0)
00806 return HUGE_VAL;
00807
00808 retval = a * ival + b * ip1val + retval / 6;
00809
00810 stp_sequence_get_bounds(curve->seq, &blo, &bhi);
00811 if (retval > bhi)
00812 retval = bhi;
00813 if (retval < blo)
00814 retval = blo;
00815 return retval;
00816 }
00817 }
00818
00819 int
00820 stp_curve_interpolate_value(const stp_curve_t *curve, double where,
00821 double *result)
00822 {
00823 size_t limit;
00824
00825 check_curve(curve);
00826
00827 limit = get_real_point_count(curve);
00828
00829 if (where < 0 || where > limit)
00830 return 0;
00831 if (curve->gamma)
00832 *result = interpolate_gamma_internal(curve, where);
00833 else
00834 *result = interpolate_point_internal((stp_curve_t *) curve, where);
00835 return 1;
00836 }
00837
00838 int
00839 stp_curve_resample(stp_curve_t *curve, size_t points)
00840 {
00841 size_t limit = points;
00842 size_t old;
00843 size_t i;
00844 double *new_vec;
00845
00846 check_curve(curve);
00847
00848 if (points == get_point_count(curve) && curve->seq)
00849 return 1;
00850
00851 if (points < 2)
00852 return 1;
00853
00854 if (curve->wrap_mode == STP_CURVE_WRAP_AROUND)
00855 limit++;
00856 if (limit > curve_point_limit)
00857 return 0;
00858 old = get_real_point_count(curve);
00859 if (old)
00860 old--;
00861 if (!old)
00862 old = 1;
00863
00864 new_vec = stp_malloc(sizeof(double) * limit);
00865
00866
00867
00868
00869
00870
00871 for (i = 0; i < limit; i++)
00872 if (curve->gamma)
00873 new_vec[i] =
00874 interpolate_gamma_internal(curve, ((double) i * (double) old /
00875 (double) (limit - 1)));
00876 else
00877 new_vec[i] =
00878 interpolate_point_internal(curve, ((double) i * (double) old /
00879 (double) (limit - 1)));
00880 stpi_curve_set_points(curve, points);
00881 stp_sequence_set_subrange(curve->seq, 0, limit, new_vec);
00882 curve->recompute_interval = 1;
00883 stp_free(new_vec);
00884 return 1;
00885 }
00886
00887 static unsigned
00888 gcd(unsigned a, unsigned b)
00889 {
00890 unsigned tmp;
00891 if (b > a)
00892 {
00893 tmp = a;
00894 a = b;
00895 b = tmp;
00896 }
00897 while (1)
00898 {
00899 tmp = a % b;
00900 if (tmp == 0)
00901 return b;
00902 a = b;
00903 b = tmp;
00904 }
00905 }
00906
00907 static unsigned
00908 lcm(unsigned a, unsigned b)
00909 {
00910 if (a == b)
00911 return a;
00912 else if (a * b == 0)
00913 return a > b ? a : b;
00914 else
00915 {
00916 double rval = (double) a / gcd(a, b) * b;
00917 if (rval > curve_point_limit)
00918 return curve_point_limit;
00919 else
00920 return rval;
00921 }
00922 }
00923
00924 static int
00925 create_gamma_curve(stp_curve_t **retval, double lo, double hi, double fgamma,
00926 int points)
00927 {
00928 *retval = stp_curve_create(STP_CURVE_WRAP_NONE);
00929 if (stp_curve_set_bounds(*retval, lo, hi) &&
00930 stp_curve_set_gamma(*retval, fgamma) &&
00931 stp_curve_resample(*retval, points))
00932 return 1;
00933 stp_curve_destroy(*retval);
00934 *retval = 0;
00935 return 0;
00936 }
00937
00938 static int
00939 interpolate_points(stp_curve_t *a, stp_curve_t *b,
00940 stp_curve_compose_t mode,
00941 int points, double *tmp_data)
00942 {
00943 double pa, pb;
00944 int i;
00945 size_t points_a = stp_curve_count_points(a);
00946 size_t points_b = stp_curve_count_points(b);
00947 for (i = 0; i < points; i++)
00948 {
00949 if (!stp_curve_interpolate_value
00950 (a, (double) i * (points_a - 1) / (points - 1), &pa))
00951 {
00952 stp_erprintf("interpolate_points: interpolate curve a value failed\n");
00953 return 0;
00954 }
00955 if (!stp_curve_interpolate_value
00956 (b, (double) i * (points_b - 1) / (points - 1), &pb))
00957 {
00958 stp_erprintf("interpolate_points: interpolate curve b value failed\n");
00959 return 0;
00960 }
00961 if (mode == STP_CURVE_COMPOSE_ADD)
00962 pa += pb;
00963 else
00964 pa *= pb;
00965 if (! finite(pa))
00966 {
00967 stp_erprintf("interpolate_points: interpolated point %lu is invalid\n",
00968 (unsigned long) i);
00969 return 0;
00970 }
00971 tmp_data[i] = pa;
00972 }
00973 return 1;
00974 }
00975
00976 int
00977 stp_curve_compose(stp_curve_t **retval,
00978 stp_curve_t *a, stp_curve_t *b,
00979 stp_curve_compose_t mode, int points)
00980 {
00981 stp_curve_t *ret;
00982 double *tmp_data;
00983 double gamma_a = stp_curve_get_gamma(a);
00984 double gamma_b = stp_curve_get_gamma(b);
00985 unsigned points_a = stp_curve_count_points(a);
00986 unsigned points_b = stp_curve_count_points(b);
00987 double alo, ahi, blo, bhi;
00988
00989 if (mode != STP_CURVE_COMPOSE_ADD && mode != STP_CURVE_COMPOSE_MULTIPLY)
00990 return 0;
00991 if (stp_curve_get_wrap(a) != stp_curve_get_wrap(b))
00992 return 0;
00993 stp_curve_get_bounds(a, &alo, &ahi);
00994 stp_curve_get_bounds(b, &blo, &bhi);
00995 if (mode == STP_CURVE_COMPOSE_MULTIPLY && (alo < 0 || blo < 0))
00996 return 0;
00997
00998 if (stp_curve_get_wrap(a) == STP_CURVE_WRAP_AROUND)
00999 {
01000 points_a++;
01001 points_b++;
01002 }
01003 if (points == -1)
01004 {
01005 points = lcm(points_a, points_b);
01006 if (stp_curve_get_wrap(a) == STP_CURVE_WRAP_AROUND)
01007 points--;
01008 }
01009 if (points < 2 || points > curve_point_limit ||
01010 ((stp_curve_get_wrap(a) == STP_CURVE_WRAP_AROUND) &&
01011 points > curve_point_limit - 1))
01012 return 0;
01013
01014 if (gamma_a && gamma_b && gamma_a * gamma_b > 0 &&
01015 mode == STP_CURVE_COMPOSE_MULTIPLY)
01016 return create_gamma_curve(retval, alo * blo, ahi * bhi, gamma_a + gamma_b,
01017 points);
01018 tmp_data = stp_malloc(sizeof(double) * points);
01019 if (!interpolate_points(a, b, mode, points, tmp_data))
01020 {
01021 stp_free(tmp_data);
01022 return 0;
01023 }
01024 ret = stp_curve_create(stp_curve_get_wrap(a));
01025 if (mode == STP_CURVE_COMPOSE_ADD)
01026 {
01027 stp_curve_rescale(ret, (ahi - alo) + (bhi - blo),
01028 STP_CURVE_COMPOSE_MULTIPLY, STP_CURVE_BOUNDS_RESCALE);
01029 stp_curve_rescale(ret, alo + blo,
01030 STP_CURVE_COMPOSE_ADD, STP_CURVE_BOUNDS_RESCALE);
01031 }
01032 else
01033 {
01034 stp_curve_rescale(ret, (ahi - alo) * (bhi - blo),
01035 STP_CURVE_COMPOSE_MULTIPLY, STP_CURVE_BOUNDS_RESCALE);
01036 stp_curve_rescale(ret, alo * blo,
01037 STP_CURVE_COMPOSE_ADD, STP_CURVE_BOUNDS_RESCALE);
01038 }
01039 if (! stp_curve_set_data(ret, points, tmp_data))
01040 goto bad1;
01041 *retval = ret;
01042 stp_free(tmp_data);
01043 return 1;
01044 bad1:
01045 stp_curve_destroy(ret);
01046 stp_free(tmp_data);
01047 return 0;
01048 }
01049
01050
01051 static stp_curve_t *
01052 stp_curve_create_from_xmltree(stp_mxml_node_t *curve)
01053 {
01054 const char *stmp;
01055 stp_mxml_node_t *child;
01056 stp_curve_t *ret = NULL;
01057 stp_curve_type_t curve_type;
01058 stp_curve_wrap_mode_t wrap_mode;
01059 double fgamma;
01060 stp_sequence_t *seq = NULL;
01061 double low, high;
01062
01063 stp_xml_init();
01064
01065 stmp = stp_mxmlElementGetAttr(curve, "type");
01066 if (stmp)
01067 {
01068 if (!strcmp(stmp, "linear"))
01069 curve_type = STP_CURVE_TYPE_LINEAR;
01070 else if (!strcmp(stmp, "spline"))
01071 curve_type = STP_CURVE_TYPE_SPLINE;
01072 else
01073 {
01074 stp_erprintf("stp_curve_create_from_xmltree: %s: \"type\" invalid\n", stmp);
01075 goto error;
01076 }
01077 }
01078 else
01079 {
01080 stp_erprintf("stp_curve_create_from_xmltree: \"type\" missing\n");
01081 goto error;
01082 }
01083
01084 stmp = stp_mxmlElementGetAttr(curve, "wrap");
01085 if (stmp)
01086 {
01087 if (!strcmp(stmp, "nowrap"))
01088 wrap_mode = STP_CURVE_WRAP_NONE;
01089 else if (!strcmp(stmp, "wrap"))
01090 {
01091 wrap_mode = STP_CURVE_WRAP_AROUND;
01092 }
01093 else
01094 {
01095 stp_erprintf("stp_curve_create_from_xmltree: %s: \"wrap\" invalid\n", stmp);
01096 goto error;
01097 }
01098 }
01099 else
01100 {
01101 stp_erprintf("stp_curve_create_from_xmltree: \"wrap\" missing\n");
01102 goto error;
01103 }
01104
01105 stmp = stp_mxmlElementGetAttr(curve, "gamma");
01106 if (stmp)
01107 {
01108 fgamma = stp_xmlstrtod(stmp);
01109 }
01110 else
01111 {
01112 stp_erprintf("stp_curve_create_from_xmltree: \"gamma\" missing\n");
01113 goto error;
01114 }
01115
01116 if (fgamma && wrap_mode != STP_CURVE_WRAP_NONE)
01117 {
01118 stp_erprintf("stp_curve_create_from_xmltree: "
01119 "gamma set and \"wrap\" is not STP_CURVE_WRAP_NONE\n");
01120 goto error;
01121 }
01122
01123
01124 ret = stp_curve_create(wrap_mode);
01125 stp_curve_set_interpolation_type(ret, curve_type);
01126
01127 child = stp_mxmlFindElement(curve, curve, "sequence", NULL, NULL, STP_MXML_DESCEND);
01128 if (child)
01129 seq = stp_sequence_create_from_xmltree(child);
01130
01131 if (seq == NULL)
01132 {
01133 stp_erprintf("stp_curve_create_from_xmltree: sequence read failed\n");
01134 goto error;
01135 }
01136
01137
01138 stp_sequence_get_bounds(seq, &low, &high);
01139 stp_curve_set_bounds(ret, low, high);
01140
01141 if (fgamma)
01142 stp_curve_set_gamma(ret, fgamma);
01143 else
01144 {
01145 size_t seq_count;
01146 const double* data;
01147
01148 stp_sequence_get_data(seq, &seq_count, &data);
01149 if (stp_curve_set_data(ret, seq_count, data) == 0)
01150 {
01151 stp_erprintf("stp_curve_create_from_xmltree: failed to set curve data\n");
01152 goto error;
01153 }
01154 }
01155
01156 if (seq)
01157 {
01158 stp_sequence_destroy(seq);
01159 seq = NULL;
01160 }
01161
01162
01163 if (stpi_curve_check_parameters(ret, stp_curve_count_points(ret)) == 0)
01164 {
01165 stp_erprintf("stp_curve_create_from_xmltree: parameter check failed\n");
01166 goto error;
01167 }
01168
01169 stp_xml_exit();
01170
01171 return ret;
01172
01173 error:
01174 stp_erprintf("stp_curve_create_from_xmltree: error during curve read\n");
01175 if (ret)
01176 stp_curve_destroy(ret);
01177 stp_xml_exit();
01178 return NULL;
01179 }
01180
01181
01182 static stp_mxml_node_t *
01183 stp_xmltree_create_from_curve(const stp_curve_t *curve)
01184 {
01185 stp_curve_wrap_mode_t wrapmode;
01186 stp_curve_type_t interptype;
01187 double gammaval, low, high;
01188 stp_sequence_t *seq;
01189
01190 char *wrap;
01191 char *type;
01192 char *cgamma;
01193
01194 stp_mxml_node_t *curvenode = NULL;
01195 stp_mxml_node_t *child = NULL;
01196
01197 stp_xml_init();
01198
01199
01200 wrapmode = stp_curve_get_wrap(curve);
01201 interptype = stp_curve_get_interpolation_type(curve);
01202 gammaval = stp_curve_get_gamma(curve);
01203
01204 if (gammaval && wrapmode != STP_CURVE_WRAP_NONE)
01205 {
01206 stp_erprintf("stp_xmltree_create_from_curve: "
01207 "curve sets gamma and wrap_mode is not STP_CURVE_WRAP_NONE\n");
01208 goto error;
01209 }
01210
01211
01212 stp_asprintf(&wrap, "%s", stpi_wrap_mode_names[wrapmode]);
01213 stp_asprintf(&type, "%s", stpi_curve_type_names[interptype]);
01214 stp_asprintf(&cgamma, "%g", gammaval);
01215
01216 curvenode = stp_mxmlNewElement(NULL, "curve");
01217 stp_mxmlElementSetAttr(curvenode, "wrap", wrap);
01218 stp_mxmlElementSetAttr(curvenode, "type", type);
01219 stp_mxmlElementSetAttr(curvenode, "gamma", cgamma);
01220
01221 stp_free(wrap);
01222 stp_free(type);
01223 stp_free(cgamma);
01224
01225 seq = stp_sequence_create();
01226 stp_curve_get_bounds(curve, &low, &high);
01227 stp_sequence_set_bounds(seq, low, high);
01228 if (gammaval != 0)
01229 {
01230 stp_sequence_set_size(seq, 0);
01231 }
01232 else
01233 {
01234 const double *data;
01235 size_t count;
01236 data = stp_curve_get_data(curve, &count);
01237 stp_sequence_set_data(seq, count, data);
01238 }
01239
01240 child = stp_xmltree_create_from_sequence(seq);
01241
01242 if (seq)
01243 {
01244 stp_sequence_destroy(seq);
01245 seq = NULL;
01246 }
01247
01248 if (child == NULL)
01249 {
01250 stp_erprintf("stp_xmltree_create_from_curve: sequence node is NULL\n");
01251 goto error;
01252 }
01253 stp_mxmlAdd(curvenode, STP_MXML_ADD_AFTER, NULL, child);
01254
01255 stp_xml_exit();
01256
01257 return curvenode;
01258
01259 error:
01260 stp_erprintf("stp_xmltree_create_from_curve: error during xmltree creation\n");
01261 if (curvenode)
01262 stp_mxmlDelete(curvenode);
01263 if (child)
01264 stp_mxmlDelete(child);
01265 stp_xml_exit();
01266
01267 return NULL;
01268 }
01269
01270 static stp_mxml_node_t *
01271 xmldoc_create_from_curve(const stp_curve_t *curve)
01272 {
01273 stp_mxml_node_t *xmldoc;
01274 stp_mxml_node_t *rootnode;
01275 stp_mxml_node_t *curvenode;
01276
01277
01278 curvenode = stp_xmltree_create_from_curve(curve);
01279 if (curvenode == NULL)
01280 {
01281 stp_erprintf("xmldoc_create_from_curve: error creating curve node\n");
01282 return NULL;
01283 }
01284
01285 xmldoc = stp_xmldoc_create_generic();
01286 if (xmldoc == NULL)
01287 {
01288 stp_erprintf("xmldoc_create_from_curve: error creating XML document\n");
01289 return NULL;
01290 }
01291 rootnode = xmldoc->child;
01292 if (rootnode == NULL)
01293 {
01294 stp_mxmlDelete(xmldoc);
01295 stp_erprintf("xmldoc_create_from_curve: error getting XML document root node\n");
01296 return NULL;
01297 }
01298
01299 stp_mxmlAdd(rootnode, STP_MXML_ADD_AFTER, NULL, curvenode);
01300
01301 return xmldoc;
01302 }
01303
01304 static int
01305 curve_whitespace_callback(stp_mxml_node_t *node, int where)
01306 {
01307 if (node->type != STP_MXML_ELEMENT)
01308 return 0;
01309 if (strcasecmp(node->value.element.name, "gimp-print") == 0)
01310 {
01311 switch (where)
01312 {
01313 case STP_MXML_WS_AFTER_OPEN:
01314 case STP_MXML_WS_BEFORE_CLOSE:
01315 case STP_MXML_WS_AFTER_CLOSE:
01316 return '\n';
01317 case STP_MXML_WS_BEFORE_OPEN:
01318 default:
01319 return 0;
01320 }
01321 }
01322 else if (strcasecmp(node->value.element.name, "curve") == 0)
01323 {
01324 switch (where)
01325 {
01326 case STP_MXML_WS_AFTER_OPEN:
01327 return '\n';
01328 case STP_MXML_WS_BEFORE_CLOSE:
01329 case STP_MXML_WS_AFTER_CLOSE:
01330 case STP_MXML_WS_BEFORE_OPEN:
01331 default:
01332 return 0;
01333 }
01334 }
01335 else if (strcasecmp(node->value.element.name, "sequence") == 0)
01336 {
01337 const char *count;
01338 switch (where)
01339 {
01340 case STP_MXML_WS_BEFORE_CLOSE:
01341 count = stp_mxmlElementGetAttr(node, "count");
01342 if (strcmp(count, "0") == 0)
01343 return 0;
01344 else
01345 return '\n';
01346 case STP_MXML_WS_AFTER_OPEN:
01347 case STP_MXML_WS_AFTER_CLOSE:
01348 return '\n';
01349 case STP_MXML_WS_BEFORE_OPEN:
01350 default:
01351 return 0;
01352 }
01353 }
01354 else
01355 return 0;
01356 }
01357
01358
01359 int
01360 stp_curve_write(FILE *file, const stp_curve_t *curve)
01361 {
01362 stp_mxml_node_t *xmldoc = NULL;
01363
01364 stp_xml_init();
01365
01366 xmldoc = xmldoc_create_from_curve(curve);
01367 if (xmldoc == NULL)
01368 {
01369 stp_xml_exit();
01370 return 1;
01371 }
01372
01373 stp_mxmlSaveFile(xmldoc, file, curve_whitespace_callback);
01374
01375 if (xmldoc)
01376 stp_mxmlDelete(xmldoc);
01377
01378 stp_xml_exit();
01379
01380 return 0;
01381 }
01382
01383 char *
01384 stp_curve_write_string(const stp_curve_t *curve)
01385 {
01386 stp_mxml_node_t *xmldoc = NULL;
01387 char *retval;
01388
01389 stp_xml_init();
01390
01391 xmldoc = xmldoc_create_from_curve(curve);
01392 if (xmldoc == NULL)
01393 {
01394 stp_xml_exit();
01395 return NULL;
01396 }
01397
01398 retval = stp_mxmlSaveAllocString(xmldoc, curve_whitespace_callback);
01399
01400 if (xmldoc)
01401 stp_mxmlDelete(xmldoc);
01402
01403 stp_xml_exit();
01404
01405 return retval;
01406 }
01407
01408 static stp_curve_t *
01409 xml_doc_get_curve(stp_mxml_node_t *doc)
01410 {
01411 stp_mxml_node_t *cur;
01412 stp_mxml_node_t *xmlcurve;
01413 stp_curve_t *curve = NULL;
01414
01415 if (doc == NULL )
01416 {
01417 stp_erprintf("xml_doc_get_curve: XML file not parsed successfully.\n");
01418 return NULL;
01419 }
01420
01421 cur = doc->child;
01422
01423 if (cur == NULL)
01424 {
01425 stp_erprintf("xml_doc_get_curve: empty document\n");
01426 return NULL;
01427 }
01428
01429 xmlcurve = stp_xml_get_node(cur, "gimp-print", "curve", NULL);
01430
01431 if (xmlcurve)
01432 curve = stp_curve_create_from_xmltree(xmlcurve);
01433
01434 return curve;
01435 }
01436
01437 stp_curve_t *
01438 stp_curve_create_from_file(const char* file)
01439 {
01440 stp_curve_t *curve = NULL;
01441 stp_mxml_node_t *doc;
01442 FILE *fp = fopen(file, "r");
01443 if (!fp)
01444 {
01445 stp_erprintf("stp_curve_create_from_file: unable to open %s: %s\n",
01446 file, strerror(errno));
01447 return NULL;
01448 }
01449 stp_deprintf(STP_DBG_XML, "stp_curve_create_from_file: reading `%s'...\n",
01450 file);
01451
01452 stp_xml_init();
01453
01454 doc = stp_mxmlLoadFile(NULL, fp, STP_MXML_NO_CALLBACK);
01455
01456 curve = xml_doc_get_curve(doc);
01457
01458 if (doc)
01459 stp_mxmlDelete(doc);
01460
01461 stp_xml_exit();
01462 (void) fclose(fp);
01463 return curve;
01464
01465 }
01466
01467 stp_curve_t *
01468 stp_curve_create_from_stream(FILE* fp)
01469 {
01470 stp_curve_t *curve = NULL;
01471 stp_mxml_node_t *doc;
01472 stp_deprintf(STP_DBG_XML, "stp_curve_create_from_fp: reading...\n");
01473
01474 stp_xml_init();
01475
01476 doc = stp_mxmlLoadFile(NULL, fp, STP_MXML_NO_CALLBACK);
01477
01478 curve = xml_doc_get_curve(doc);
01479
01480 if (doc)
01481 stp_mxmlDelete(doc);
01482
01483 stp_xml_exit();
01484 return curve;
01485
01486 }
01487
01488 stp_curve_t *
01489 stp_curve_create_from_string(const char* string)
01490 {
01491 stp_curve_t *curve = NULL;
01492 stp_mxml_node_t *doc;
01493 stp_deprintf(STP_DBG_XML,
01494 "stp_curve_create_from_string: reading '%s'...\n", string);
01495 stp_xml_init();
01496
01497 doc = stp_mxmlLoadString(NULL, string, STP_MXML_NO_CALLBACK);
01498
01499 curve = xml_doc_get_curve(doc);
01500
01501 if (doc)
01502 stp_mxmlDelete(doc);
01503
01504 stp_xml_exit();
01505 return curve;
01506 }