void AntiAliasOperation::executePixel(float output[4],
                                      int x, int y,
                                      void *data)
{
	MemoryBuffer *input_buffer = (MemoryBuffer *)data;
	const int buffer_width = input_buffer->getWidth(),
	          buffer_height = input_buffer->getHeight();
	if (y < 0 || y >= buffer_height || x < 0 || x >= buffer_width) {
		output[0] = 0.0f;
	}
	else {
		const float *buffer = input_buffer->getBuffer();
		const float *row_curr = &buffer[y * buffer_width];
		if (x == 0 || x == buffer_width - 1 ||
		    y == 0 || y == buffer_height - 1)
		{
			output[0] = row_curr[x];
			return;
		}
		const float *row_prev = &buffer[(y - 1) * buffer_width],
		            *row_next = &buffer[(y + 1) * buffer_width];
		float ninepix[9];
		if (extrapolate9(&ninepix[0], &ninepix[1], &ninepix[2],
		                 &ninepix[3], &ninepix[4], &ninepix[5],
		                 &ninepix[6], &ninepix[7], &ninepix[8],
		                 &row_prev[x - 1], &row_prev[x], &row_prev[x + 1],
		                 &row_curr[x - 1], &row_curr[x], &row_curr[x + 1],
		                 &row_next[x - 1], &row_next[x], &row_next[x + 1]))
		{
			/* Some rounding magic to so make weighting correct with the
			 * original coefficients.
			 */
			unsigned char result = ((3 * ninepix[0] + 5 * ninepix[1] + 3 * ninepix[2] +
			                         5 * ninepix[3] + 6 * ninepix[4] + 5 * ninepix[5] +
			                         3 * ninepix[6] + 5 * ninepix[7] + 3 * ninepix[8]) * 255.0f +
			                        19.0f) / 38.0f;
			output[0] = result / 255.0f;
		}
		else {
			output[0] = row_curr[x];
		}
	}
}
Ejemplo n.º 2
0
static gboolean
process (GeglOperation       *operation,
         GeglBuffer          *input,
         GeglBuffer          *output,
         const GeglRectangle *roi,
         gint                 level)
{
    gint          components;
    gint          col, c;
    gfloat       *rowbefore;
    gfloat       *rowthis;
    gfloat       *rowafter;
    gfloat       *dest;
    gfloat       *ninepix;
    gboolean      has_alpha;
    guint         alpha;
    const Babl   *format = gegl_operation_get_format (operation, "input");

    /* The rectangle of the current row we are working on */
    GeglRectangle rowrect;

    /* The rectangle of the sample we are going to take for the
     * next line (this does include the interpolation distance!) */
    GeglRectangle rownext_bufrect;

    components = babl_format_get_n_components (format);
    has_alpha  = babl_format_has_alpha (format);
    alpha      = components - 1;

    /* The original algorithm that appeared in GIMP did a manual clamping
     * of samples outside the input rectangle, by always allocating a
     * buffer which is 1-pixel wider than necessary, and then filling the
     * edges of the buffer with repetitions of the edges.
     * We don't need this complexity here thanks to the CLAMP abyss policy
     * which is implemented by GEGL. We still allocate buffers which are
     * larger, but we let GEGL fill the edges with the clamped values.
     */

    rowbefore  = g_new (gfloat, (roi->width + 2) * components);
    rowthis    = g_new (gfloat, (roi->width + 2) * components);
    rowafter   = g_new (gfloat, (roi->width + 2) * components);
    dest       = g_new (gfloat, roi->width * components);
    ninepix    = g_new (gfloat, 9 * components);

    gegl_rectangle_set (&rowrect, roi->x, roi->y, roi->width, 1);
    gegl_rectangle_set (&rownext_bufrect, roi->x - 1, roi->y - 1, roi->width + 2, 1);

    gegl_buffer_get (input, &rownext_bufrect, 1.0, format,
                     rowbefore, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP);
    ++rownext_bufrect.y;

    gegl_buffer_get (input, &rownext_bufrect, 1.0, format,
                     rowthis, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP);
    ++rownext_bufrect.y;

    gegl_buffer_get (input, &rownext_bufrect, 1.0, format,
                     rowafter, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP);
    ++rownext_bufrect.y;

    for (rowrect.y = roi->y; rowrect.y < (roi->y + roi->height); ++rowrect.y)
    {
        gfloat *tmp;

        /* this macro returns the current pixel if it has some opacity. Otherwise
         * it returns the center pixel of the current 3x3 area. */
#define USE_IF_ALPHA(p) (((!has_alpha) || *((p)+alpha)) ? (p) : &rowthis[(col+1) * components])

        for (col = 0; col < roi->width; ++col)
        {
            /* do 9x extrapolation pass */
            if (((!has_alpha) || (rowthis[(col + 1) * components + alpha] > 0)) &&
                    extrapolate9 (components,
                                  &ninepix[0 * components],
                                  &ninepix[1 * components],
                                  &ninepix[2 * components],
                                  &ninepix[3 * components],
                                  &ninepix[4 * components],
                                  &ninepix[5 * components],
                                  &ninepix[6 * components],
                                  &ninepix[7 * components],
                                  &ninepix[8 * components],
                                  USE_IF_ALPHA (&rowbefore[(col + 0) * components]),
                                  USE_IF_ALPHA (&rowbefore[(col + 1) * components]),
                                  USE_IF_ALPHA (&rowbefore[(col + 2) * components]),
                                  USE_IF_ALPHA (&rowthis  [(col + 0) * components]),
                                  &rowthis  [(col + 1) * components],
                                  USE_IF_ALPHA (&rowthis  [(col + 2) * components]),
                                  USE_IF_ALPHA (&rowafter [(col + 0) * components]),
                                  USE_IF_ALPHA (&rowafter [(col + 1) * components]),
                                  USE_IF_ALPHA (&rowafter [(col + 2) * components])
                                 ))
            {
                /* subsample results and put into dest */
                for (c = 0; c < components; ++c)
                {
#define NINEPIX(index, c) ninepix[(index) * components + (c)]
                    dest[(col * components) + c] =
                        (3 * NINEPIX(0, c) + 5 * NINEPIX(1, c) + 3 * NINEPIX(2, c) +
                         5 * NINEPIX(3, c) + 6 * NINEPIX(4, c) + 5 * NINEPIX(5, c) +
                         3 * NINEPIX(6, c) + 5 * NINEPIX(7, c) + 3 * NINEPIX(8, c)
                         /* The GIMP implementation added 19 (out of 255) here before
                          * normalizing (dividing by 38), which is equivalent to a
                          * call to "ceil". We don't need this since we are working
                          * with floating point numbers... */
                        ) / 38;
#undef NINEPIX
                }
            }
            else
            {
                memcpy (&dest[col * components], &rowthis[(col + 1) * components], components * sizeof(gfloat));
            }
        }

#undef USE_IF_ALPHA

        /* write result row to dest */
        gegl_buffer_set (output, &rowrect, 0, format, &dest[0], GEGL_AUTO_ROWSTRIDE);

        /* rotate pointers */
        tmp       = rowbefore;
        rowbefore = rowthis;
        rowthis   = rowafter;
        rowafter  = tmp;

        /* populate new after-row */
        gegl_buffer_get (input, &rownext_bufrect, 1.0, format,
                         rowafter, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP);
        ++rownext_bufrect.y;
    }

    g_free (rowbefore);
    g_free (rowthis);
    g_free (rowafter);
    g_free (dest);
    g_free (ninepix);

    return  TRUE;
}