示例#1
0
PRIVATE void
get_premultiplied_double_row( W8 *in,
                              int PRbytes,
                              int         x,
                              int         y,
                              int         w,
                              double     *row,
                              W8      *tmp_src,
                              int         n )
{
    int b;
    int bytes = PRbytes;

    pixel_region_get_row( in, y, w, tmp_src, bytes );

    if( pixel_region_has_alpha( bytes ) )
    {
        /* premultiply the alpha into the double array */
        double *irow  = row;
        int     alpha = bytes - 1;
        double  mod_alpha;

        for( x = 0; x < w; ++x )
        {
            mod_alpha = tmp_src[ alpha ] / 255.0;
            for( b = 0; b < alpha; ++b )
            {
                irow[ b ] = mod_alpha * tmp_src[ b ];
            }

            irow[ b ] = tmp_src[ alpha ];
            irow += bytes;
            tmp_src += bytes;
        }
    }
    else /* no alpha */
    {
        for( x = 0; x < w * bytes; ++x )
        {
            row[ x ] = tmp_src[ x ];
        }
    }

    /* set the off edge pixels to their nearest neighbor */
    for( b = 0; b < 2 * bytes; b++ )
    {
        row[ b - 2 * bytes ] = row[ b % bytes ];
    }

    for( b = 0; b < bytes * 2; b++ )
    {
        row[ b + w * bytes ] = row[ (w - 1) * bytes + b % bytes ];
    }
}
示例#2
0
void
subsample_region (PixelRegion *srcPR,
                  PixelRegion *destPR,
                  gint         subsample)
{
  const gint     width       = destPR->w;
  const gint     height      = destPR->h;
  const gint     orig_width  = srcPR->w / subsample;
  const gint     orig_height = srcPR->h / subsample;
  const gdouble  x_ratio     = (gdouble) orig_width / (gdouble) width;
  const gdouble  y_ratio     = (gdouble) orig_height / (gdouble) height;
  const gint     bytes       = destPR->bytes;
  const gint     destwidth   = destPR->rowstride;
  const gboolean has_alpha   = pixel_region_has_alpha (srcPR);
  guchar        *src,  *s;
  guchar        *dest, *d;
  gdouble       *row,  *r;
  gint           src_row, src_col;
  gdouble        x_sum, y_sum;
  gdouble        x_last, y_last;
  gdouble       *x_frac, y_frac;
  gdouble        tot_frac;
  gint           i, j;
  gint           b;
  gint           frac;
  gboolean       advance_dest;

#if 0
  g_printerr ("subsample_region: (%d x %d) -> (%d x %d)\n",
              orig_width, orig_height, width, height);
#endif

  /*  the data pointers...  */
  src  = g_new (guchar, orig_width * bytes);
  dest = destPR->data;

  /*  allocate an array to help with the calculations  */
  row    = g_new (gdouble, width * bytes);
  x_frac = g_new (gdouble, width + orig_width);

  /*  initialize the pre-calculated pixel fraction array  */
  src_col = 0;
  x_sum = (gdouble) src_col;
  x_last = x_sum;

  for (i = 0; i < width + orig_width; i++)
    {
      if (x_sum + x_ratio <= (src_col + 1 + EPSILON))
        {
          x_sum += x_ratio;
          x_frac[i] = x_sum - x_last;
        }
      else
        {
          src_col ++;
          x_frac[i] = src_col - x_last;
        }

      x_last += x_frac[i];
    }

  /*  clear the "row" array  */
  memset (row, 0, sizeof (gdouble) * width * bytes);

  /*  counters...  */
  src_row = 0;
  y_sum = (gdouble) src_row;
  y_last = y_sum;

  pixel_region_get_row (srcPR,
                        srcPR->x, srcPR->y + src_row * subsample,
                        orig_width * subsample,
                        src, subsample);

  /*  Scale the selected region  */
  for (i = 0; i < height; )
    {
      src_col = 0;
      x_sum = (gdouble) src_col;

      /* determine the fraction of the src pixel we are using for y */
      if (y_sum + y_ratio <= (src_row + 1 + EPSILON))
        {
          y_sum += y_ratio;
          y_frac = y_sum - y_last;
          advance_dest = TRUE;
        }
      else
        {
          src_row ++;
          y_frac = src_row - y_last;
          advance_dest = FALSE;
        }

      y_last += y_frac;

      s = src;
      r = row;

      frac = 0;
      j = width;

      while (j)
        {
          tot_frac = x_frac[frac++] * y_frac;

          if (has_alpha)
            {
              /* premultiply */

              gdouble local_frac = tot_frac * (gdouble) s[bytes - 1] / 255.0;

              for (b = 0; b < (bytes - 1); b++)
                r[b] += s[b] * local_frac;

              r[bytes - 1] += local_frac;
            }
          else
            {
              for (b = 0; b < bytes; b++)
                r[b] += s[b] * tot_frac;
            }

          /*  increment the destination  */
          if (x_sum + x_ratio <= (src_col + 1 + EPSILON))
            {
              r += bytes;
              x_sum += x_ratio;
              j--;
            }

          /* increment the source */
          else
            {
              s += bytes;
              src_col++;
            }
        }

      if (advance_dest)
        {
          tot_frac = 1.0 / (x_ratio * y_ratio);

          /*  copy "row" to "dest"  */
          d = dest;
          r = row;

          j = width;
          while (j--)
            {
              if (has_alpha)
                {
                  /* unpremultiply */

                  gdouble alpha = r[bytes - 1];

                  if (alpha > EPSILON)
                    {
                      for (b = 0; b < (bytes - 1); b++)
                        d[b] = (guchar) ((r[b] / alpha) + 0.5);

                      d[bytes - 1] = (guchar) ((alpha * tot_frac * 255.0) + 0.5);
                    }
                  else
                    {
                      for (b = 0; b < bytes; b++)
                        d[b] = 0;
                    }
                }
              else
                {
                  for (b = 0; b < bytes; b++)
                    d[b] = (guchar) ((r[b] * tot_frac) + 0.5);
                }

              r += bytes;
              d += bytes;
            }

          dest += destwidth;

          /*  clear the "row" array  */
          memset (row, 0, sizeof (gdouble) * destwidth);

          i++;
        }
      else
        {
          pixel_region_get_row (srcPR,
                                srcPR->x,
                                srcPR->y + src_row * subsample,
                                orig_width * subsample,
                                src, subsample);
        }
    }

  /*  free up temporary arrays  */
  g_free (row);
  g_free (x_frac);
  g_free (src);
}
示例#3
0
void
subsample_indexed_region (PixelRegion  *srcPR,
                          PixelRegion  *destPR,
                          const guchar *cmap,
                          gint          subsample)
{
  const gint     width       = destPR->w;
  const gint     height      = destPR->h;
  const gint     orig_width  = srcPR->w / subsample;
  const gint     orig_height = srcPR->h / subsample;
  const gdouble  x_ratio     = (gdouble) orig_width / (gdouble) width;
  const gdouble  y_ratio     = (gdouble) orig_height / (gdouble) height;
  const gint     bytes       = destPR->bytes;
  const gint     destwidth   = destPR->rowstride;
  const gboolean has_alpha   = pixel_region_has_alpha (srcPR);
  guchar        *src,  *s;
  guchar        *dest, *d;
  gdouble       *row,  *r;
  gint           src_row, src_col;
  gdouble        x_sum, y_sum;
  gdouble        x_last, y_last;
  gdouble       *x_frac, y_frac;
  gdouble        tot_frac;
  gint           i, j;
  gint           b;
  gint           frac;
  gboolean       advance_dest;

  g_return_if_fail (cmap != NULL);

  /*  the data pointers...  */
  src  = g_new (guchar, orig_width * bytes);
  dest = destPR->data;

  /*  allocate an array to help with the calculations  */
  row    = g_new0 (gdouble, width * bytes);
  x_frac = g_new (gdouble, width + orig_width);

  /*  initialize the pre-calculated pixel fraction array  */
  src_col = 0;
  x_sum   = (gdouble) src_col;
  x_last  = x_sum;

  for (i = 0; i < width + orig_width; i++)
    {
      if (x_sum + x_ratio <= (src_col + 1 + EPSILON))
        {
          x_sum += x_ratio;
          x_frac[i] = x_sum - x_last;
        }
      else
        {
          src_col++;
          x_frac[i] = src_col - x_last;
        }

      x_last += x_frac[i];
    }

  /*  counters...  */
  src_row = 0;
  y_sum   = (gdouble) src_row;
  y_last  = y_sum;

  pixel_region_get_row (srcPR,
                        srcPR->x,
                        srcPR->y + src_row * subsample,
                        orig_width * subsample,
                        src,
                        subsample);

  /*  Scale the selected region  */
  for (i = 0; i < height; )
    {
      src_col = 0;
      x_sum   = (gdouble) src_col;

      /* determine the fraction of the src pixel we are using for y */
      if (y_sum + y_ratio <= (src_row + 1 + EPSILON))
        {
          y_sum += y_ratio;
          y_frac = y_sum - y_last;
          advance_dest = TRUE;
        }
      else
        {
          src_row++;
          y_frac = src_row - y_last;
          advance_dest = FALSE;
        }

      y_last += y_frac;

      s = src;
      r = row;

      frac = 0;

      j  = width;
      while (j)
        {
          gint index = *s * 3;

          tot_frac = x_frac[frac++] * y_frac;

          /*  transform the color to RGB  */
          if (has_alpha)
            {
              if (s[ALPHA_I] & 0x80)
                {
                  r[RED]   += cmap[index++] * tot_frac;
                  r[GREEN] += cmap[index++] * tot_frac;
                  r[BLUE]  += cmap[index++] * tot_frac;
                  r[ALPHA] += tot_frac;
                }
              /* else the pixel contributes nothing and needs not to be added
               */
            }
          else
            {
              r[RED]   += cmap[index++] * tot_frac;
              r[GREEN] += cmap[index++] * tot_frac;
              r[BLUE]  += cmap[index++] * tot_frac;
            }

          /*  increment the destination  */
          if (x_sum + x_ratio <= (src_col + 1 + EPSILON))
            {
              r += bytes;
              x_sum += x_ratio;
              j--;
            }
          /* increment the source */
          else
            {
              s += srcPR->bytes;
              src_col++;
            }
        }

      if (advance_dest)
        {
          tot_frac = 1.0 / (x_ratio * y_ratio);

          /*  copy "row" to "dest"  */
          d = dest;
          r = row;

          j = width;
          while (j--)
            {
              if (has_alpha)
                {
                  /* unpremultiply */

                  gdouble alpha = r[bytes - 1];

                  if (alpha > EPSILON)
                    {
                      for (b = 0; b < (bytes - 1); b++)
                        d[b] = (guchar) ((r[b] / alpha) + 0.5);

                      d[bytes - 1] = (guchar) ((alpha * tot_frac * 255.0) + 0.5);
                    }
                  else
                    {
                      for (b = 0; b < bytes; b++)
                        d[b] = 0;
                    }
                }
              else
                {
                  for (b = 0; b < bytes; b++)
                    d[b] = (guchar) ((r[b] * tot_frac) + 0.5);
                }

              r += bytes;
              d += bytes;
            }

          dest += destwidth;

          /*  clear the "row" array  */
          memset (row, 0, sizeof (gdouble) * destwidth);

          i++;
        }
      else
        {
          pixel_region_get_row (srcPR,
                                srcPR->x,
                                srcPR->y + src_row * subsample,
                                orig_width * subsample,
                                src,
                                subsample);
        }
    }

  /*  free up temporary arrays  */
  g_free (row);
  g_free (x_frac);
  g_free (src);
}
示例#4
0
void
hue_saturation (HueSaturation *hs,
                PixelRegion   *srcPR,
                PixelRegion   *destPR)
{
    const guchar *src, *s;
    guchar       *dest, *d;
    const gint    hue_thresholds[]    = { 21, 64, 106, 149, 192, 234, 255 };
    gint          alpha;
    gint          w, h;
    gint          r, g, b;
    gint          hue;
    gint          hue_counter;
    gint          secondary_hue       = 0;
    gboolean      use_secondary_hue   = FALSE;
    gfloat        primary_intensity   = 0.0;
    gfloat        secondary_intensity = 0.0;
    gfloat        overlap_hue         = (hs->overlap / 100.0) * 21;

    /*  Set the transfer arrays  (for speed)  */
    h     = srcPR->h;
    src   = srcPR->data;
    dest  = destPR->data;
    alpha = pixel_region_has_alpha (srcPR);

    while (h--)
    {
        w = srcPR->w;
        s = src;
        d = dest;

        while (w--)
        {
            r = s[RED];
            g = s[GREEN];
            b = s[BLUE];

            gimp_rgb_to_hsl_int (&r, &g, &b);

            hue = (r + (128 / 6)) / 6;

            for (hue_counter = 0; hue_counter < 7; hue_counter++)
                if (r < hue_thresholds[hue_counter] + overlap_hue)
                {
                    gint  hue_threshold = hue_thresholds[hue_counter];

                    hue = hue_counter;

                    if (overlap_hue > 1.0 && r > hue_threshold - overlap_hue)
                    {
                        secondary_hue = hue_counter + 1;
                        use_secondary_hue = TRUE;
                        secondary_intensity =
                            (r - hue_threshold + overlap_hue) / (2.0 * overlap_hue);
                        primary_intensity = 1.0 - secondary_intensity;
                    }
                    else
                    {
                        use_secondary_hue = FALSE;
                    }
                    break;
                }

            if (hue >= 6)
            {
                hue = 0;
                use_secondary_hue = FALSE;
            }

            if (secondary_hue >= 6)
                secondary_hue = 0;

            if (use_secondary_hue)
            {
                /*  find nearest hue on the circle
                     *  between primary and secondary hue
                     */
                gint diff;

                diff = hs->hue_transfer[hue][r] - hs->hue_transfer[secondary_hue][r];
                if (diff < -127 || diff >= 128)
                    r = (gint) (hs->hue_transfer[hue][r] * primary_intensity +
                                (hs->hue_transfer[secondary_hue][r] + 255) * secondary_intensity) % 255;
                else
                    r = hs->hue_transfer[hue][r] * primary_intensity +
                        hs->hue_transfer[secondary_hue][r] * secondary_intensity;

                g = hs->saturation_transfer[hue][g] * primary_intensity +
                    hs->saturation_transfer[secondary_hue][g] * secondary_intensity;
                b = hs->lightness_transfer[hue][b] * primary_intensity +
                    hs->lightness_transfer[secondary_hue][b] * secondary_intensity;
            }
            else
            {
                r = hs->hue_transfer[hue][r];
                g = hs->saturation_transfer[hue][g];
                b = hs->lightness_transfer[hue][b];
            }

            gimp_hsl_to_rgb_int (&r, &g, &b);

            d[RED]   = r;
            d[GREEN] = g;
            d[BLUE]  = b;

            if (alpha)
                d[ALPHA] = s[ALPHA];

            s += srcPR->bytes;
            d += destPR->bytes;
        }

        src  += srcPR->rowstride;
        dest += destPR->rowstride;
    }
}
示例#5
0
/**
 * \brief Resize texture.
 * \param[in] in Original texture data.
 * \param[in] inwidth Original width of texture in pixels.
 * \param[in] inheight Original height of texture in pixels.
 * \param[in,out] out Resized texture data.
 * \param[in] outwidth New width of texture in pixels.
 * \param[in] outheight New height of texture in pixels.
 * \param[in] bytes Number of bytes per pixel.
 * \param[in] interpolation  See InterpolationType
 */
