Search code examples
imagepngpixel

Get X/Y position of pixel in PNG file


After stripping off header bytes and de-compressing the pixel values, a PNG file leaves us with a set of rows (a horizontal strip of the image one pixel high).

Each row starts with a single byte specifying the filter used, followed by RGB values:

+-----+-----+-----+-----+-----+-----+-----+
| 0:F | 1:R | 2:G | 3:B | 4:R | 5:G | 6:B |    // end of first row in image
+-----+-----+-----+-----+-----+-----+-----+
| 7:F | 8:R | 9:G |10:B |11:R |12:G |13:B |    // end of second row
+-----+-----+-----+-----+-----+-----+-----+

In an image without the filter byte, I could just divide the index by 3 (since there are three values per RGB pixel), then use these formulas to get the x/y position of that pixel:

x = index % width
y = index / width

But the filter byte is throwing me off! How do I get the x/y position of a pixel, given a red pixel's byte index? (Say at byte 4 or at byte 11, as shown above.)

I've tried all kinds of permutations but I think there must be an elegant solution!


Solution

  • Based on comments from @usr2564301, I think this works correctly:

    y = ((index-1) / 3) / width
    x = ((index-y) / 3) % width
    

    Where width is the width of the image in pixels, not the width of the row of bytes.

    We subtract y from the index because each row has a single filter byte and we need to remove them all to get the x position.

    Alternatively, y can be calculated using:

    y = index / row_width
    

    Where row_width is the number of bytes per row: three for RGB and one filter byte times the width of the image.