Let's say I parse an image file with multiple different libraries, and ask the library for the RGB value at pixel (20, 30).
Under what conditions can I expect to get consistent results across libraries and library versions?
Intuitively, I would assume that with simpler formats like PPM or (with some constraints) BMP I could probably expect consistent results, and with JPEG I'd get results all over the place even in relatively simple cases with no way to avoid that.
That leaves me thinking about PNG: If I take an input image, convert it to a PNG with a defined color depth (e.g. 8-bit-per-channel RGBA, with all transparency values set to fully opaque) and no color profile, should I be able to expect:
all common libraries to interpret the resulting PNG in the same way (yielding the same array of RGB(A) values when reading the file)?
all common libraries to be able to turn said array of RGB(A) values back into a PNG that all common libraries will interpret in the same way?
(Obviously, the file bytes themselves will likely be different due to metadata, order of packets, etc. - I'm just talking about pixel values here. Also, obviously the initial conversion step may change the image if the original input had a color profile etc.)
For example, if you get this sample file:
wget https://upload.wikimedia.org/wikipedia/commons/thumb/7/7a/Sun_getting_through_fog_in_the_New_Zealand_bush%2C_Bryant_Range.jpg/500px-Sun_getting_through_fog_in_the_New_Zealand_bush%2C_Bryant_Range.jpg
then decode with Python:
import PIL.Image
img = PIL.Image.open('500px-Sun_getting_through_fog_in_the_New_Zealand_bush,_Bryant_Range.jpg')
print(img.getpixel((100,100))) # prints (73, 50, 60)
you will get different results than with Golang:
package main
import (
"fmt"
"image"
"log"
"os"
"image/color"
_ "image/jpeg"
_ "image/png"
)
func main() {
reader, err := os.Open("500px-Sun_getting_through_fog_in_the_New_Zealand_bush,_Bryant_Range.jpg")
if err != nil {
log.Fatal(err)
}
m, _, err := image.Decode(reader)
if err != nil {
log.Fatal(err)
}
c := m.At(100, 100).(color.YCbCr)
fmt.Printf("%+v\n", c)
r, g, b := color.YCbCrToRGB(c.Y, c.Cb, c.Cr)
fmt.Printf("%v %v %v\n", r, g, b) // prints 72 50 59
}
GIMP decodes pixel (100, 100) as (73, 50, 60), i.e. same as PIL, if you select "Keep" in the profile dialog.