coolbutuseless / foist

Fast Output of Images
MIT License
17 stars 1 forks source link

off by 1? #3

Open mdsumner opened 8 months ago

mdsumner commented 8 months ago

You're probably aware ... and I realize there's a pending rewrite, but I found this for a particular real world blue where often the difference was not detectable, so I pinned it down to a smallish example.

I also realize that you're probably using 1:256 because it's an R index for a palette, but: that means when you give an array of bytes (which write_png accepts!) you get these wrong values out by 1. So, I'm also asking do you want to align numeric array input to byte values for future foist?

  cu <- structure(c("#002C4A", "#002E42", "#003549", "#004250", "#003D4F", 
            "#003449", "#004054", "#002949", "#00374B", "#084759", "#034254", 
            "#00364B", "#1E585C", "#012A40", "#003B4B", "#134C5F", "#084557", 
            "#023B4F", "#67714C", "#003848", "#002D48", "#00384B", "#0D4A5C", 
            "#044154"), dim = c(6L, 4L))
library(foist)
 par(mfcol = c(1, 3), mar = rep(0.1, 4))
plot(as.raster(cu), interpolate = F)
plot(as.raster(array(t(col2rgb(cu))/255, c(6, 4, 3))), interpolate = F)
write_png(array(t(col2rgb(cu)), c(6, 4, 3)), "a.png", invert = TRUE)
a <- png::readPNG("a.png")
plot(as.raster(matrix(rgb(a[,,1], a[,,2], a[,,3]), 6, byrow = F)), interpolate = F)


## we have pushed by 1 for each Byte
cbind(as.vector(cu), rgb(a[,,1], a[,,2], a[,,3]))
#>       [,1]      [,2]     
#>  [1,] "#002C4A" "#FF2B49"
#>  [2,] "#002E42" "#FF2D41"
#>  [3,] "#003549" "#FF3448"
#>  [4,] "#004250" "#FF414F"
#>  [5,] "#003D4F" "#FF3C4E"
#>  [6,] "#003449" "#FF3348"
#>  [7,] "#004054" "#FF3F53"
#>  [8,] "#002949" "#FF2848"
#>  [9,] "#00374B" "#FF364A"
#> [10,] "#084759" "#074658"
#> [11,] "#034254" "#024153"
#> [12,] "#00364B" "#FF354A"
#> [13,] "#1E585C" "#1D575B"
#> [14,] "#012A40" "#00293F"
#> [15,] "#003B4B" "#FF3A4A"
#> [16,] "#134C5F" "#124B5E"
#> [17,] "#084557" "#074456"
#> [18,] "#023B4F" "#013A4E"
#> [19,] "#67714C" "#66704B"
#> [20,] "#003848" "#FF3747"
#> [21,] "#002D48" "#FF2C47"
#> [22,] "#00384B" "#FF374A"
#> [23,] "#0D4A5C" "#0C495B"
#> [24,] "#044154" "#034053"

## if we add 1, we get the same result
par(mfcol = c(1, 3), mar = rep(0, 4))
plot(as.raster(cu), interpolate = F)
plot(as.raster(array(t(col2rgb(cu))/255, c(6, 4, 3))), interpolate = F)
write_png(array(t(col2rgb(cu)), c(6, 4, 3)) + 1, "b.png", invert = TRUE)
b <- png::readPNG("b.png")
plot(as.raster(matrix(rgb(b[,,1], b[,,2], b[,,3]), 6, byrow = F)), interpolate = F)


## now they are the same
cbind(as.vector(cu), rgb(b[,,1], b[,,2], b[,,3]))
#>       [,1]      [,2]     
#>  [1,] "#002C4A" "#002C4A"
#>  [2,] "#002E42" "#002E42"
#>  [3,] "#003549" "#003549"
#>  [4,] "#004250" "#004250"
#>  [5,] "#003D4F" "#003D4F"
#>  [6,] "#003449" "#003449"
#>  [7,] "#004054" "#004054"
#>  [8,] "#002949" "#002949"
#>  [9,] "#00374B" "#00374B"
#> [10,] "#084759" "#084759"
#> [11,] "#034254" "#034254"
#> [12,] "#00364B" "#00364B"
#> [13,] "#1E585C" "#1E585C"
#> [14,] "#012A40" "#012A40"
#> [15,] "#003B4B" "#003B4B"
#> [16,] "#134C5F" "#134C5F"
#> [17,] "#084557" "#084557"
#> [18,] "#023B4F" "#023B4F"
#> [19,] "#67714C" "#67714C"
#> [20,] "#003848" "#003848"
#> [21,] "#002D48" "#002D48"
#> [22,] "#00384B" "#00384B"
#> [23,] "#0D4A5C" "#0D4A5C"
#> [24,] "#044154" "#044154"

Created on 2024-01-24 with reprex v2.0.2

Here's foist writing an array of raw Bytes, which I want but don't want to unpack the values to offset them by 1! :)

  ex <- c(.7, .8, -0.4, -.2) * 20037508
dsn <- "<GDAL_WMS><Service name=\"TMS\"><ServerUrl>http://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/${z}/${y}/${x}</ServerUrl></Service><DataWindow><UpperLeftX>-20037508.34</UpperLeftX><UpperLeftY>20037508.34</UpperLeftY><LowerRightX>20037508.34</LowerRightX><LowerRightY>-20037508.34</LowerRightY><TileLevel>17</TileLevel><TileCountX>1</TileCountX><TileCountY>1</TileCountY><YOrigin>top</YOrigin></DataWindow><Projection>EPSG:900913</Projection><BlockSizeX>256</BlockSizeX><BlockSizeY>256</BlockSizeY><BandsCount>3</BandsCount><MaxConnections>10</MaxConnections><Cache /></GDAL_WMS>"

library(vapour)
im <- gdal_raster_data(dsn, target_ext = ex, target_dim = dm <- c(256, 512), bands = 1:3, band_output_type = "Byte")
#im <- gdal_raster_image(dsn, target_ext = ex, target_dim = dm <- c(4, 6))
ximage::ximage(im, asp = 1)


foist::write_png(array(unlist(im), c(dm, 3)), tf <- tempfile(fileext = ".png"), invert = TRUE)
plot(as.raster(aperm(png::readPNG(tf), c(2, 1, 3))))

Created on 2024-01-24 with reprex v2.0.2