pixelize.c 21.4 KB
Newer Older
Andy Gill's avatar
Andy Gill committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/* This file is an image processing operation for GEGL
 *
 * GEGL is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * GEGL is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
 *
 * Copyright 2006 Øyvind Kolås <pippin@gimp.org>
17
 * Copyright 2013 Téo Mazars   <teo.mazars@ensimag.fr>
Andy Gill's avatar
Andy Gill committed
18 19 20 21 22 23
 */

#include "config.h"
#include <glib/gi18n-lib.h>
#include <math.h>

24 25
#ifdef GEGL_PROPERTIES

26 27 28 29 30
enum_start (gegl_pixelize_norm)
  enum_value (GEGL_PIXELIZE_NORM_MANHATTAN, "Diamond")
  enum_value (GEGL_PIXELIZE_NORM_EUCLIDEAN, "Round")
  enum_value (GEGL_PIXELIZE_NORM_INFINITY,  "Square")
enum_end (GeglPixelizeNorm)
31

32 33 34
property_enum   (norm, _("Shape"),
    GeglPixelizeNorm, gegl_pixelize_norm, GEGL_PIXELIZE_NORM_INFINITY)
    description (_("The shape of pixels"))
35

36 37 38 39 40 41 42
property_int    (size_x, _("Block width"), 16)
    description (_("Width of blocks in pixels"))
    value_range (1, G_MAXINT)
    ui_range    (1, 2048)
    ui_gamma    (1.5)
    ui_meta     ("unit", "pixel-distance")
    ui_meta     ("axis", "x")
43

44 45 46 47 48 49 50
property_int    (size_y, _("Block height"), 16)
    description (_("Height of blocks in pixels"))
    value_range (1, G_MAXINT)
    ui_range    (1, 2048)
    ui_gamma    (1.5)
    ui_meta     ("unit", "pixel-distance")
    ui_meta     ("axis", "y")
51

52
property_double (ratio_x, _("Size ratio X"), 1.0)
53 54 55
    description (_("Horizontal size ratio of a pixel inside each block"))
    value_range (0.0, 1.0)
    ui_meta     ("axis", "x")
56

57
property_double (ratio_y, _("Size ratio Y"), 1.0)
58 59 60
    description (_("Vertical size ratio of a pixel inside each block"))
    value_range (0.0, 1.0)
    ui_meta     ("axis", "y")
61

62 63 64
property_color  (background, _("Background color"), "white")
    description (_("Color used to fill the background"))
    ui_meta     ("role", "color-secondary")
65

Andy Gill's avatar
Andy Gill committed
66 67
#else

68 69
#define GEGL_OP_AREA_FILTER
#define GEGL_OP_C_FILE "pixelize.c"
Andy Gill's avatar
Andy Gill committed
70

71
#include "gegl-op.h"
Andy Gill's avatar
Andy Gill committed
72

73 74 75
#define CHUNK_SIZE           (1024)
#define ALLOC_THRESHOLD_SIZE (64)
#define SQR(x)               ((x)*(x))
Andy Gill's avatar
Andy Gill committed
76

77 78
static void
prepare (GeglOperation *operation)
Andy Gill's avatar
Andy Gill committed
79
{
80
  GeglProperties              *o;
Andy Gill's avatar
Andy Gill committed
81 82 83
  GeglOperationAreaFilter *op_area;

  op_area = GEGL_OPERATION_AREA_FILTER (operation);
84
  o       = GEGL_PROPERTIES (operation);
Andy Gill's avatar
Andy Gill committed
85 86

  op_area->left   =
87
  op_area->right  = o->size_x;
Andy Gill's avatar
Andy Gill committed
88
  op_area->top    =
89
  op_area->bottom = o->size_y;
Andy Gill's avatar
Andy Gill committed
90

91 92
  gegl_operation_set_format (operation, "input",  babl_format ("RaGaBaA float"));
  gegl_operation_set_format (operation, "output", babl_format ("RaGaBaA float"));
Andy Gill's avatar
Andy Gill committed
93 94
}

