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

src/main/channel.c

Go to the documentation of this file.
00001 /*
00002  * "$Id: channel.c,v 1.14 2004/05/07 19:20:28 rleigh Exp $"
00003  *
00004  *   Dither routine entrypoints
00005  *
00006  *   Copyright 2003 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 <gimp-print/gimp-print-intl-internal.h>
00033 #ifdef HAVE_LIMITS_H
00034 #include <limits.h>
00035 #endif
00036 #include <math.h>
00037 #include <string.h>
00038 
00039 #ifdef __GNUC__
00040 #define inline __inline__
00041 #endif
00042 
00043 typedef struct
00044 {
00045   double value;
00046   double lower;
00047   double upper;
00048   double cutoff;
00049   unsigned short s_density;
00050 } stpi_subchannel_t;
00051 
00052 typedef struct
00053 {
00054   unsigned subchannel_count;
00055   stpi_subchannel_t *sc;
00056   unsigned short *lut;
00057 } stpi_channel_t;
00058 
00059 typedef struct
00060 {
00061   unsigned channel_count;
00062   unsigned total_channels;
00063   unsigned input_channels;
00064   size_t width;
00065   int initialized;
00066   unsigned ink_limit;
00067   unsigned max_density;
00068   stpi_channel_t *c;
00069   unsigned short *input_data;
00070   unsigned short *data;
00071   int black_channel;
00072 } stpi_channel_group_t;
00073 
00074 
00075 static void
00076 clear_a_channel(stpi_channel_group_t *cg, int channel)
00077 {
00078   if (channel < cg->channel_count)
00079     {
00080       STP_SAFE_FREE(cg->c[channel].sc);
00081       STP_SAFE_FREE(cg->c[channel].lut);
00082       cg->c[channel].subchannel_count = 0;
00083     }
00084 }
00085 
00086 static void
00087 stpi_channel_clear(void *vc)
00088 {
00089   stpi_channel_group_t *cg = (stpi_channel_group_t *) vc;
00090   int i;
00091   if (cg->channel_count > 0)
00092     for (i = 0; i < cg->channel_count; i++)
00093       clear_a_channel(cg, i);
00094   if (cg->data != cg->input_data)
00095     STP_SAFE_FREE(cg->data);
00096   STP_SAFE_FREE(cg->input_data);
00097   STP_SAFE_FREE(cg->c);
00098   cg->channel_count = 0;
00099   cg->total_channels = 0;
00100   cg->input_channels = 0;
00101   cg->initialized = 0;
00102 }
00103 
00104 void
00105 stp_channel_reset(stp_vars_t *v)
00106 {
00107   stpi_channel_group_t *cg =
00108     ((stpi_channel_group_t *) stp_get_component_data(v, "Channel"));
00109   if (cg)
00110     stpi_channel_clear(cg);
00111 }
00112 
00113 void
00114 stp_channel_reset_channel(stp_vars_t *v, int channel)
00115 {
00116   stpi_channel_group_t *cg =
00117     ((stpi_channel_group_t *) stp_get_component_data(v, "Channel"));
00118   if (cg)
00119     clear_a_channel(cg, channel);
00120 }
00121 
00122 static void
00123 stpi_channel_free(void *vc)
00124 {
00125   stpi_channel_clear(vc);
00126   stp_free(vc);
00127 }
00128 
00129 static stpi_subchannel_t *
00130 get_channel(stp_vars_t *v, unsigned channel, unsigned subchannel)
00131 {
00132   stpi_channel_group_t *cg =
00133     ((stpi_channel_group_t *) stp_get_component_data(v, "Channel"));
00134   if (!cg)
00135     return NULL;
00136   if (channel >= cg->channel_count)
00137     return NULL;
00138   if (subchannel >= cg->c[channel].subchannel_count)
00139     return NULL;
00140   return &(cg->c[channel].sc[subchannel]);
00141 }
00142 
00143 void
00144 stp_channel_add(stp_vars_t *v, unsigned channel, unsigned subchannel,
00145                 double value)
00146 {
00147   stpi_channel_group_t *cg =
00148     ((stpi_channel_group_t *) stp_get_component_data(v, "Channel"));
00149   stpi_channel_t *chan;
00150   if (!cg)
00151     {
00152       cg = stp_zalloc(sizeof(stpi_channel_group_t));
00153       cg->black_channel = -1;
00154       stp_allocate_component_data(v, "Channel", NULL, stpi_channel_free, cg);
00155     }
00156   if (channel >= cg->channel_count)
00157     {
00158       unsigned oc = cg->channel_count;
00159       cg->c = stp_realloc(cg->c, sizeof(stpi_channel_t) * (channel + 1));
00160       memset(cg->c + oc, 0, sizeof(stpi_channel_t) * (channel + 1 - oc));
00161       if (channel >= cg->channel_count)
00162         cg->channel_count = channel + 1;
00163     }
00164   chan = cg->c + channel;
00165   if (subchannel >= chan->subchannel_count)
00166     {
00167       unsigned oc = chan->subchannel_count;
00168       chan->sc =
00169         stp_realloc(chan->sc, sizeof(stpi_subchannel_t) * (subchannel + 1));
00170       (void) memset
00171         (chan->sc + oc, 0, sizeof(stpi_subchannel_t) * (subchannel + 1 - oc));
00172       chan->sc[subchannel].value = value;
00173       if (subchannel >= chan->subchannel_count)
00174         chan->subchannel_count = subchannel + 1;
00175     }
00176   chan->sc[subchannel].value = value;
00177   chan->sc[subchannel].s_density = 65535;
00178   chan->sc[subchannel].cutoff = 0.75;
00179 }
00180 
00181 void
00182 stp_channel_set_density_adjustment(stp_vars_t *v, int color, int subchannel,
00183                                    double adjustment)
00184 {
00185   stpi_subchannel_t *sch = get_channel(v, color, subchannel);
00186   if ((strcmp(stp_get_string_parameter(v, "STPIOutputType"), "Raw") == 0 &&
00187        strcmp(stp_get_string_parameter(v, "ColorCorrection"), "None") == 0) ||
00188       (strcmp(stp_get_string_parameter(v, "ColorCorrection"), "Raw") == 0))
00189     {
00190       stp_dprintf(STP_DBG_INK, v,
00191                   "Ignoring channel_density channel %d subchannel %d adjustment %f\n",
00192                   color, subchannel, adjustment);
00193     }
00194   else
00195     {
00196       stp_dprintf(STP_DBG_INK, v,
00197                   "channel_density channel %d subchannel %d adjustment %f\n",
00198                   color, subchannel, adjustment);
00199       if (sch && adjustment >= 0 && adjustment <= 1)
00200         sch->s_density = adjustment * 65535;
00201     }
00202 }
00203 
00204 void
00205 stp_channel_set_ink_limit(stp_vars_t *v, double limit)
00206 {
00207   stpi_channel_group_t *cg =
00208     ((stpi_channel_group_t *) stp_get_component_data(v, "Channel"));
00209   stp_dprintf(STP_DBG_INK, v, "ink_limit %f\n", limit);
00210   if (limit > 0)
00211     cg->ink_limit = 65535 * limit;
00212 }
00213 
00214 void
00215 stp_channel_set_black_channel(stp_vars_t *v, int channel)
00216 {
00217   stpi_channel_group_t *cg =
00218     ((stpi_channel_group_t *) stp_get_component_data(v, "Channel"));
00219   stp_dprintf(STP_DBG_INK, v, "black_channel %d\n", channel);
00220   cg->black_channel = channel;
00221 }
00222 
00223 void
00224 stp_channel_set_cutoff_adjustment(stp_vars_t *v, int color, int subchannel,
00225                                   double adjustment)
00226 {
00227   stpi_subchannel_t *sch = get_channel(v, color, subchannel);
00228   stp_dprintf(STP_DBG_INK, v,
00229               "channel_cutoff channel %d subchannel %d adjustment %f\n",
00230               color, subchannel, adjustment);
00231   if (sch && adjustment >= 0)
00232     sch->cutoff = adjustment;
00233 }
00234 
00235 static int
00236 input_needs_splitting(const stp_vars_t *v)
00237 {
00238   const stpi_channel_group_t *cg =
00239     ((const stpi_channel_group_t *) stp_get_component_data(v, "Channel"));
00240 #if 1
00241   return cg->total_channels != cg->input_channels;
00242 #else
00243   int i;
00244   if (!cg || cg->channel_count <= 0)
00245     return 0;
00246   for (i = 0; i < cg->channel_count; i++)
00247     {
00248       if (cg->c[i].subchannel_count > 1)
00249         return 1;
00250     }
00251   return 0;
00252 #endif
00253 }
00254 
00255 void
00256 stp_channel_initialize(stp_vars_t *v, stp_image_t *image,
00257                        int input_channel_count)
00258 {
00259   stpi_channel_group_t *cg =
00260     ((stpi_channel_group_t *) stp_get_component_data(v, "Channel"));
00261   int width = stp_image_width(image);
00262   int i, j, k;
00263   if (!cg)
00264     {
00265       cg = stp_zalloc(sizeof(stpi_channel_group_t));
00266       cg->black_channel = -1;
00267       stp_allocate_component_data(v, "Channel", NULL, stpi_channel_free, cg);
00268     }
00269   if (cg->initialized)
00270     return;
00271   cg->initialized = 1;
00272   cg->max_density = 0;
00273   if (cg->black_channel < -1 || cg->black_channel >= cg->channel_count)
00274     cg->black_channel = -1;
00275   for (i = 0; i < cg->channel_count; i++)
00276     {
00277       stpi_channel_t *c = &(cg->c[i]);
00278       int sc = c->subchannel_count;
00279       if (sc > 1)
00280         {
00281           int val = 0;
00282           int next_breakpoint;
00283           c->lut = stp_zalloc(sizeof(unsigned short) * sc * 65536);
00284           next_breakpoint = c->sc[0].value * 65535 * c->sc[0].cutoff;
00285           if (next_breakpoint > 65535)
00286             next_breakpoint = 65535;
00287           while (val <= next_breakpoint)
00288             {
00289               int value = (int) ((double) val / c->sc[0].value);
00290               c->lut[val * sc + sc - 1] = value;
00291               val++;
00292             }
00293 
00294           for (k = 0; k < sc - 1; k++)
00295             {
00296               double this_val = c->sc[k].value;
00297               double next_val = c->sc[k + 1].value;
00298               double this_cutoff = c->sc[k].cutoff;
00299               double next_cutoff = c->sc[k + 1].cutoff;
00300               int range;
00301               int base = val;
00302               double cutoff = sqrt(this_cutoff * next_cutoff);
00303               next_breakpoint = next_val * 65535 * cutoff;
00304               if (next_breakpoint > 65535)
00305                 next_breakpoint = 65535;
00306               range = next_breakpoint - val;
00307               while (val <= next_breakpoint)
00308                 {
00309                   double where = ((double) val - base) / (double) range;
00310                   double lower_val = base * (1.0 - where);
00311                   double lower_amount = lower_val / this_val;
00312                   double upper_amount = (val - lower_val) / next_val;
00313                   c->lut[val * sc + sc - k - 2] = upper_amount;
00314                   c->lut[val * sc + sc - k - 1] = lower_amount;
00315                   val++;
00316                 }
00317             }
00318           while (val <= 65535)
00319             {
00320               c->lut[val * sc] = val / c->sc[sc - 1].value;
00321               val++;
00322             }
00323         }
00324       cg->total_channels += c->subchannel_count;
00325       for (j = 0; j < c->subchannel_count; j++)
00326         cg->max_density += c->sc[j].s_density;
00327     }
00328   cg->input_channels = input_channel_count;
00329   cg->width = width;
00330   cg->data = stp_malloc(sizeof(unsigned short) * cg->total_channels * width);
00331   if (!input_needs_splitting(v))
00332     {
00333       cg->input_data = cg->data;
00334       return;
00335     }
00336   cg->input_data =
00337     stp_malloc(sizeof(unsigned short) * cg->input_channels * width);
00338 }
00339 
00340 static void
00341 clear_channel(unsigned short *data, unsigned width, unsigned depth)
00342 {
00343   int i;
00344   width *= depth;
00345   for (i = 0; i < width; i += depth)
00346     data[i] = 0;
00347 }
00348 
00349 static int
00350 scale_channel(unsigned short *data, unsigned width, unsigned depth,
00351               unsigned short density)
00352 {
00353   int i;
00354   int retval = 0;
00355   unsigned short previous_data = 0;
00356   unsigned short previous_value = 0;
00357   if (density > 65535)
00358     density = 65535;
00359   width *= depth;
00360   for (i = 0; i < width; i += depth)
00361     {
00362       if (data[i] == previous_data)
00363         data[i] = previous_value;
00364       else if (data[i] == (unsigned short) 65535)
00365         {
00366           data[i] = density;
00367           retval = 1;
00368         }
00369       else if (data[i] > 0)
00370         {
00371           unsigned short tval = (32767u + data[i] * density) / 65535u;
00372           previous_data = data[i];
00373           if (tval)
00374             retval = 1;
00375           previous_value = (unsigned short) tval;
00376           data[i] = (unsigned short) tval;
00377         }
00378     }
00379   return retval;
00380 }
00381 
00382 static int
00383 scan_channel(unsigned short *data, unsigned width, unsigned depth)
00384 {
00385   int i;
00386   width *= depth;
00387   for (i = 0; i < width; i += depth)
00388     {
00389       if (data[i])
00390         return 1;
00391     }
00392   return 0;
00393 }
00394 
00395 static inline unsigned
00396 ink_sum(const unsigned short *data, int total_channels)
00397 {
00398   int j;
00399   unsigned total_ink = 0;
00400   for (j = 0; j < total_channels; j++)
00401     total_ink += data[j];
00402   return total_ink;
00403 }
00404 
00405 static int
00406 limit_ink(const stp_vars_t *v)
00407 {
00408   int i;
00409   int retval = 0;
00410   stpi_channel_group_t *cg =
00411     ((stpi_channel_group_t *) stp_get_component_data(v, "Channel"));
00412   unsigned short *ptr = cg->data;
00413   if (cg->ink_limit == 0 || cg->ink_limit >= cg->max_density)
00414     return 0;
00415   for (i = 0; i < cg->width; i++)
00416     {
00417       int total_ink = ink_sum(ptr, cg->total_channels);
00418       if (total_ink > cg->ink_limit) /* Need to limit ink? */
00419         {
00420           int j;
00421           /*
00422            * FIXME we probably should first try to convert light ink to dark
00423            */
00424           double ratio = (double) cg->ink_limit / (double) total_ink;
00425           for (j = 0; j < cg->total_channels; j++)
00426             ptr[j] *= ratio;
00427           retval = 1;
00428         }
00429       ptr += cg->total_channels;
00430    }
00431   return retval;
00432 }
00433 
00434 static inline int
00435 mem_eq(const unsigned short *i1, const unsigned short *i2, int count)
00436 {
00437   int i;
00438   for (i = 0; i < count; i++)
00439     if (i1[i] != i2[i])
00440       return 0;
00441   return 1;
00442 }
00443 
00444 void
00445 stp_channel_convert(const stp_vars_t *v, unsigned *zero_mask)
00446 {
00447   stpi_channel_group_t *cg =
00448     ((stpi_channel_group_t *) stp_get_component_data(v, "Channel"));
00449   int i, j, k;
00450   int nz[STP_CHANNEL_LIMIT];
00451   int outbytes = cg->total_channels * sizeof(unsigned short);
00452   const unsigned short *input_cache = NULL;
00453   const unsigned short *output_cache = NULL;
00454   unsigned black_value = 0;
00455   unsigned l_val = 0;
00456   unsigned i_val = 0;
00457   unsigned o_val = 0;
00458   unsigned offset = 0;
00459   unsigned virtual_black = 0;
00460   memset(nz, 0, sizeof(nz));
00461   if (input_needs_splitting(v))
00462     {
00463       const unsigned short *input = cg->input_data;
00464       unsigned short *output = cg->data;
00465       const unsigned short *o_output;
00466       for (i = 0; i < cg->width; i++)
00467         {
00468           int zero_ptr = 0;
00469           if (input_cache && mem_eq(input_cache, input, cg->input_channels))
00470             {
00471               memcpy(output, output_cache, outbytes);
00472               input += cg->input_channels;
00473               output += cg->total_channels;
00474             }
00475           else
00476             {
00477               input_cache = input;
00478               black_value = 0;
00479               o_output = output;
00480               if (cg->black_channel >= 0)
00481                 black_value = input[cg->black_channel];
00482               virtual_black = 65535;
00483               for (j = 0; j < cg->channel_count; j++)
00484                 {
00485                   if (input[j] < virtual_black && j != cg->black_channel)
00486                     virtual_black = input[j];
00487                 }
00488               black_value += virtual_black / 4;
00489               for (j = 0; j < cg->channel_count; j++)
00490                 {
00491                   stpi_channel_t *c = &(cg->c[j]);
00492                   int s_count = c->subchannel_count;
00493                   if (s_count >= 1)
00494                     {
00495                       i_val = *input++;
00496                       if (i_val == 0)
00497                         {
00498                           for (k = 0; k < s_count; k++)
00499                             *(output++) = 0;
00500                         }
00501                       else if (s_count == 1)
00502                         {
00503                           if (c->sc[0].s_density < 65535)
00504                             i_val = i_val * c->sc[0].s_density / 65535;
00505                           nz[zero_ptr++] |= *(output++) = i_val;
00506                         }
00507                       else
00508                         {
00509                           l_val = i_val;
00510                           if (i_val > 0 && black_value &&
00511                               j != cg->black_channel)
00512                             {
00513                               l_val += black_value;
00514                               if (l_val > 65535)
00515                                 l_val = 65535;
00516                             }
00517                           offset = l_val * s_count;
00518                           for (k = 0; k < s_count; k++)
00519                             {
00520                               if (c->sc[k].s_density > 0)
00521                                 {
00522                                   o_val = c->lut[offset + k];
00523                                   if (i_val != l_val)
00524                                     o_val = o_val * i_val / l_val;
00525                                   if (c->sc[k].s_density < 65535)
00526                                     o_val = o_val * c->sc[k].s_density / 65535;
00527                                 }
00528                               else
00529                                 o_val = 0;
00530                               *output++ = o_val;
00531                               nz[zero_ptr++] |= o_val;
00532                             }
00533                         }
00534                     }
00535                 }
00536               output_cache = o_output;
00537             }
00538         }
00539       if (zero_mask)
00540         {
00541           *zero_mask = 0;
00542           for (i = 0; i < cg->total_channels; i++)
00543             if (!nz[i])
00544               *zero_mask |= 1 << i;
00545         }
00546     }
00547   else
00548     {
00549       int physical_channel = 0;
00550       if (zero_mask)
00551         *zero_mask = 0;
00552       for (i = 0; i < cg->channel_count; i++)
00553         {
00554           stpi_channel_t *ch = &(cg->c[i]);
00555           if (ch->subchannel_count > 0)
00556             for (j = 0; j < ch->subchannel_count; j++)
00557               {
00558                 stpi_subchannel_t *sch = &(ch->sc[j]);
00559                 unsigned density = sch->s_density;
00560                 unsigned short *output = cg->data + physical_channel;
00561                 if (density == 0)
00562                   {
00563                     clear_channel(output, cg->width, cg->total_channels);
00564                     if (zero_mask)
00565                       *zero_mask |= 1 << physical_channel;
00566                   }
00567                 else if (density != 65535)
00568                   {
00569                     if (scale_channel(output, cg->width, cg->total_channels,
00570                                       density) == 0)
00571                       if (zero_mask)
00572                         *zero_mask |= 1 << physical_channel;
00573                   }
00574                 else if (zero_mask)
00575                   {
00576                     if (scan_channel(output, cg->width, cg->total_channels) == 0)
00577                       *zero_mask |= 1 << physical_channel;
00578                   }
00579                 physical_channel++;
00580               }
00581         }
00582     }
00583   (void) limit_ink(v);
00584 }
00585 
00586 unsigned short *
00587 stp_channel_get_input(const stp_vars_t *v)
00588 {
00589   stpi_channel_group_t *cg =
00590     ((stpi_channel_group_t *) stp_get_component_data(v, "Channel"));
00591   return (unsigned short *) cg->input_data;
00592 }
00593 
00594 unsigned short *
00595 stp_channel_get_output(const stp_vars_t *v)
00596 {
00597   stpi_channel_group_t *cg =
00598     ((stpi_channel_group_t *) stp_get_component_data(v, "Channel"));
00599   return cg->data;
00600 }

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