public Image scale(Image img)
    {
        // Offset the image by one pixel so there's a border around it.
        // This lets us avoid having to check that A-I are in range of the image before samping them
        sourceGraphics.drawImage(img, 1, 1, null);

        int line = width + 2;
        for (int y = 0; y < height; y++)
        {
            // Two lines of target pixel pointers
            int tp0 = y * width * 4 - 1;
            int tp1 = tp0 + width * 2;

            // Three lines of source pixel pointers
            int sp0 = (y) * line;
            int sp1 = (y + 1) * line;
            int sp2 = (y + 2) * line;

            // Fill the initial A-I values
            int A = sourcePixels[sp0];
            int B = sourcePixels[++sp0];
            int C = sourcePixels[++sp0];
            int D = sourcePixels[sp1];
            int E = sourcePixels[++sp1];
            int F = sourcePixels[++sp1];
            int G = sourcePixels[sp2];
            int H = sourcePixels[++sp2];
            int I = sourcePixels[++sp2];

            for (int x = 0; x < width; x++)
            {
                if (B != H && D != F)
                {
                    targetPixels[++tp0] = D == B ? D : E;
                    targetPixels[++tp0] = B == F ? F : E;
                    targetPixels[++tp1] = D == H ? D : E;
                    targetPixels[++tp1] = H == F ? F : E;
                }
                else
                {
                    targetPixels[++tp0] = E;
                    targetPixels[++tp0] = E;
                    targetPixels[++tp1] = E;
                    targetPixels[++tp1] = E;
                }

                // Scroll A-I left
                A = B;
                B = C;
                D = E;
                E = F;
                G = H;
                H = I;

                // Resample rightmost edge
                C = sourcePixels[++sp0];
                F = sourcePixels[++sp1];
                I = sourcePixels[++sp2];
            }
        }

        return targetImage;
    }