PUBLIC void TM_ResampleTexture( W8 *in, int inwidth, int inheight, W8 *out, int outwidth, int outheight, W16 bytes, InterpolationType interpolation )
{
    double *src[ 4 ];
    W8  *src_tmp;
    W8  *dest;
    double *row, *accum;
    int     b;
    int     width, height;
    int     orig_width, orig_height;
    double  y_rat;
    int     i;
    int     old_y = -4;
    int     new_y;
    int     x, y;


    if( interpolation == INTERPOLATION_NONE )
    {
        scale_region_no_resample( in, inwidth, inheight, out, outwidth, outheight, (char)bytes );
        return;
    }


    orig_width = inwidth;
    orig_height = inheight;

    width = outwidth;
    height = outheight;

#if 0

    Com_DPrintf( "scale_region: (%d x %d) -> (%d x %d)\n",
                 orig_width, orig_height, width, height );

#endif

    /*  find the ratios of old y to new y  */
    y_rat = (double) orig_height / (double) height;


    /*  the data pointers...  */
    for( i = 0 ; i < 4 ; ++i )
    {
        src[ i ] = (double *) MM_MALLOC( sizeof( double ) * width * bytes );
    }

    dest = (PW8) MM_MALLOC( width * bytes);

    src_tmp = (PW8) MM_MALLOC( orig_width * bytes );

    /* offset the row pointer by 2*bytes so the range of the array
    	is [-2*bytes] to [(orig_width + 2)*bytes] */
    row = (double *) MM_MALLOC( sizeof( double ) * (orig_width + 2 * 2) * bytes );
    row += bytes * 2;

    accum = (double *) MM_MALLOC( sizeof( double ) * width * bytes );


    /*  Scale the selected region  */

    for( y = 0 ; y < height ; y++ )
    {

        if( height < orig_height )
        {
            int          max;
            double       frac;
            const double inv_ratio = 1.0 / y_rat;

            if( y == 0 ) /* load the first row if this is the first time through */
            {
                get_scaled_row( &src[0], 0, width, row, src_tmp, in, orig_width, orig_height, bytes );
            }

            new_y = (int)(y * y_rat);
            frac = 1.0 - (y * y_rat - new_y);
            for( x = 0 ; x < width * bytes; ++x )
            {
                accum[x] = src[3][x] * frac;
            }

            max = (int) ((y + 1) * y_rat) - new_y - 1;

            get_scaled_row( &src[ 0 ], ++new_y, width, row, src_tmp, in, orig_width, orig_height, bytes  );

            while( max > 0 )
            {
                for( x = 0 ; x < width * bytes ; ++x )
                {
                    accum[x] += src[ 3 ][ x ];
                }

                get_scaled_row( &src[ 0 ], ++new_y, width, row, src_tmp, in, orig_width, orig_height, bytes );
                max--;
            }

            frac = (y + 1) * y_rat - ((int) ((y + 1) * y_rat));
            for( x = 0 ; x < width * bytes ; ++x )
            {
                accum[ x ] += frac * src[ 3 ][ x ];
                accum[ x ] *= inv_ratio;
            }
        }
        else if( height > orig_height )
        {
            double p0, p1, p2, p3;
            double dy;

            new_y = (int)floor( y * y_rat - 0.5 );

            while( old_y <= new_y )
            {
                /* get the necesary lines from the source image, scale them,
                	and put them into src[] */
                get_scaled_row( &src[ 0 ], old_y + 2, width, row, src_tmp, in, orig_width, orig_height, bytes );
                old_y++;
            }

            dy = (y * y_rat - 0.5) - new_y;

            p0 = cubic( dy, 1, 0, 0, 0 );
            p1 = cubic( dy, 0, 1, 0, 0 );
            p2 = cubic( dy, 0, 0, 1, 0 );
            p3 = cubic( dy, 0, 0, 0, 1 );

            for( x = 0 ; x < width * bytes ; ++x )
            {
                accum[ x ] = ( p0 * src[ 0 ][ x ] + p1 * src[ 1 ][ x ] +
                               p2 * src[ 2 ][ x ] + p3 * src[ 3 ][ x ] );
            }


        }
        else /* height == orig_height */
        {
            get_scaled_row( &src[ 0 ], y, width, row, src_tmp, in, orig_width, orig_height, bytes );
            memcpy( accum, src[ 3 ], sizeof( double ) * width * bytes );
        }

        if( pixel_region_has_alpha( bytes ) )
        {
            /* unmultiply the alpha */
            double  inv_alpha;
            double *p = accum;
            int     alpha = bytes - 1;
            int     result;
            W8		*d = dest;

            for( x = 0 ; x < width ; ++x )
            {
                if( p[ alpha ] > 0.001 )
                {
                    inv_alpha = 255.0 / p[ alpha ];
                    for( b = 0 ; b < alpha ; b++ )
                    {
                        result = (int)RINT( inv_alpha * p[ b ] );
                        if( result < 0 )
                        {
                            d[ b ] = 0;
                        }
                        else if( result > 255 )
                        {
                            d[ b ] = 255;
                        }
                        else
                        {
                            d[ b ] = result;
                        }
                    }
                    result = (int)RINT( p[ alpha ] );
                    if( result > 255 )
                    {
                        d[ alpha ] = 255;
                    }
                    else
                    {
                        d[ alpha ] = result;
                    }
                }
                else /* alpha <= 0 */
                {
                    for( b = 0 ; b <= alpha ; ++b )
                    {
                        d[ b ] = 0;
                    }
                }

                d += bytes;
                p += bytes;
            }
        }
        else
        {
            int w = width * bytes;

            for( x = 0 ; x < w ; ++x )
            {
                if( accum[ x ] < 0.0 )
                {
                    dest[ x ] = 0;
                }
                else if( accum[ x ] > 255.0 )
                {
                    dest[ x ] = 255;
                }
                else
                {
                    dest[ x ] = (W8)RINT( accum[ x ] );
                }
            }
        }
        pixel_region_set_row( out, bytes, y, width, dest );
    }

    /*  free up temporary arrays  */
    MM_FREE( accum );

    for( i = 0 ; i < 4 ; ++i )
    {
        MM_FREE( src[ i ] );
    }

    MM_FREE( src_tmp );
    MM_FREE( dest );

    row -= 2 * bytes;
    MM_FREE( row );
}