95 96 97 98 99 100 101 102 103 104 105 106 107 108
static GeglRectangle
get_bounding_box (GeglOperation *self)
{
  GeglRectangle  result = { 0, 0, 0, 0 };
  GeglRectangle *in_rect;

  in_rect = gegl_operation_source_get_bounding_box (self, "input");
  if (in_rect)
    {
      result = *in_rect;
    }

  return result;
}
109

Andy Gill's avatar
Andy Gill committed
110
static void
111 112 113
mean_rectangle_noalloc (GeglBuffer    *input,
                        GeglRectangle *rect,
                        GeglColor     *color)
Andy Gill's avatar
Andy Gill committed
114
{
115 116 117 118 119 120 121 122
  GeglBufferIterator *gi;
  gfloat              col[] = {0.0, 0.0, 0.0, 0.0};
  gint                c;

  gi = gegl_buffer_iterator_new (input, rect, 0, babl_format ("RaGaBaA float"),
                                 GEGL_BUFFER_READ, GEGL_ABYSS_CLAMP);

  while (gegl_buffer_iterator_next (gi))
Andy Gill's avatar
Andy Gill committed
123
    {
124
      gint    k;
125 126 127
      gfloat *data = (gfloat*) gi->data[0];

      for (k = 0; k < gi->length; k++)
Andy Gill's avatar
Andy Gill committed
128
        {
129 130 131 132
          for (c = 0; c < 4; c++)
            col[c] += data[c];

          data += 4;
Andy Gill's avatar
Andy Gill committed
133 134
        }
    }
135 136 137 138 139

  for (c = 0; c < 4; c++)
    col[c] /= rect->width * rect->height;

  gegl_color_set_pixel (color, babl_format ("RaGaBaA float"), col);
Andy Gill's avatar
Andy Gill committed
140 141
}

142
static void
143 144 145 146
mean_rectangle (gfloat        *input,
                GeglRectangle *rect,
                gint           rowstride,
                gfloat        *color)
Andy Gill's avatar
Andy Gill committed
147
{
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
  gint c, x, y;

  for (c = 0; c < 4; c++)
    color[c] = 0;

  for (y = rect->y; y < rect->y + rect->height; y++)
    for (x = rect->x; x < rect->x + rect->width; x++)
      for (c = 0; c < 4; c++)
        color[c] += input [4 * (y * rowstride + x) + c];

  for (c = 0; c < 4; c++)
    color[c] /= rect->width * rect->height;
}

static void
163 164 165 166 167 168
set_rectangle (gfloat          *output,
               GeglRectangle   *rect,
               GeglRectangle   *rect_shape,
               gint             rowstride,
               gfloat          *color,
               GeglPixelizeNorm norm)
169 170
{
  gint c, x, y;
171 172
  gfloat center_x, center_y;
  GeglRectangle rect2;
173

174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
  gfloat shape_area = rect_shape->width * rect_shape->height;

  center_x = rect_shape->x + rect_shape->width / 2.0f;
  center_y = rect_shape->y + rect_shape->height / 2.0f;

  gegl_rectangle_intersect (&rect2, rect, rect_shape);

  switch (norm)
    {
    case (GEGL_PIXELIZE_NORM_INFINITY):

      for (y = rect2.y; y < rect2.y + rect2.height; y++)
        for (x = rect2.x; x < rect2.x + rect2.width; x++)
          for (c = 0; c < 4; c++)
            output [4 * (y * rowstride + x) + c] = color[c];
      break;

    case (GEGL_PIXELIZE_NORM_EUCLIDEAN):

      for (y = rect->y; y < rect->y + rect->height; y++)
        for (x = rect->x; x < rect->x + rect->width; x++)
          if (SQR ((x - center_x) / (gfloat) rect_shape->width) +
              SQR ((y - center_y) / (gfloat) rect_shape->height) <= 1.0f)
            for (c = 0; c < 4; c++)
              output [4 * (y * rowstride + x) + c] = color[c];
      break;

    case (GEGL_PIXELIZE_NORM_MANHATTAN):

      for (y = rect->y; y < rect->y + rect->height; y++)
        for (x = rect->x; x < rect->x + rect->width; x++)
          if (fabsf (center_x - x) * rect_shape->height +
              fabsf (center_y - y) * rect_shape->width < shape_area)
            for (c = 0; c < 4; c++)
              output [4 * (y * rowstride + x) + c] = color[c];

      break;
    }
212 213
}

