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

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

# src/main/dither-inks.c

Go to the documentation of this file.

    00001 /*
    00002  * "$Id: dither-inks_8c-source.html,v 1.1.1.2 2004/12/22 23:48:58 jlovell 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  * Revision History:
    00024  *
    00025  *   See ChangeLog
    00026  */
    00027
    00028 #ifdef HAVE_CONFIG_H
    00029 #include <config.h>
    00030 #endif
    00031 #include <gimp-print/gimp-print.h>
    00032 #include "gimp-print-internal.h"
    00033 #include <gimp-print/gimp-print-intl-internal.h>
    00034 #ifdef HAVE_LIMITS_H
    00035 #include <limits.h>
    00036 #endif
    00037 #include <math.h>
    00038 #include <assert.h>
    00039 #include <string.h>
    00040 #include "dither-impl.h"
    00041
    00042 int
    00043 stpi_dither_translate_channel(stp_vars_t *v, unsigned channel,
    00044                               unsigned subchannel)
    00045 {
    00046   stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
    00047   unsigned chan_idx;
    00048   if (!d)
    00049     return -1;
    00050   if (channel >= d->channel_count)
    00051     return -1;
    00052   if (subchannel >= d->subchannel_count[channel])
    00053     return -1;
    00054   chan_idx = d->channel_index[channel];
    00055   return chan_idx + subchannel;
    00056 }
    00057
    00058 unsigned char *
    00059 stp_dither_get_channel(stp_vars_t *v, unsigned channel, unsigned subchannel)
    00060 {
    00061   stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
    00062   int place = stpi_dither_translate_channel(v, channel, subchannel);
    00063   if (place >= 0)
    00064     return d->channel[place].ptr;
    00065   else
    00066     return NULL;
    00067 }
    00068
    00069 static void
    00070 insert_channel(stp_vars_t *v, stpi_dither_t *d, int channel)
    00071 {
    00072   unsigned oc = d->channel_count;
    00073   int i;
    00074   d->channel_index =
    00075     stp_realloc (d->channel_index, sizeof(unsigned) * (channel + 1));
    00076   d->subchannel_count =
    00077     stp_realloc (d->subchannel_count, sizeof(unsigned) * (channel + 1));
    00078   for (i = oc; i < channel + 1; i++)
    00079     {
    00080       if (oc == 0)
    00081         d->channel_index[i] = 0;
    00082       else
    00083         d->channel_index[i] =
    00084           d->channel_index[oc - 1] + d->subchannel_count[oc - 1];
    00085       d->subchannel_count[i] = 0;
    00086     }
    00087   d->channel_count = channel + 1;
    00088 }
    00089
    00090 void
    00091 stpi_dither_channel_destroy(stpi_dither_channel_t *channel)
    00092 {
    00093   int i;
    00094   STP_SAFE_FREE(channel->ink_list);
    00095   if (channel->errs)
    00096     {
    00097       for (i = 0; i < channel->error_rows; i++)
    00098         STP_SAFE_FREE(channel->errs[i]);
    00099       STP_SAFE_FREE(channel->errs);
    00100     }
    00101   STP_SAFE_FREE(channel->ranges);
    00102   stp_dither_matrix_destroy(&(channel->pick));
    00103   stp_dither_matrix_destroy(&(channel->dithermat));
    00104 }
    00105
    00106 static void
    00107 initialize_channel(stp_vars_t *v, int channel, int subchannel)
    00108 {
    00109   stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
    00110   int idx = stpi_dither_translate_channel(v, channel, subchannel);
    00111   stpi_dither_channel_t *dc = &(CHANNEL(d, idx));
    00112   stp_shade_t shade;
    00113   stp_dotsize_t dot;
    00114   assert(idx >= 0);
    00115   memset(dc, 0, sizeof(stpi_dither_channel_t));
    00116   stp_dither_matrix_clone(&(d->dither_matrix), &(dc->dithermat), 0, 0);
    00117   stp_dither_matrix_clone(&(d->transition_matrix), &(dc->pick), 0, 0);
    00118   shade.dot_sizes = &dot;
    00119   shade.value = 1.0;
    00120   shade.numsizes = 1;
    00121   dot.bit_pattern = 1;
    00122   dot.value = 1.0;
    00123   stp_dither_set_inks_full(v, channel, 1, &shade, 1.0, 1.0);
    00124 }
    00125
    00126 static void
    00127 insert_subchannel(stp_vars_t *v, stpi_dither_t *d, int channel, int subchannel)
    00128 {
    00129   int i;
    00130   unsigned oc = d->subchannel_count[channel];
    00131   unsigned increment = subchannel - oc + 1;
    00132   unsigned old_place = d->channel_index[channel] + oc;
    00133   stpi_dither_channel_t *nc =
    00134     stp_malloc(sizeof(stpi_dither_channel_t) *
    00135                (d->total_channel_count + increment));
    00136
    00137   if (d->channel)
    00138     {
    00139       /*
    00140        * Copy the old channels, including all subchannels of the current
    00141        * channel that already existed.
    00142        */
    00143       memcpy(nc, d->channel, sizeof(stpi_dither_channel_t) * old_place);
    00144       if (old_place < d->total_channel_count)
    00145         /*
    00146          * If we're inserting a new subchannel in the middle somewhere,
    00147          * we need to move everything else up
    00148          */
    00149         memcpy(nc + old_place + increment, d->channel + old_place,
    00150                (sizeof(stpi_dither_channel_t) *
    00151                 (d->total_channel_count - old_place)));
    00152       stp_free(d->channel);
    00153     }
    00154   d->channel = nc;
    00155   if (channel < d->channel_count - 1)
    00156     /* Now fix up the subchannel offsets */
    00157     for (i = channel + 1; i < d->channel_count; i++)
    00158       d->channel_index[i] += increment;
    00159   d->subchannel_count[channel] = subchannel + 1;
    00160   d->total_channel_count += increment;
    00161   for (i = oc; i < oc + increment; i++)
    00162     initialize_channel(v, channel, i);
    00163 }
    00164
    00165 void
    00166 stpi_dither_finalize(stp_vars_t *v)
    00167 {
    00168   stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
    00169   if (!d->finalized)
    00170     {
    00171       int i;
    00172       unsigned rc = 1 + (unsigned) ceil(sqrt(CHANNEL_COUNT(d)));
    00173       unsigned x_n = d->dither_matrix.x_size / rc;
    00174       unsigned y_n = d->dither_matrix.y_size / rc;
    00175       for (i = 0; i < CHANNEL_COUNT(d); i++)
    00176         {
    00177           stpi_dither_channel_t *dc = &(CHANNEL(d, i));
    00178           stp_dither_matrix_clone(&(d->dither_matrix), &(dc->dithermat),
    00179                                    x_n * (i % rc), y_n * (i / rc));
    00180           stp_dither_matrix_clone(&(d->dither_matrix), &(dc->pick),
    00181                                    x_n * (i % rc), y_n * (i / rc));
    00182         }
    00183       d->finalized = 1;
    00184     }
    00185 }
    00186
    00187 void
    00188 stp_dither_add_channel(stp_vars_t *v, unsigned char *data,
    00189                        unsigned channel, unsigned subchannel)
    00190 {
    00191   stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
    00192   int idx;
    00193   if (channel >= d->channel_count)
    00194     insert_channel(v, d, channel);
    00195   if (subchannel >= d->subchannel_count[channel])
    00196     insert_subchannel(v, d, channel, subchannel);
    00197   idx = stpi_dither_translate_channel(v, channel, subchannel);
    00198   assert(idx >= 0);
    00199   d->channel[idx].ptr = data;
    00200 }
    00201
    00202 static void
    00203 stpi_dither_finalize_ranges(stp_vars_t *v, stpi_dither_channel_t *dc)
    00204 {
    00205   stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
    00206   int i;
    00207   unsigned lbit = dc->bit_max;
    00208   dc->signif_bits = 0;
    00209   while (lbit > 0)
    00210     {
    00211       dc->signif_bits++;
    00212       lbit >>= 1;
    00213     }
    00214
    00215   for (i = 0; i < dc->nlevels; i++)
    00216     {
    00217       if (dc->ranges[i].lower->bits == dc->ranges[i].upper->bits)
    00218         dc->ranges[i].is_same_ink = 1;
    00219       else
    00220         dc->ranges[i].is_same_ink = 0;
    00221       if (dc->ranges[i].range_span > 0 && dc->ranges[i].value_span > 0)
    00222         dc->ranges[i].is_equal = 0;
    00223       else
    00224         dc->ranges[i].is_equal = 1;
    00225
    00226       stp_dprintf(STP_DBG_INK, v,
    00227                   "    level %d value[0] %d value[1] %d range[0] %d range[1] %d\n",
    00228                   i, dc->ranges[i].lower->value, dc->ranges[i].upper->value,
    00229                   dc->ranges[i].lower->range, dc->ranges[i].upper->range);
    00230       stp_dprintf(STP_DBG_INK, v,
    00231                   "       bits[0] %d bits[1] %d\n",
    00232                   dc->ranges[i].lower->bits, dc->ranges[i].upper->bits);
    00233       stp_dprintf(STP_DBG_INK, v,
    00234                   "       rangespan %d valuespan %d same_ink %d equal %d\n",
    00235                   dc->ranges[i].range_span, dc->ranges[i].value_span,
    00236                   dc->ranges[i].is_same_ink, dc->ranges[i].is_equal);
    00237       if (i > 0 && dc->ranges[i].lower->range >= d->adaptive_limit)
    00238         {
    00239           d->adaptive_limit = dc->ranges[i].lower->range + 1;
    00240           if (d->adaptive_limit > 65535)
    00241             d->adaptive_limit = 65535;
    00242           stp_dprintf(STP_DBG_INK, v, "Setting adaptive limit to %d\n",
    00243                       d->adaptive_limit);
    00244         }
    00245     }
    00246   for (i = 0; i <= dc->nlevels; i++)
    00247     stp_dprintf(STP_DBG_INK, v,
    00248                 "    ink_list[%d] range %d value %d bits %d\n",
    00249                 i, dc->ink_list[i].range,
    00250                 dc->ink_list[i].value, dc->ink_list[i].bits);
    00251   if (dc->nlevels == 1 && dc->ranges[0].upper->bits == 1)
    00252     dc->very_fast = 1;
    00253   else
    00254     dc->very_fast = 0;
    00255
    00256   stp_dprintf(STP_DBG_INK, v,
    00257               "  bit_max %d signif_bits %d\n", dc->bit_max, dc->signif_bits);
    00258 }
    00259
    00260 static void
    00261 stpi_dither_set_ranges(stp_vars_t *v, int color, const stp_shade_t *shade,
    00262                        double density, double darkness)
    00263 {
    00264   stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
    00265   stpi_dither_channel_t *dc = &(CHANNEL(d, color));
    00266   const stp_dotsize_t *ranges = shade->dot_sizes;
    00267   int nlevels = shade->numsizes;
    00268   int i;
    00269
    00270   STP_SAFE_FREE(dc->ranges);
    00271   STP_SAFE_FREE(dc->ink_list);
    00272
    00273   dc->nlevels = nlevels > 1 ? nlevels + 1 : nlevels;
    00274   dc->ranges = (stpi_dither_segment_t *)
    00275     stp_zalloc(dc->nlevels * sizeof(stpi_dither_segment_t));
    00276   dc->ink_list = (stpi_ink_defn_t *)
    00277     stp_zalloc((dc->nlevels + 1) * sizeof(stpi_ink_defn_t));
    00278   dc->bit_max = 0;
    00279   dc->density = density * 65535;
    00280   dc->darkness = darkness;
    00281   stp_init_debug_messages(v);
    00282   stp_dprintf(STP_DBG_INK, v,
    00283               "stpi_dither_set_ranges channel %d nlevels %d density %f darkness %f\n",
    00284               color, nlevels, density, darkness);
    00285   for (i = 0; i < nlevels; i++)
    00286     stp_dprintf(STP_DBG_INK, v,
    00287                 "  level %d value %f pattern %x\n", i,
    00288                 ranges[i].value, ranges[i].bit_pattern);
    00289   dc->ranges[0].lower = &dc->ink_list[0];
    00290   dc->ranges[0].upper = &dc->ink_list[1];
    00291   dc->ink_list[0].range = 0;
    00292   dc->ink_list[0].value = 0;
    00293   dc->ink_list[0].bits = 0;
    00294   if (nlevels == 1)
    00295     dc->ink_list[1].range = 65535;
    00296   else
    00297     dc->ink_list[1].range = ranges[0].value * 65535.0 * density;
    00298   if (dc->ink_list[1].range > 65535)
    00299     dc->ink_list[1].range = 65535;
    00300   dc->ink_list[1].value = ranges[0].value * 65535.0;
    00301   if (dc->ink_list[1].value > 65535)
    00302     dc->ink_list[1].value = 65535;
    00303   dc->ink_list[1].bits = ranges[0].bit_pattern;
    00304   if (ranges[0].bit_pattern > dc->bit_max)
    00305     dc->bit_max = ranges[0].bit_pattern;
    00306   dc->ranges[0].range_span = dc->ranges[0].upper->range;
    00307   dc->ranges[0].value_span = dc->ranges[0].upper->value;
    00308   if (dc->nlevels > 1)
    00309     {
    00310       for (i = 1; i < nlevels; i++)
    00311         {
    00312           int l = i + 1;
    00313           dc->ranges[i].lower = &dc->ink_list[i];
    00314           dc->ranges[i].upper = &dc->ink_list[l];
    00315
    00316           dc->ink_list[l].range =
    00317             (ranges[i].value + ranges[i].value) * 32768.0 * density;
    00318           if (dc->ink_list[l].range > 65535)
    00319             dc->ink_list[l].range = 65535;
    00320           dc->ink_list[l].value = ranges[i].value * 65535.0;
    00321           if (dc->ink_list[l].value > 65535)
    00322             dc->ink_list[l].value = 65535;
    00323           dc->ink_list[l].bits = ranges[i].bit_pattern;
    00324           if (ranges[i].bit_pattern > dc->bit_max)
    00325             dc->bit_max = ranges[i].bit_pattern;
    00326           dc->ranges[i].range_span =
    00327             dc->ink_list[l].range - dc->ink_list[i].range;
    00328           dc->ranges[i].value_span =
    00329             dc->ink_list[l].value - dc->ink_list[i].value;
    00330         }
    00331       dc->ranges[i].lower = &dc->ink_list[i];
    00332       dc->ranges[i].upper = &dc->ink_list[i+1];
    00333       dc->ink_list[i+1] = dc->ink_list[i];
    00334       dc->ink_list[i+1].range = 65535;
    00335       dc->ranges[i].range_span =
    00336         dc->ink_list[i+1].range - dc->ink_list[i].range;
    00337       dc->ranges[i].value_span =
    00338         dc->ink_list[i+1].value - dc->ink_list[i].value;
    00339     }
    00340   stpi_dither_finalize_ranges(v, dc);
    00341   stp_flush_debug_messages(v);
    00342 }
    00343
    00344 void
    00345 stp_dither_set_inks_simple(stp_vars_t *v, int color, int nlevels,
    00346                            const double *levels, double density,
    00347                            double darkness)
    00348 {
    00349   stp_shade_t s;
    00350   stp_dotsize_t *d = stp_malloc(nlevels * sizeof(stp_dotsize_t));
    00351   int i;
    00352   s.dot_sizes = d;
    00353   s.value = 65535.0;
    00354   s.numsizes = nlevels;
    00355
    00356   for (i = 0; i < nlevels; i++)
    00357     {
    00358       d[i].bit_pattern = i + 1;
    00359       d[i].value = levels[i];
    00360     }
    00361   stp_dither_set_inks_full(v, color, 1, &s, density, darkness);
    00362   stp_free(d);
    00363 }
    00364
    00365 void
    00366 stp_dither_set_inks_full(stp_vars_t *v, int color, int nshades,
    00367                          const stp_shade_t *shades, double density,
    00368                          double darkness)
    00369 {
    00370   int i;
    00371   int idx;
    00372   stpi_dither_channel_t *dc;
    00373
    00374   stpi_dither_t *d = (stpi_dither_t *) stp_get_component_data(v, "Dither");
    00375
    00376   stp_channel_reset_channel(v, color);
    00377
    00378   for (i = nshades - 1; i >= 0; i--)
    00379     {
    00380       int subchannel = nshades - i - 1;
    00381       idx = stpi_dither_translate_channel(v, color, subchannel);
    00382       assert(idx >= 0);
    00383       dc = &(CHANNEL(d, idx));
    00384
    00385       stp_channel_add(v, color, subchannel, shades[i].value);
    00386       if (idx >= 0)
    00387         stpi_dither_set_ranges(v, idx, &shades[i], density,
    00388                                shades[i].value * darkness);
    00389       stp_dprintf(STP_DBG_INK, v,
    00390                   "  shade %d value %f\n",
    00391                   i, shades[i].value);
    00392     }
    00393 }
    00394
    00395 void
    00396 stp_dither_set_inks(stp_vars_t *v, int color, double density, double darkness,
    00397                     int nshades, const double *svalues,
    00398                     int ndotsizes, const double *dvalues)
    00399 {
    00400   int i, j;
    00401   stp_shade_t *shades = stp_malloc(sizeof(stp_shade_t) * nshades);
    00402   stp_dotsize_t *dotsizes = stp_malloc(sizeof(stp_dotsize_t) * ndotsizes);
    00403   j = 0;
    00404   for (i = 0; i < ndotsizes; i++)
    00405     {
    00406       /* Skip over any zero-valued dot sizes */
    00407       if (dvalues[i] > 0)
    00408         {
    00409           dotsizes[j].value = dvalues[i];
    00410           dotsizes[j].bit_pattern = i + 1;
    00411           j++;
    00412         }
    00413     }
    00414   for (i = 0; i < nshades; i++)
    00415     {
    00416       shades[i].value = svalues[i];
    00417       shades[i].numsizes = j;
    00418       shades[i].dot_sizes = dotsizes;
    00419     }
    00420   stp_dither_set_inks_full(v, color, nshades, shades, density, darkness);
    00421   stp_free(dotsizes);
    00422   stp_free(shades);
    00423 }