Exemple #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 ];
    }
}
Exemple #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);
}
Exemple #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);
}
Exemple #4
0
/*
non-interpolating scale_region.
 */
PRIVATE void
scale_region_no_resample( W8 *in, int inwidth, int inheight,
                          W8 *out, int outwidth, int outheight, char bytes )
{
    int   *x_src_offsets;
    int   *y_src_offsets;
    W8 *src;
    W8 *dest;
    int    width, height, orig_width, orig_height;
    int    last_src_y;
    int    row_bytes;
    int    x, y, b;


    orig_width = inwidth;
    orig_height = inheight;

    width = outwidth;
    height = outheight;


    /*  the data pointers...  */
    x_src_offsets = (int *) MM_MALLOC( sizeof( int ) * width * bytes );
    y_src_offsets = (int *) MM_MALLOC( sizeof( int ) * height );
    src  = (unsigned char *) MM_MALLOC( orig_width * bytes);
    dest = (unsigned char *) MM_MALLOC( width * bytes);

    /*  pre-calc the scale tables  */
    for( b = 0; b < bytes; b++ )
    {
        for( x = 0; x < width; x++ )
        {
            x_src_offsets[ b + x * bytes ] =
                b + bytes * ((x * orig_width + orig_width / 2) / width);
        }
    }

    for( y = 0; y < height; y++ )
    {
        y_src_offsets[ y ] = (y * orig_height + orig_height / 2) / height;
    }

    /*  do the scaling  */
    row_bytes = width * bytes;
    last_src_y = -1;
    for( y = 0; y < height; y++ )
    {
        /* if the source of this line was the same as the source
        *  of the last line, there's no point in re-rescaling.
        */
        if( y_src_offsets[ y ] != last_src_y )
        {
            pixel_region_get_row( in, y_src_offsets[ y ], orig_width, src, bytes );
            //pixel_region_get_row( srcPR, 0, y_src_offsets[y], orig_width, src, 1 );
            for( x = 0 ; x < row_bytes ; x++ )
            {
                dest[ x ] = src[ x_src_offsets[ x ] ];
            }
            last_src_y = y_src_offsets[ y ];
        }

        pixel_region_set_row( out, bytes, y, width, dest );
    }

    MM_FREE( x_src_offsets );
    MM_FREE( y_src_offsets );
    MM_FREE( src );
    MM_FREE( dest );
}
Exemple #5
0
gboolean
gimp_image_crop_auto_shrink (GimpImage *image,
                             gint       x1,
                             gint       y1,
                             gint       x2,
                             gint       y2,
                             gboolean   active_drawable_only,
                             gint      *shrunk_x1,
                             gint      *shrunk_y1,
                             gint      *shrunk_x2,
                             gint      *shrunk_y2)
{
  GimpDrawable    *active_drawable = NULL;
  GimpPickable    *pickable;
  ColorsEqualFunc  colors_equal_func;
  guchar           bgcolor[MAX_CHANNELS] = { 0, 0, 0, 0 };
  gboolean         has_alpha;
  PixelRegion      PR;
  guchar          *buffer = NULL;
  gint             width, height;
  GimpImageType    type;
  gint             bytes;
  gint             x, y, abort;
  gboolean         retval = FALSE;

  g_return_val_if_fail (image != NULL, FALSE);
  g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE);
  g_return_val_if_fail (shrunk_x1 != NULL, FALSE);
  g_return_val_if_fail (shrunk_y1 != NULL, FALSE);
  g_return_val_if_fail (shrunk_x2 != NULL, FALSE);
  g_return_val_if_fail (shrunk_y2 != NULL, FALSE);

  gimp_set_busy (image->gimp);

  /* You should always keep in mind that crop->tx2 and crop->ty2 are
     the NOT the coordinates of the bottomright corner of the area to
     be cropped. They point at the pixel located one to the right and
     one to the bottom.
   */

  if (active_drawable_only)
    {
      active_drawable = gimp_image_get_active_drawable (image);

      if (! active_drawable)
        goto FINISH;

      pickable = GIMP_PICKABLE (active_drawable);
    }
  else
    {
      pickable = GIMP_PICKABLE (image->projection);
   }

  gimp_pickable_flush (pickable);

  type      = gimp_pickable_get_image_type (pickable);
  bytes     = GIMP_IMAGE_TYPE_BYTES (type);
  has_alpha = GIMP_IMAGE_TYPE_HAS_ALPHA (type);

  switch (gimp_image_crop_guess_bgcolor (pickable,
                                         bytes, has_alpha, bgcolor,
                                         x1, x2-1, y1, y2-1))
    {
    case AUTO_CROP_ALPHA:
      colors_equal_func = (ColorsEqualFunc) gimp_image_crop_colors_alpha;
      break;
    case AUTO_CROP_COLOR:
      colors_equal_func = (ColorsEqualFunc) gimp_image_crop_colors_equal;
      break;
    default:
      goto FINISH;
      break;
    }

  width  = x2 - x1;
  height = y2 - y1;

  pixel_region_init (&PR, gimp_pickable_get_tiles (pickable),
                     x1, y1, width, height, FALSE);

  /* The following could be optimized further by processing
   * the smaller side first instead of defaulting to width    --Sven
   */

  buffer = g_malloc ((width > height ? width : height) * bytes);

  /* Check how many of the top lines are uniform/transparent. */
  abort = FALSE;
  for (y = y1; y < y2 && !abort; y++)
    {
      pixel_region_get_row (&PR, x1, y, width, buffer, 1);
      for (x = 0; x < width && !abort; x++)
        abort = !(colors_equal_func) (bgcolor, buffer + x * bytes, bytes);
    }
  if (y == y2 && !abort)
    goto FINISH;
  y1 = y - 1;

  /* Check how many of the bottom lines are uniform/transparent. */
  abort = FALSE;
  for (y = y2; y > y1 && !abort; y--)
    {
      pixel_region_get_row (&PR, x1, y-1 , width, buffer, 1);
      for (x = 0; x < width && !abort; x++)
        abort = !(colors_equal_func) (bgcolor, buffer + x * bytes, bytes);
    }
  y2 = y + 1;

  /* compute a new height for the next operations */
  height = y2 - y1;

  /* Check how many of the left lines are uniform/transparent. */
  abort = FALSE;
  for (x = x1; x < x2 && !abort; x++)
    {
      pixel_region_get_col (&PR, x, y1, height, buffer, 1);
      for (y = 0; y < height && !abort; y++)
        abort = !(colors_equal_func) (bgcolor, buffer + y * bytes, bytes);
    }
  x1 = x - 1;

  /* Check how many of the right lines are uniform/transparent. */
  abort = FALSE;
  for (x = x2; x > x1 && !abort; x--)
    {
      pixel_region_get_col (&PR, x-1, y1, height, buffer, 1);
      for (y = 0; y < height && !abort; y++)
        abort = !(colors_equal_func) (bgcolor, buffer + y * bytes, bytes);
    }
  x2 = x + 1;

  *shrunk_x1 = x1;
  *shrunk_y1 = y1;
  *shrunk_x2 = x2;
  *shrunk_y2 = y2;

  retval = TRUE;

 FINISH:
  g_free (buffer);
  gimp_unset_busy (image->gimp);

  return retval;
}