214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
static void
set_rectangle_noalloc (GeglBuffer      *output,
                       GeglRectangle   *rect,
                       GeglRectangle   *rect_shape,
                       GeglColor       *color,
                       GeglPixelizeNorm norm)
{
  if (norm == GEGL_PIXELIZE_NORM_INFINITY)
    {
      GeglRectangle rect2;
      gegl_rectangle_intersect (&rect2, rect, rect_shape);
      gegl_buffer_set_color (output, &rect2, color);
    }
  else
    {
      GeglBufferIterator *gi;
      gint                c, x, y;
      gfloat              col[4];
      gfloat              center_x, center_y;
      gfloat              shape_area = rect_shape->width * rect_shape->height;

      center_x = rect_shape->x + rect_shape->width / 2.0f;
      center_y = rect_shape->y + rect_shape->height / 2.0f;

      gegl_color_get_pixel (color, babl_format ("RaGaBaA float"), col);

      gi = gegl_buffer_iterator_new (output, rect, 0, babl_format ("RaGaBaA float"),
                                     GEGL_BUFFER_WRITE, GEGL_ABYSS_CLAMP);

      while (gegl_buffer_iterator_next (gi))
        {
          gfloat       *data = (gfloat*) gi->data[0];
          GeglRectangle roi = gi->roi[0];

          switch (norm)
            {
            case (GEGL_PIXELIZE_NORM_EUCLIDEAN):

              for (y = 0; y < roi.height; y++)
                for (x = 0; x < roi.width; x++)
                  if (SQR ((x + roi.x - center_x) / (gfloat) rect_shape->width) +
                      SQR ((y + roi.y - center_y) / (gfloat) rect_shape->height) <= 1.0f)
                    for (c = 0; c < 4; c++)
                      data [4 * (y * roi.width + x) + c] = col[c];
              break;

            case (GEGL_PIXELIZE_NORM_MANHATTAN):

              for (y = 0; y < roi.height; y++)
                for (x = 0; x < roi.width; x++)
                  if (fabsf (x + roi.x - center_x) * rect_shape->height +
                      fabsf (y + roi.y - center_y) * rect_shape->width
                      < shape_area)
                    for (c = 0; c < 4; c++)
                      data [4 * (y * roi.width + x) + c] = col[c];
              break;

            case (GEGL_PIXELIZE_NORM_INFINITY):
              break;
            }
        }
    }
}
277

278 279 280 281 282 283 284
static int
block_index (int pos,
             int size)
{
  return pos < 0 ? ((pos + 1) / size - 1) : (pos / size);
}

285 286 287 288 289
static void
pixelize_noalloc (GeglBuffer          *input,
                  GeglBuffer          *output,
                  const GeglRectangle *roi,
                  const GeglRectangle *whole_region,
290
                  GeglProperties          *o)
