Main Page   Modules   Alphabetical List   Data Structures   File List   Data Fields   Globals  

src/main/curve.c

Go to the documentation of this file.
00001 /*
00002  * "$Id: curve.c,v 1.45 2004/05/07 19:20:29 rleigh Exp $"
00003  *
00004  *   Print plug-in driver utility functions for the GIMP.
00005  *
00006  *   Copyright 1997-2000 Michael Sweet (mike@easysw.com) and
00007  *      Robert Krawitz (rlk@alum.mit.edu)
00008  *
00009  *   This program is free software; you can redistribute it and/or modify it
00010  *   under the terms of the GNU General Public License as published by the Free
00011  *   Software Foundation; either version 2 of the License, or (at your option)
00012  *   any later version.
00013  *
00014  *   This program is distributed in the hope that it will be useful, but
00015  *   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
00016  *   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00017  *   for more details.
00018  *
00019  *   You should have received a copy of the GNU General Public License
00020  *   along with this program; if not, write to the Free Software
00021  *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
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;       /* Do we need to recompute the deltas? */
00050   double gamma;                 /* 0.0 means that the curve is not a gamma */
00051   stp_sequence_t *seq;          /* Sequence (contains the curve data) */
00052   double *interval;             /* We allocate an extra slot for the
00053                                    wrap-around value. */
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  * We could do more sanity checks here if we want.
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  * Get the total number of points in the base sequence class
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  * Get the number of points used by the curve (that are visible to the
00104  * user).  This is the real point count, but is decreased by 1 if the
00105  * curve wraps around.
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) /* No intervals can be computed */
00153     return;
00154   delta_count--; /* One less than the real point count.  Note size_t
00155                     is unsigned. */
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  * Recompute the delta values for interpolation.
00247  * When we actually do support spline curves, this routine will
00248  * compute the second derivatives for that purpose, too.
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  * Create a default curve
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  * Find the minimum and maximum points on the curve.  This does not
00376  * attempt to find the minimum and maximum interpolations; with cubic
00377  * splines these could exceed the boundaries.  That's OK; the interpolation
00378  * code will clip them to the bounds.
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   /* Validate the data before we commit to it. */
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   /* Allocate sequence; also accounts for WRAP_MODE */
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  * Note that we return a pointer to the raw data here.
00476  * A lot of operations change the data vector, that's why we don't
00477  * guarantee it across non-const calls.
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 /* "Overloaded" functions */
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; /* Infinity */
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; /* Infinity */
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; /* Infinity */
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)     /* this means a pure gamma curve */
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    * Be very careful how we calculate the location along the scale!
00868    * If we're not careful how we do it, we might get a small roundoff
00869    * error
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)  /* The curve node */
01053 {
01054   const char *stmp;                       /* Temporary string */
01055   stp_mxml_node_t *child;                 /* Child sequence node */
01056   stp_curve_t *ret = NULL;                /* Curve to return */
01057   stp_curve_type_t curve_type;            /* Type of curve */
01058   stp_curve_wrap_mode_t wrap_mode;        /* Curve wrap mode */
01059   double fgamma;                          /* Gamma value */
01060   stp_sequence_t *seq = NULL;             /* Sequence data */
01061   double low, high;                       /* Sequence bounds */
01062 
01063   stp_xml_init();
01064   /* Get curve type */
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   /* Get curve wrap mode */
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   /* Get curve gamma */
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   /* If gamma is set, wrap_mode must be STP_CURVE_WRAP_NONE */
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   /* Set up the curve */
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   /* Set curve bounds */
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 /* Not a gamma curve, so set points */
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     /* Validate curve */
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)  /* The 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   /* Get curve details */
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   /* Construct the allocated strings required */
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) /* A gamma curve does not require sequence data */
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   /* Get curve details */
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   /* Create the XML tree */
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)  /* The 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)  /* The 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 }

Generated on Wed May 12 20:21:28 2004 for libgimpprint API Reference by doxygen1.2.17