What is the output of a PNG file?

Hi. If I read a PNG graphics file and print it, what does the outpur represent?

library(png)
img <- readPNG(system.file("img", "Rlogo.png", package="png"))
img

It seems to be a bit map of the image. If I run the following code, I get a rough version of the image.

library(tidyverse)
> Image <- png::readPNG("PistonsPlot.png")
> dim(Image)
[1] 438 547   3
> DF <- as.data.frame(Image[,,1])
> DFlng <- pivot_longer(DF, cols = everything())
> DFlng <- DFlng |> mutate(X = rep(547:1, 438), Y = rep(438:1, each = 547))
> ggplot(DFlng, aes(X, Y, color = value)) + geom_point()
> DFlng <- DFlng |> mutate(X = rep(1:547, 438), Y = rep(438:1, each = 547))
> ggplot(DFlng, aes(X, Y, color = value)) + geom_point()

I only plotted one of the three shelves in the array. I suppose each shelf is one color in RGB coding of the image, but that is just a guess.

  1. What is a shelf, and how would I combine them? I assume the answer is in the third coordinate of Image?

  2. I was not expecting the plot to appear on a grid, which is a plus. This brings up a different question. Suppose I am printing the image with grid::grid.raster(img) Is there a way to save a subset of the image with geom_rect ?

  1. Yes, shelf is the third dimension. I don't think there is a single standard name for it.
  2. I have no experience manipulating png files, so I can't help you with that. I suppose subsets of the array can be made in the usual way but I don't know the best ways to get decent images from them.

I am still unclear what an image file represents. Is it a 3 dimensional object where (x = height, y = width, z = one of R, G, or B)? Is (x,y) a pixel? And what does the 7 digit value represent - is it the percentage of full color (I'm sure I have the wording incorrect here). And somehow every (x,y) is going to get converted to a six digit hex number?

The png I looked at is three dimensional. It seems that each matrix value is a pixel, x positions in columns, y in rows. I suppose the three in z are the RGB values. If I multiply the stored values by 255, I get all integers. Most of the values in my example are 0 or 1, but if I filter for values between 0 and 1, I get a fairly small set of integers. That's just a quirk of my image, I suppose. Each integer can be coded as a two digit hexadecimal.

library(tidyverse)
Image <- png::readPNG("~/R/Play/PistonsPlot.png")
dim(Image)
#> [1] 438 547   3
DF <- as.data.frame(Image[,,1])
DFlng <- pivot_longer(DF, cols = everything())
num <- filter(DFlng, value<1, value>0)
num$rescale <- num$value * 255
table(num$rescale)
#> 
#>   51   58   77   94   97  102  110  132  142  144  168  171  182  200  201  219 
#> 1464  600  185    1 1096  449   97    1  150  616    1  121  504  101    1  433 
#>  228  235  248 
#>  112 5608 1379

Created on 2024-02-05 with reprex v2.0.2

1 Like

Hi, just wanted to add on. Appears the answer is yes each entry is a pixel because it’s a raster:

Reads an image from a PNG file/content into a raster array.

Each entry is a percentage of the channel because:

Most common files decompress into RGB (3 channels), RGBA (4 channels), Grayscale (1 channel) or GA (2 channels)

And I think the png can be stored as hex, but doesn’t need to be it seems:

Alternative representation of an image is of nativeRaster class which is an integer matrix with each entry representing one pixel in binary encoded RGBA format (as used internally by R). It can be obtained from readPNG using native = TRUE .

Sources:

1 Like

This topic was automatically closed 21 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.