291
{
292 293
  gint start_x = block_index (roi->x, o->size_x) * o->size_x;
  gint start_y = block_index (roi->y, o->size_y) * o->size_y;
294
  gint x, y;
295
  gint off_shape_x, off_shape_y;
296 297 298

  GeglColor *color = gegl_color_new ("white");

299 300 301 302 303 304 305 306 307 308
  GeglRectangle rect_shape;

  rect_shape.width  = ceilf (o->size_x * (gfloat)o->ratio_x);
  rect_shape.height = ceilf (o->size_y * (gfloat)o->ratio_y);

  off_shape_x = floorf ((o->size_x - (gfloat)o->ratio_x * o->size_x) / 2.0f);
  off_shape_y = floorf ((o->size_y - (gfloat)o->ratio_y * o->size_y) / 2.0f);

  for (y = start_y; y < roi->y + roi->height; y += o->size_y)
    for (x = start_x; x < roi->x + roi->width; x += o->size_x)
309
      {
310
        GeglRectangle rect = {x, y, o->size_x, o->size_y};
Andy Gill's avatar
Andy Gill committed
311

312 313 314 315 316 317 318 319 320
        gegl_rectangle_intersect (&rect, whole_region, &rect);

        if (rect.width < 1 || rect.height < 1)
          continue;

        mean_rectangle_noalloc (input, &rect, color);

        gegl_rectangle_intersect (&rect, roi, &rect);

321 322 323 324
        rect_shape.x = x + off_shape_x;
        rect_shape.y = y + off_shape_y;

        set_rectangle_noalloc (output, &rect, &rect_shape, color, o->norm);
325 326 327 328 329 330 331 332 333 334 335
      }

  g_object_unref (color);
}

static void
pixelize (gfloat              *input,
          gfloat              *output,
          const GeglRectangle *roi,
          const GeglRectangle *extended_roi,
          const GeglRectangle *whole_region,
336
          GeglProperties          *o)
337
{
338 339
  gint          start_x = block_index (roi->x, o->size_x) * o->size_x;
  gint          start_y = block_index (roi->y, o->size_y) * o->size_y;
340 341 342 343 344 345 346 347 348 349
  gint          x, y;
  gint          off_shape_x, off_shape_y;
  gfloat        color[4];
  GeglRectangle rect_shape;

  rect_shape.width  = ceilf (o->size_x * (gfloat)o->ratio_x);
  rect_shape.height = ceilf (o->size_y * (gfloat)o->ratio_y);

  off_shape_x = floorf ((o->size_x - (gfloat)o->ratio_x * o->size_x) / 2.0f);
  off_shape_y = floorf ((o->size_y - (gfloat)o->ratio_y * o->size_y) / 2.0f);
350

351 352
  for (y = start_y; y < roi->y + roi->height; y += o->size_y)
    for (x = start_x; x < roi->x + roi->width; x += o->size_x)
353
      {
354
        GeglRectangle rect = {x, y, o->size_x, o->size_y};
355 356
        GeglRectangle rect2;

357 358 359
        rect_shape.x = x + off_shape_x;
        rect_shape.y = y + off_shape_y;

360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
        gegl_rectangle_intersect (&rect, whole_region, &rect);

        if (rect.width < 1 || rect.height < 1)
          continue;

        rect2.x = rect.x - extended_roi->x;
        rect2.y = rect.y - extended_roi->y;
        rect2.width  = rect.width;
        rect2.height = rect.height;

        mean_rectangle (input, &rect2, extended_roi->width, color);

        gegl_rectangle_intersect (&rect, roi, &rect);

        rect2.x = rect.x - roi->x;
        rect2.y = rect.y - roi->y;
        rect2.width  = rect.width;
        rect2.height = rect.height;

379 380 381 382 383
        rect_shape.x -= roi->x;
        rect_shape.y -= roi->y;

        set_rectangle (output, &rect2, &rect_shape,
                       roi->width, color, o->norm);
384
      }
Andy Gill's avatar
Andy Gill committed
385 386
}

387 388 389
#include "opencl/gegl-cl.h"
#include "buffer/gegl-buffer-cl-iterator.h"

Victor Oliveira's avatar
Victor Oliveira committed
390
#include "opencl/pixelize.cl.h"
391

