libgimpprint API Reference: src/main/print-dither-matrices.c Source File

Main Page | Modules | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

# src/main/print-dither-matrices.c

Go to the documentation of this file.

    00001 /*
    00002  * "$Id: print-dither-matrices_8c-source.html,v 1.1.1.2 2004/12/22 23:49:06 jlovell Exp $"
    00003  *
    00004  *   Print plug-in driver utility functions for the GIMP.
    00005  *
    00006  *   Copyright 2001 Robert Krawitz (rlk@alum.mit.edu)
    00007  *
    00008  *   This program is free software; you can redistribute it and/or modify it
    00009  *   under the terms of the GNU General Public License as published by the Free
    00010  *   Software Foundation; either version 2 of the License, or (at your option)
    00011  *   any later version.
    00012  *
    00013  *   This program is distributed in the hope that it will be useful, but
    00014  *   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    00015  *   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    00016  *   for more details.
    00017  *
    00018  *   You should have received a copy of the GNU General Public License
    00019  *   along with this program; if not, write to the Free Software
    00020  *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
    00021  *
    00022  * Revision History:
    00023  *
    00024  *   See ChangeLog
    00025  */
    00026
    00027 #ifdef HAVE_CONFIG_H
    00028 #include <config.h>
    00029 #endif
    00030 #include <gimp-print/gimp-print.h>
    00031 #include "gimp-print-internal.h"
    00032 #include <math.h>
    00033 #include <string.h>
    00034 #include <stdlib.h>
    00035 #include <stdio.h>
    00036 #include <assert.h>
    00037 #include "dither-impl.h"
    00038
    00039 #ifdef __GNUC__
    00040 #define inline __inline__
    00041 #endif
    00042
    00043
    00044 static unsigned
    00045 gcd(unsigned a, unsigned b)
    00046 {
    00047   unsigned tmp;
    00048   if (b > a)
    00049     {
    00050       tmp = a;
    00051       a = b;
    00052       b = tmp;
    00053     }
    00054   while (1)
    00055     {
    00056       tmp = a % b;
    00057       if (tmp == 0)
    00058         return b;
    00059       a = b;
    00060       b = tmp;
    00061     }
    00062 }
    00063
    00064 static inline int
    00065 calc_ordered_point(unsigned x, unsigned y, int steps, int multiplier,
    00066                    int size, const unsigned *map)
    00067 {
    00068   int i, j;
    00069   unsigned retval = 0;
    00070   int divisor = 1;
    00071   int div1;
    00072   for (i = 0; i < steps; i++)
    00073     {
    00074       int xa = (x / divisor) % size;
    00075       int ya = (y / divisor) % size;
    00076       unsigned base;
    00077       base = map[ya + (xa * size)];
    00078       div1 = 1;
    00079       for (j = i; j < steps - 1; j++)
    00080         div1 *= size * size;
    00081       retval += base * div1;
    00082       divisor *= size;
    00083     }
    00084   return retval * multiplier;
    00085 }
    00086
    00087 static int
    00088 is_po2(size_t i)
    00089 {
    00090   if (i == 0)
    00091     return 0;
    00092   return (((i & (i - 1)) == 0) ? 1 : 0);
    00093 }
    00094
    00095 void
    00096 stp_dither_matrix_iterated_init(stp_dither_matrix_impl_t *mat, size_t size,
    00097                                 size_t expt, const unsigned *array)
    00098 {
    00099   int i;
    00100   int x, y;
    00101   mat->base = size;
    00102   mat->exp = expt;
    00103   mat->x_size = 1;
    00104   for (i = 0; i < expt; i++)
    00105     mat->x_size *= mat->base;
    00106   mat->y_size = mat->x_size;
    00107   mat->total_size = mat->x_size * mat->y_size;
    00108   mat->matrix = stp_malloc(sizeof(unsigned) * mat->x_size * mat->y_size);
    00109   for (x = 0; x < mat->x_size; x++)
    00110     for (y = 0; y < mat->y_size; y++)
    00111       {
    00112         mat->matrix[x + y * mat->x_size] =
    00113           calc_ordered_point(x, y, mat->exp, 1, mat->base, array);
    00114         mat->matrix[x + y * mat->x_size] =
    00115           (double) mat->matrix[x + y * mat->x_size] * 65536.0 /
    00116           (double) (mat->x_size * mat->y_size);
    00117       }
    00118   mat->last_x = mat->last_x_mod = 0;
    00119   mat->last_y = mat->last_y_mod = 0;
    00120   mat->index = 0;
    00121   mat->i_own = 1;
    00122   if (is_po2(mat->x_size))
    00123     mat->fast_mask = mat->x_size - 1;
    00124   else
    00125     mat->fast_mask = 0;
    00126 }
    00127
    00128 #define MATRIX_POINT(m, x, y, x_size, y_size) \
    00129   ((m)[(((x) + (x_size)) % (x_size)) + ((x_size) * (((y) + (y_size)) % (y_size)))])
    00130
    00131 void
    00132 stp_dither_matrix_shear(stp_dither_matrix_impl_t *mat, int x_shear, int y_shear)
    00133 {
    00134   int i;
    00135   int j;
    00136   int *tmp = stp_malloc(mat->x_size * mat->y_size * sizeof(int));
    00137   for (i = 0; i < mat->x_size; i++)
    00138     for (j = 0; j < mat->y_size; j++)
    00139       MATRIX_POINT(tmp, i, j, mat->x_size, mat->y_size) =
    00140         MATRIX_POINT(mat->matrix, i, j * (x_shear + 1), mat->x_size,
    00141                     mat->y_size);
    00142   for (i = 0; i < mat->x_size; i++)
    00143     for (j = 0; j < mat->y_size; j++)
    00144       MATRIX_POINT(mat->matrix, i, j, mat->x_size, mat->y_size) =
    00145         MATRIX_POINT(tmp, i * (y_shear + 1), j, mat->x_size, mat->y_size);
    00146   stp_free(tmp);
    00147 }
    00148
    00149 int
    00150 stp_dither_matrix_validate_array(const stp_array_t *array)
    00151 {
    00152   double low, high;
    00153   const stp_sequence_t *seq = stp_array_get_sequence(array);
    00154   stp_sequence_get_bounds(seq, &low, &high);
    00155   if (low < 0 || high > 65535)
    00156     return 0;
    00157   return 1;
    00158 }
    00159
    00160
    00161 void
    00162 stp_dither_matrix_init_from_dither_array(stp_dither_matrix_impl_t *mat,
    00163                                          const stp_array_t *array,
    00164                                          int transpose)
    00165 {
    00166   int x, y;
    00167   size_t count;
    00168   const unsigned short *vec;
    00169   int x_size, y_size;
    00170   const stp_sequence_t *seq = stp_array_get_sequence(array);
    00171   stp_array_get_size(array, &x_size, &y_size);
    00172
    00173   vec = stp_sequence_get_ushort_data(seq, &count);
    00174   mat->base = x_size;;
    00175   mat->exp = 1;
    00176   mat->x_size = x_size;
    00177   mat->y_size = y_size;
    00178   mat->total_size = mat->x_size * mat->y_size;
    00179   mat->matrix = stp_malloc(sizeof(unsigned) * mat->x_size * mat->y_size);
    00180   for (x = 0; x < mat->x_size; x++)
    00181     for (y = 0; y < mat->y_size; y++)
    00182       {
    00183         if (transpose)
    00184           mat->matrix[x + y * mat->x_size] = vec[y + x * mat->y_size];
    00185         else
    00186           mat->matrix[x + y * mat->x_size] = vec[x + y * mat->x_size];
    00187       }
    00188   mat->last_x = mat->last_x_mod = 0;
    00189   mat->last_y = mat->last_y_mod = 0;
    00190   mat->index = 0;
    00191   mat->i_own = 1;
    00192   if (is_po2(mat->x_size))
    00193     mat->fast_mask = mat->x_size - 1;
    00194   else
    00195     mat->fast_mask = 0;
    00196 }
    00197
    00198
    00199 void
    00200 stp_dither_matrix_init(stp_dither_matrix_impl_t *mat, int x_size, int y_size,
    00201                        const unsigned int *array, int transpose, int prescaled)
    00202 {
    00203   int x, y;
    00204   mat->base = x_size;
    00205   mat->exp = 1;
    00206   mat->x_size = x_size;
    00207   mat->y_size = y_size;
    00208   mat->total_size = mat->x_size * mat->y_size;
    00209   mat->matrix = stp_malloc(sizeof(unsigned) * mat->x_size * mat->y_size);
    00210   for (x = 0; x < mat->x_size; x++)
    00211     for (y = 0; y < mat->y_size; y++)
    00212       {
    00213         if (transpose)
    00214           mat->matrix[x + y * mat->x_size] = array[y + x * mat->y_size];
    00215         else
    00216           mat->matrix[x + y * mat->x_size] = array[x + y * mat->x_size];
    00217         if (!prescaled)
    00218           mat->matrix[x + y * mat->x_size] =
    00219             (double) mat->matrix[x + y * mat->x_size] * 65536.0 /
    00220             (double) (mat->x_size * mat->y_size);
    00221       }
    00222   mat->last_x = mat->last_x_mod = 0;
    00223   mat->last_y = mat->last_y_mod = 0;
    00224   mat->index = 0;
    00225   mat->i_own = 1;
    00226   if (is_po2(mat->x_size))
    00227     mat->fast_mask = mat->x_size - 1;
    00228   else
    00229     mat->fast_mask = 0;
    00230 }
    00231
    00232 void
    00233 stp_dither_matrix_init_short(stp_dither_matrix_impl_t *mat, int x_size, int y_size,
    00234                              const unsigned short *array, int transpose,
    00235                              int prescaled)
    00236 {
    00237   int x, y;
    00238   mat->base = x_size;
    00239   mat->exp = 1;
    00240   mat->x_size = x_size;
    00241   mat->y_size = y_size;
    00242   mat->total_size = mat->x_size * mat->y_size;
    00243   mat->matrix = stp_malloc(sizeof(unsigned) * mat->x_size * mat->y_size);
    00244   for (x = 0; x < mat->x_size; x++)
    00245     for (y = 0; y < mat->y_size; y++)
    00246       {
    00247         if (transpose)
    00248           mat->matrix[x + y * mat->x_size] = array[y + x * mat->y_size];
    00249         else
    00250           mat->matrix[x + y * mat->x_size] = array[x + y * mat->x_size];
    00251         if (!prescaled)
    00252           mat->matrix[x + y * mat->x_size] =
    00253             (double) mat->matrix[x + y * mat->x_size] * 65536.0 /
    00254             (double) (mat->x_size * mat->y_size);
    00255       }
    00256   mat->last_x = mat->last_x_mod = 0;
    00257   mat->last_y = mat->last_y_mod = 0;
    00258   mat->index = 0;
    00259   mat->i_own = 1;
    00260   if (is_po2(mat->x_size))
    00261     mat->fast_mask = mat->x_size - 1;
    00262   else
    00263     mat->fast_mask = 0;
    00264 }
    00265
    00266 void
    00267 stp_dither_matrix_destroy(stp_dither_matrix_impl_t *mat)
    00268 {
    00269   if (mat->i_own && mat->matrix)
    00270     stp_free(mat->matrix);
    00271   mat->matrix = NULL;
    00272   mat->base = 0;
    00273   mat->exp = 0;
    00274   mat->x_size = 0;
    00275   mat->y_size = 0;
    00276   mat->total_size = 0;
    00277   mat->i_own = 0;
    00278 }
    00279
    00280 void
    00281 stp_dither_matrix_clone(const stp_dither_matrix_impl_t *src, stp_dither_matrix_impl_t *dest,
    00282                         int x_offset, int y_offset)
    00283 {
    00284   dest->base = src->base;
    00285   dest->exp = src->exp;
    00286   dest->x_size = src->x_size;
    00287   dest->y_size = src->y_size;
    00288   dest->total_size = src->total_size;
    00289   dest->matrix = src->matrix;
    00290   dest->x_offset = x_offset;
    00291   dest->y_offset = y_offset;
    00292   dest->last_x = 0;
    00293   dest->last_x_mod = dest->x_offset % dest->x_size;
    00294   dest->last_y = 0;
    00295   dest->last_y_mod = dest->x_size * (dest->y_offset % dest->y_size);
    00296   dest->index = dest->last_x_mod + dest->last_y_mod;
    00297   dest->fast_mask = src->fast_mask;
    00298   dest->i_own = 0;
    00299 }
    00300
    00301 void
    00302 stp_dither_matrix_copy(const stp_dither_matrix_impl_t *src, stp_dither_matrix_impl_t *dest)
    00303 {
    00304   int x;
    00305   dest->base = src->base;
    00306   dest->exp = src->exp;
    00307   dest->x_size = src->x_size;
    00308   dest->y_size = src->y_size;
    00309   dest->total_size = src->total_size;
    00310   dest->matrix = stp_malloc(sizeof(unsigned) * dest->x_size * dest->y_size);
    00311   for (x = 0; x < dest->x_size * dest->y_size; x++)
    00312     dest->matrix[x] = src->matrix[x];
    00313   dest->x_offset = 0;
    00314   dest->y_offset = 0;
    00315   dest->last_x = 0;
    00316   dest->last_x_mod = 0;
    00317   dest->last_y = 0;
    00318   dest->last_y_mod = 0;
    00319   dest->index = 0;
    00320   dest->fast_mask = src->fast_mask;
    00321   dest->i_own = 1;
    00322 }
    00323
    00324 void
    00325 stp_dither_matrix_scale_exponentially(stp_dither_matrix_impl_t *mat, double exponent)
    00326 {
    00327   int i;
    00328   int mat_size = mat->x_size * mat->y_size;
    00329   for (i = 0; i < mat_size; i++)
    00330     {
    00331       double dd = mat->matrix[i] / 65535.0;
    00332       dd = pow(dd, exponent);
    00333       mat->matrix[i] = 65535 * dd;
    00334     }
    00335 }
    00336
    00337 void
    00338 stp_dither_matrix_set_row(stp_dither_matrix_impl_t *mat, int y)
    00339 {
    00340   mat->last_y = y;
    00341   mat->last_y_mod = mat->x_size * ((y + mat->y_offset) % mat->y_size);
    00342   mat->index = mat->last_x_mod + mat->last_y_mod;
    00343 }
    00344
    00345 static void
    00346 preinit_matrix(stp_vars_t *v)
    00347 {
    00348   stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
    00349   int i;
    00350   for (i = 0; i < CHANNEL_COUNT(d); i++)
    00351     stp_dither_matrix_destroy(&(CHANNEL(d, i).dithermat));
    00352   stp_dither_matrix_destroy(&(d->dither_matrix));
    00353 }
    00354
    00355 static void
    00356 postinit_matrix(stp_vars_t *v, int x_shear, int y_shear)
    00357 {
    00358   stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
    00359   unsigned rc = 1 + (unsigned) ceil(sqrt(CHANNEL_COUNT(d)));
    00360   int i, j;
    00361   int color = 0;
    00362   unsigned x_n = d->dither_matrix.x_size / rc;
    00363   unsigned y_n = d->dither_matrix.y_size / rc;
    00364   if (x_shear || y_shear)
    00365     stp_dither_matrix_shear(&(d->dither_matrix), x_shear, y_shear);
    00366   for (i = 0; i < rc; i++)
    00367     for (j = 0; j < rc; j++)
    00368       if (color < CHANNEL_COUNT(d))
    00369         {
    00370           stp_dither_matrix_clone(&(d->dither_matrix),
    00371                                   &(CHANNEL(d, color).dithermat),
    00372                                   x_n * i, y_n * j);
    00373           color++;
    00374         }
    00375   stp_dither_set_transition(v, d->transition);
    00376 }
    00377
    00378 void
    00379 stp_dither_set_iterated_matrix(stp_vars_t *v, size_t edge, size_t iterations,
    00380                                const unsigned *data, int prescaled,
    00381                                int x_shear, int y_shear)
    00382 {
    00383   stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
    00384   preinit_matrix(v);
    00385   stp_dither_matrix_iterated_init(&(d->dither_matrix), edge, iterations, data);
    00386   postinit_matrix(v, x_shear, y_shear);
    00387 }
    00388
    00389 void
    00390 stp_dither_set_matrix(stp_vars_t *v, const stp_dither_matrix_generic_t *matrix,
    00391                       int transposed, int x_shear, int y_shear)
    00392 {
    00393   stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
    00394   int x = transposed ? matrix->y : matrix->x;
    00395   int y = transposed ? matrix->x : matrix->y;
    00396   preinit_matrix(v);
    00397   if (matrix->bytes == 2)
    00398     stp_dither_matrix_init_short(&(d->dither_matrix), x, y,
    00399                                  (const unsigned short *) matrix->data,
    00400                                  transposed, matrix->prescaled);
    00401   else if (matrix->bytes == 4)
    00402     stp_dither_matrix_init(&(d->dither_matrix), x, y,
    00403                            (const unsigned *)matrix->data,
    00404                            transposed, matrix->prescaled);
    00405   postinit_matrix(v, x_shear, y_shear);
    00406 }
    00407
    00408 void
    00409 stp_dither_set_matrix_from_dither_array(stp_vars_t *v,
    00410                                         const stp_array_t *array,
    00411                                         int transpose)
    00412 {
    00413   stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
    00414   preinit_matrix(v);
    00415   stp_dither_matrix_init_from_dither_array(&(d->dither_matrix), array, transpose);
    00416   postinit_matrix(v, 0, 0);
    00417 }
    00418
    00419 void
    00420 stp_dither_set_transition(stp_vars_t *v, double exponent)
    00421 {
    00422   stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
    00423   unsigned rc = 1 + (unsigned) ceil(sqrt(CHANNEL_COUNT(d)));
    00424   int i, j;
    00425   int color = 0;
    00426   unsigned x_n = d->dither_matrix.x_size / rc;
    00427   unsigned y_n = d->dither_matrix.y_size / rc;
    00428   for (i = 0; i < CHANNEL_COUNT(d); i++)
    00429     stp_dither_matrix_destroy(&(CHANNEL(d, i).pick));
    00430   stp_dither_matrix_destroy(&(d->transition_matrix));
    00431   stp_dither_matrix_copy(&(d->dither_matrix), &(d->transition_matrix));
    00432   d->transition = exponent;
    00433   if (exponent < .999 || exponent > 1.001)
    00434     stp_dither_matrix_scale_exponentially(&(d->transition_matrix), exponent);
    00435   for (i = 0; i < rc; i++)
    00436     for (j = 0; j < rc; j++)
    00437       if (color < CHANNEL_COUNT(d))
    00438         {
    00439           stp_dither_matrix_clone(&(d->dither_matrix),
    00440                                   &(CHANNEL(d, color).pick),
    00441                                   x_n * i, y_n * j);
    00442           color++;
    00443         }
    00444 }
    00445
    00446 static stp_list_t *dither_matrix_cache = NULL;
    00447
    00448 typedef struct
    00449 {
    00450   int x;
    00451   int y;
    00452   const char *filename;
    00453   const stp_array_t *dither_array;
    00454 } stp_xml_dither_cache_t;
    00455
    00456 static stp_xml_dither_cache_t *
    00457 stp_xml_dither_cache_get(int x, int y)
    00458 {
    00459   stp_list_item_t *ln;
    00460
    00461   stp_deprintf(STP_DBG_XML,
    00462                "stp_xml_dither_cache_get: lookup %dx%d... ", x, y);
    00463   if (!dither_matrix_cache)
    00464     {
    00465       stp_deprintf(STP_DBG_XML, "cache does not exist\n");
    00466       return NULL;
    00467     }
    00468
    00469   ln = stp_list_get_start(dither_matrix_cache);
    00470
    00471   while (ln)
    00472     {
    00473       if (((stp_xml_dither_cache_t *) stp_list_item_get_data(ln))->x == x &&
    00474           ((stp_xml_dither_cache_t *) stp_list_item_get_data(ln))->y == y)
    00475         {
    00476
    00477           stp_deprintf(STP_DBG_XML, "found\n");
    00478
    00479           return ((stp_xml_dither_cache_t *) stp_list_item_get_data(ln));
    00480         }
    00481       ln = stp_list_item_next(ln);
    00482     }
    00483   stp_deprintf(STP_DBG_XML, "missing\n");
    00484
    00485   return NULL;
    00486 }
    00487
    00488 static void
    00489 stp_xml_dither_cache_set(int x, int y, const char *filename)
    00490 {
    00491   stp_xml_dither_cache_t *cacheval;
    00492
    00493   assert(x && y && filename);
    00494
    00495   stp_xml_init();
    00496
    00497   if (dither_matrix_cache == NULL)
    00498     dither_matrix_cache = stp_list_create();
    00499
    00500   if (stp_xml_dither_cache_get(x, y))
    00501       /* Already cached for this x and y aspect */
    00502     return;
    00503
    00504   cacheval = stp_malloc(sizeof(stp_xml_dither_cache_t));
    00505   cacheval->x = x;
    00506   cacheval->y = y;
    00507   cacheval->filename = stp_strdup(filename);
    00508   cacheval->dither_array = NULL;
    00509
    00510   stp_list_item_create(dither_matrix_cache, NULL, (void *) cacheval);
    00511
    00512   stp_deprintf(STP_DBG_XML, "stp_xml_dither_cache_set: added %dx%d\n", x, y);
    00513
    00514   stp_xml_exit();
    00515
    00516   return;
    00517 }
    00518
    00519 /*
    00520  * Parse the <dither-matrix> node.
    00521  */
    00522 static int
    00523 stp_xml_process_dither_matrix(stp_mxml_node_t *dm,     /* The dither matrix node */
    00524                                const char *file)  /* Source file */
    00525
    00526 {
    00527   const char *value;
    00528   int x = -1;
    00529   int y = -1;
    00530
    00531   value = stp_mxmlElementGetAttr(dm, "x-aspect");
    00532   x = stp_xmlstrtol(value);
    00533
    00534   value = stp_mxmlElementGetAttr(dm, "y-aspect");
    00535   y = stp_xmlstrtol(value);
    00536
    00537   stp_deprintf(STP_DBG_XML,
    00538                "stp_xml_process_dither_matrix: x=%d, y=%d\n", x, y);
    00539
    00540   stp_xml_dither_cache_set(x, y, file);
    00541   return 1;
    00542 }
    00543
    00544 static stp_array_t *
    00545 stpi_dither_array_create_from_xmltree(stp_mxml_node_t *dm) /* Dither matrix node */
    00546 {
    00547   const char *stmp;
    00548   stp_mxml_node_t *child;
    00549   int x_aspect, y_aspect; /* Dither matrix size */
    00550
    00551   /* Get x-size */
    00552   stmp = stp_mxmlElementGetAttr(dm, "x-aspect");
    00553   if (stmp)
    00554     {
    00555       x_aspect = (int) stp_xmlstrtoul(stmp);
    00556     }
    00557   else
    00558     {
    00559       stp_erprintf("stpi_dither_array_create_from_xmltree: \"x-aspect\" missing\n");
    00560       goto error;
    00561     }
    00562   /* Get y-size */
    00563   stmp = stp_mxmlElementGetAttr(dm, "y-aspect");
    00564   if (stmp)
    00565     {
    00566       y_aspect = (int) stp_xmlstrtoul(stmp);
    00567     }
    00568   else
    00569     {
    00570       stp_erprintf("stpi_dither_array_create_from_xmltree: \"y-aspect\" missing\n");
    00571       goto error;
    00572     }
    00573
    00574   /* Now read in the array */
    00575   child = stp_mxmlFindElement(dm, dm, "array", NULL, NULL, STP_MXML_DESCEND);
    00576   if (child)
    00577     return stp_array_create_from_xmltree(child);
    00578   else
    00579     stp_erprintf("stpi_dither_array_create_from_xmltree: cannot find root\n");
    00580  error:
    00581   return NULL;
    00582 }
    00583
    00584 static stp_array_t *
    00585 xml_doc_get_dither_array(stp_mxml_node_t *doc)
    00586 {
    00587   stp_mxml_node_t *cur;
    00588   stp_mxml_node_t *xmlseq;
    00589
    00590   if (doc == NULL )
    00591     {
    00592       fprintf(stderr,"xml_doc_get_dither_array: XML file not parsed successfully.\n");
    00593       return NULL;
    00594     }
    00595
    00596   cur = doc->child;
    00597
    00598   if (cur == NULL)
    00599     {
    00600       fprintf(stderr,"xml_doc_get_dither_array: empty document\n");
    00601       return NULL;
    00602     }
    00603
    00604   xmlseq = stp_xml_get_node(cur, "gimp-print", "dither-matrix", NULL);
    00605   if (xmlseq == NULL )
    00606     {
    00607       fprintf(stderr,"xml-doc-get-dither-array: XML file is not a dither matrix.\n");
    00608       return NULL;
    00609     }
    00610
    00611   return stpi_dither_array_create_from_xmltree(xmlseq);
    00612 }
    00613
    00614 static stp_array_t *
    00615 stpi_dither_array_create_from_file(const char* file)
    00616 {
    00617   stp_mxml_node_t *doc;
    00618   stp_array_t *ret = NULL;
    00619
    00620   FILE *fp = fopen(file, "r");
    00621   if (!fp)
    00622     {
    00623       stp_erprintf("stp_curve_create_from_file: unable to open %s: %s\n",
    00624                    file, strerror(errno));
    00625       return NULL;
    00626     }
    00627
    00628   stp_xml_init();
    00629
    00630   stp_deprintf(STP_DBG_XML,
    00631                "stpi_dither_array_create_from_file: reading `%s'...\n", file);
    00632
    00633   doc = stp_mxmlLoadFile(NULL, fp, STP_MXML_NO_CALLBACK);
    00634   (void) fclose(fp);
    00635
    00636   if (doc)
    00637     {
    00638       ret = xml_doc_get_dither_array(doc);
    00639       stp_mxmlDelete(doc);
    00640     }
    00641
    00642   stp_xml_exit();
    00643
    00644   return ret;
    00645 }
    00646
    00647 static stp_array_t *
    00648 stp_xml_get_dither_array(int x, int y)
    00649 {
    00650   stp_xml_dither_cache_t *cachedval;
    00651   stp_array_t *ret;
    00652
    00653   cachedval = stp_xml_dither_cache_get(x, y);
    00654
    00655   if (cachedval && cachedval->dither_array)
    00656     return stp_array_create_copy(cachedval->dither_array);
    00657
    00658   if (!cachedval)
    00659     {
    00660       char buf[1024];
    00661       (void) sprintf(buf, "dither-matrix-%dx%d.xml", x, y);
    00662       stp_xml_parse_file_named(buf);
    00663       cachedval = stp_xml_dither_cache_get(x, y);
    00664       if (cachedval == NULL || cachedval->filename == NULL)
    00665         {
    00666           return NULL;
    00667         }
    00668     }
    00669
    00670   ret = stpi_dither_array_create_from_file(cachedval->filename);
    00671
    00672   cachedval->dither_array = ret;
    00673   return stp_array_create_copy(ret);
    00674 }
    00675
    00676 void
    00677 stpi_init_dither(void)
    00678 {
    00679   stp_register_xml_parser("dither-matrix", stp_xml_process_dither_matrix);
    00680 }
    00681
    00682 stp_array_t *
    00683 stp_find_standard_dither_array(int x_aspect, int y_aspect)
    00684 {
    00685   stp_array_t *answer;
    00686   int divisor = gcd(x_aspect, y_aspect);
    00687
    00688   x_aspect /= divisor;
    00689   y_aspect /= divisor;
    00690
    00691   if (x_aspect == 3)            /* We don't have x3 matrices */
    00692     x_aspect += 1;              /* so cheat */
    00693   if (y_aspect == 3)
    00694     y_aspect += 1;
    00695
    00696   divisor = gcd(x_aspect, y_aspect);
    00697   x_aspect /= divisor;
    00698   y_aspect /= divisor;
    00699
    00700   answer = stp_xml_get_dither_array(x_aspect, y_aspect);
    00701   if (answer)
    00702     return answer;
    00703   answer = stp_xml_get_dither_array(y_aspect, x_aspect);
    00704   if (answer)
    00705     return answer;
    00706   return NULL;
    00707 }