00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
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
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
00521
00522 static int
00523 stp_xml_process_dither_matrix(stp_mxml_node_t *dm,
00524 const char *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)
00546 {
00547 const char *stmp;
00548 stp_mxml_node_t *child;
00549 int x_aspect, y_aspect;
00550
00551
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
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
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)
00692 x_aspect += 1;
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 }