392
static GeglClRunData *cl_data = NULL;
393

Victor Oliveira's avatar
Victor Oliveira committed
394
static gboolean
395 396 397 398 399 400 401 402 403 404 405 406
cl_pixelize (cl_mem               in_tex,
             cl_mem               aux_tex,
             cl_mem               out_tex,
             const GeglRectangle *src_rect,
             const GeglRectangle *roi,
             gint                 xsize,
             gint                 ysize,
             gfloat               xratio,
             gfloat               yratio,
             gfloat               bg_color[4],
             gint                 norm,
             GeglRectangle       *image_extent)
407 408 409 410
{
  cl_int cl_err = 0;
  const size_t gbl_size[2]= {roi->width, roi->height};

411 412 413 414 415 416 417
  gint cx0 = block_index (roi->x, xsize);
  gint cy0 = block_index (roi->y, ysize);
  gint block_count_x = block_index (roi->x + roi->width  + xsize - 1, xsize) - cx0;
  gint block_count_y = block_index (roi->y + roi->height + ysize - 1, ysize) - cy0;
  cl_int4 bbox = {{ image_extent->x, image_extent->y,
                    image_extent->x + image_extent->width,
                    image_extent->y + image_extent->height }};
418

419 420
  cl_int line_width = roi->width + 2 * xsize;

421
  size_t gbl_size_tmp[2] = {block_count_x, block_count_y};
422 423 424

  if (!cl_data)
  {
425
    const char *kernel_name[] = {"calc_block_color", "kernel_pixelize", NULL};
Victor Oliveira's avatar
Victor Oliveira committed
426
    cl_data = gegl_cl_compile_and_build (pixelize_cl_source, kernel_name);
427 428 429 430
  }

  if (!cl_data) return 1;

431 432 433 434 435 436 437
  cl_err = gegl_cl_set_kernel_args (cl_data->kernel[0],
                                    sizeof(cl_mem), (void*)&in_tex,
                                    sizeof(cl_mem), (void*)&aux_tex,
                                    sizeof(cl_int), (void*)&xsize,
                                    sizeof(cl_int), (void*)&ysize,
                                    sizeof(cl_int), (void*)&roi->x,
                                    sizeof(cl_int), (void*)&roi->y,
438
                                    sizeof(cl_int4), &bbox,
439 440 441
                                    sizeof(cl_int), (void*)&line_width,
                                    sizeof(cl_int), (void*)&block_count_x,
                                    NULL);
Victor Oliveira's avatar
Victor Oliveira committed
442
  CL_CHECK;
443

444
  cl_err = gegl_clEnqueueNDRangeKernel (gegl_cl_get_command_queue (),
445 446 447
                                        cl_data->kernel[0], 2,
                                        NULL, gbl_size_tmp, NULL,
                                        0, NULL, NULL);
Victor Oliveira's avatar
Victor Oliveira committed
448 449
  CL_CHECK;

450
  cl_err = gegl_cl_set_kernel_args (cl_data->kernel[1],
451 452 453 454 455 456 457 458 459 460 461
                                    sizeof(cl_mem),   (void*)&aux_tex,
                                    sizeof(cl_mem),   (void*)&out_tex,
                                    sizeof(cl_int),   (void*)&xsize,
                                    sizeof(cl_int),   (void*)&ysize,
                                    sizeof(cl_float), (void*)&xratio,
                                    sizeof(cl_float), (void*)&yratio,
                                    sizeof(cl_int),   (void*)&roi->x,
                                    sizeof(cl_int),   (void*)&roi->y,
                                    sizeof(cl_float4),(void*)bg_color,
                                    sizeof(cl_int),   (void*)&norm,
                                    sizeof(cl_int),   (void*)&block_count_x,
462
                                    NULL);
463
  CL_CHECK;
464 465

  cl_err = gegl_clEnqueueNDRangeKernel (gegl_cl_get_command_queue (),
466 467 468
                                        cl_data->kernel[1], 2,
                                        NULL, gbl_size, NULL,
                                        0, NULL, NULL);
Victor Oliveira's avatar
Victor Oliveira committed
469 470 471 472 473 474
  CL_CHECK;

  return FALSE;

error:
  return TRUE;
475 476 477 478 479 480 481 482
}

