The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.
// C code for Image::Filter::Floyd
// Floyd-Steinberg Dithering
// (c) 2002 - Hendrik Van Belleghem
// hendrik@quickndirty.org
// Released under the GPL

#include <math.h>
#include <stdio.h>
#include "gd.h"

gdImagePtr floyd (gdImagePtr imageptr, int limit)
{ gdImagePtr imfloyd;
  int dimx = 0;
  int dimy = 0;
  int w = 0;
  int h = 0;
  int pixel = 0;
  int newpixel = 0;
  int index = 0;
  int diff = 0;
  dimx = gdImageSX(imageptr);
  dimy = gdImageSY(imageptr);
  imfloyd = gdImageCreateTrueColor(dimx,dimy);
  for (w = 0; w < dimx-2 ; w++)
  { for (h = 1; h < dimy-2 ; h++)
    { pixel = (gdImageRed(imageptr,gdImageGetPixel(imageptr,w,h)) > limit ? 255 : 0);
      diff = gdImageRed(imageptr,gdImageGetPixel(imageptr,w,h))-pixel;
      index = gdImageColorExact(imfloyd,pixel,pixel,pixel);
      if (index == -1) 
      { index = gdImageColorAllocate(imageptr,pixel,pixel,pixel); }
        gdImageSetPixel(imfloyd,w,h,index);
 
        newpixel = (int) (gdImageRed(imageptr,gdImageGetPixel(imageptr,w+1,h)) + (7/16 * diff));
        newpixel = newpixel > 255 ? 255 : (newpixel < 0 ? 0 : newpixel);
        index = gdImageColorExact(imageptr,newpixel,newpixel,newpixel);
        if (index == -1) 
        { index = gdImageColorAllocate(imageptr,newpixel,newpixel,newpixel); }
        gdImageSetPixel(imageptr,w+1,h,index);

        newpixel = (int) (gdImageRed(imageptr,gdImageGetPixel(imageptr,w+1,h+1)) + (1/16 * diff));
        newpixel = newpixel > 255 ? 255 : (newpixel < 0 ? 0 : newpixel);
        index = gdImageColorExact(imageptr,newpixel,newpixel,newpixel);
        if (index == -1) 
        { index = gdImageColorAllocate(imageptr,newpixel,newpixel,newpixel); }
        gdImageSetPixel(imageptr,w+1,h+1,index);

        newpixel = (int) (gdImageRed(imageptr,gdImageGetPixel(imageptr,w-1,h+1)) + (3/16 * diff));
        newpixel = newpixel > 255 ? 255 : (newpixel < 0 ? 0 : newpixel);
        index = gdImageColorExact(imageptr,newpixel,newpixel,newpixel);
        if (index == -1) 
        { index = gdImageColorAllocate(imageptr,newpixel,newpixel,newpixel); }
        gdImageSetPixel(imageptr,w-1,h+1,index);

        newpixel = (int) (gdImageRed(imageptr,gdImageGetPixel(imageptr,w,h+1)) + (5/16 * diff));
        newpixel = newpixel > 255 ? 255 : (newpixel < 0 ? 0 : newpixel);
        index = gdImageColorExact(imageptr,newpixel,newpixel,newpixel);
        if (index == -1) 
        { index = gdImageColorAllocate(imageptr,newpixel,newpixel,newpixel); }
        gdImageSetPixel(imageptr,w,h+1,index);
    }
 }
 return imfloyd;
}