static gboolean
cl_process (GeglOperation       *operation,
            GeglBuffer          *input,
            GeglBuffer          *output,
            const GeglRectangle *roi)
{
483 484
  const Babl *in_format  = babl_format ("RaGaBaA float");
  const Babl *out_format = babl_format ("RaGaBaA float");
485 486 487
  gint   err;
  gfloat bg_color[4];
  gint   norm;
488 489

  GeglOperationAreaFilter *op_area = GEGL_OPERATION_AREA_FILTER (operation);
490
  GeglProperties *o = GEGL_PROPERTIES (operation);
491
  GeglRectangle *image_extent;
492

493 494 495 496 497 498 499 500 501 502 503 504 505 506
  GeglBufferClIterator *i = gegl_buffer_cl_iterator_new   (output,
                                                           roi,
                                                           out_format,
                                                           GEGL_CL_BUFFER_WRITE);

  gint read = gegl_buffer_cl_iterator_add_2 (i,
                                             input,
                                             roi,
                                             in_format,
                                             GEGL_CL_BUFFER_READ,
                                             op_area->left,
                                             op_area->right,
                                             op_area->top,
                                             op_area->bottom,
507
                                             GEGL_ABYSS_CLAMP);
508

509 510 511 512 513 514 515 516
  gint aux = gegl_buffer_cl_iterator_add_aux (i,
                                              roi,
                                              in_format,
                                              op_area->left,
                                              op_area->right,
                                              op_area->top,
                                              op_area->bottom);

517

518 519 520 521 522 523 524 525
  gegl_color_get_pixel (o->background, babl_format ("RaGaBaA float"), bg_color);

  norm = 0;
  norm = o->norm == GEGL_PIXELIZE_NORM_EUCLIDEAN ? 1 : norm;
  norm = o->norm == GEGL_PIXELIZE_NORM_INFINITY  ? 2 : norm;

  image_extent = gegl_operation_source_get_bounding_box (operation, "input");

526
  while (gegl_buffer_cl_iterator_next (i, &err) && !err)
527
    {
528
      err = cl_pixelize(i->tex[read],
529 530 531 532 533
                        i->tex[aux],
                        i->tex[0],
                        &i->roi[read],
                        &i->roi[0],
                        o->size_x,
534 535 536 537 538 539
                        o->size_y,
                        o->ratio_x,
                        o->ratio_y,
                        bg_color,
                        norm,
                        image_extent);
540

541 542 543 544 545
      if (err)
        {
          gegl_buffer_cl_iterator_stop (i);
          break;
        }
546
    }
547

548
  return !err;
549 550
}

Andy Gill's avatar
Andy Gill committed
551 552 553 554
static gboolean
process (GeglOperation       *operation,
         GeglBuffer          *input,
         GeglBuffer          *output,
555 556
         const GeglRectangle *roi,
         gint                 level)
Andy Gill's avatar
Andy Gill committed
557
{
558 559
  GeglRectangle            src_rect;
  GeglRectangle           *whole_region;
560
  GeglProperties          *o = GEGL_PROPERTIES (operation);
Andy Gill's avatar
Andy Gill committed
561 562 563
  GeglOperationAreaFilter *op_area;

  op_area = GEGL_OPERATION_AREA_FILTER (operation);
564 565

  whole_region = gegl_operation_source_get_bounding_box (operation, "input");
566

567
  if (gegl_operation_use_opencl (operation))
568 569 570
    if (cl_process (operation, input, output, roi))
      return TRUE;

571 572
  if (o->size_x * o->size_y < SQR (ALLOC_THRESHOLD_SIZE))
    {
573
      gfloat  background_color[4];
574 575 576 577 578 579
      gfloat *input_buf  = g_new (gfloat,
                                  (CHUNK_SIZE + o->size_x * 2) *
                                  (CHUNK_SIZE + o->size_y * 2) * 4);
      gfloat *output_buf = g_new (gfloat, SQR (CHUNK_SIZE) * 4);
      gint    i, j;

580 581 582
      gegl_color_get_pixel (o->background, babl_format("RaGaBaA float"),
                            background_color);

583 584 585 586
      for (j = 0; (j-1) * CHUNK_SIZE < roi->height; j++)
        for (i = 0; (i-1) * CHUNK_SIZE < roi->width; i++)
          {
            GeglRectangle chunked_result;
587
            GeglRectangle chunked_sizes;
588 589 590 591

            chunked_result = *GEGL_RECTANGLE (roi->x + i * CHUNK_SIZE,
                                              roi->y + j * CHUNK_SIZE,
                                              CHUNK_SIZE, CHUNK_SIZE);
Andy Gill's avatar
Andy Gill committed
592

593
            gegl_rectangle_intersect (&chunked_result, &chunked_result, roi);
Andy Gill's avatar
Andy Gill committed
594

595 596
            if (chunked_result.width < 1  || chunked_result.height < 1)
              continue;
Andy Gill's avatar
Andy Gill committed
597

598 599 600 601 602
            src_rect = chunked_result;
            src_rect.x -= op_area->left;
            src_rect.y -= op_area->top;
            src_rect.width += op_area->left + op_area->right;
            src_rect.height += op_area->top + op_area->bottom;
603

604 605 606
            gegl_buffer_get (input, &src_rect, 1.0, babl_format ("RaGaBaA float"),
                             input_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP);

607 608 609 610 611 612 613 614 615 616
            gegl_rectangle_copy (&chunked_sizes, &chunked_result);
            chunked_sizes.x = 0;
            chunked_sizes.y = 0;

            set_rectangle (output_buf, &chunked_sizes, &chunked_sizes,
                           chunked_result.width, background_color,
                           GEGL_PIXELIZE_NORM_INFINITY);

            pixelize (input_buf, output_buf, &chunked_result, &src_rect,
                      whole_region, o);
617

618 619
            gegl_buffer_set (output, &chunked_result, 1.0,
                             babl_format ("RaGaBaA float"),
620 621 622 623 624 625 626 627
                             output_buf, GEGL_AUTO_ROWSTRIDE);
          }

      g_free (input_buf);
      g_free (output_buf);
    }
  else
    {
628 629
      gegl_buffer_set_color (output, roi, o->background);
      pixelize_noalloc (input, output, roi, whole_region, o);
630
    }
Andy Gill's avatar
Andy Gill committed
631 632 633 634 635 636

  return  TRUE;
}


static void
637
gegl_op_class_init (GeglOpClass *klass)
Andy Gill's avatar
Andy Gill committed
638 639 640 641 642 643 644
{
  GeglOperationClass       *operation_class;
  GeglOperationFilterClass *filter_class;

  operation_class = GEGL_OPERATION_CLASS (klass);
  filter_class    = GEGL_OPERATION_FILTER_CLASS (klass);

645 646 647
  operation_class->prepare          = prepare;
  operation_class->get_bounding_box = get_bounding_box;
  operation_class->opencl_support   = TRUE;
648

649 650
  filter_class->process           = process;

651
  gegl_operation_class_set_keys (operation_class,
652 653 654
    "name",               "gegl:pixelize",
    "categories",         "blur",
    "position-dependent", "true",
655
    "description", _("Simplify image into an array of solid-colored rectangles"),
656
    NULL);
Andy Gill's avatar
Andy Gill committed
657 658 659
}

#endif