Nothing
knitr::opts_chunk$set( collapse = FALSE, comment = "#>" )
A JPEG file is a collection of markers which define blocks of data in the file. See Wikipedia to get an overview of the file format.
This vignette simply parses out all the headers and prints a description of each one.
There is an included table of jpeg_markers
in this vignette, but only the
first 15 rows are displayed here.
This data consists of:
Hex
the hexadecimal code that is the makerMarker
the codename for this markerName
/Description
more information about this markerjpeg_markers <- data.frame( stringsAsFactors = FALSE, Hex = c("FFC0","FFC1","FFC2", "FFC3","FFC4","FFC5","FFC6","FFC7","FFC8","FFC9", "FFCA","FFCB","FFCC","FFCD","FFCE","FFCF","FFD0", "FFD1","FFD2","FFD3","FFD4","FFD5","FFD6","FFD7", "FFD8","FFD9","FFDA","FFDB","FFDC","FFDD","FFDE", "FFDF","FFE0","FFE1","FFE2","FFE3","FFE4","FFE5", "FFE6","FFE7","FFE8","FFE9","FFEA","FFEB", "FFEC","FFED","FFEE","FFEF","FFF0","FFF1","FFF2", "FFF3","FFF4","FFF5","FFF6","FFF7","FFF8","FFF9", "FFFA","FFFB","FFFC","FFFD","FFFE"), Marker = c("SOF0","SOF1","SOF2", "SOF3","DHT","SOF5","SOF6","SOF7","JPG","SOF9", "SOF10","SOF11","DAC","SOF13","SOF14","SOF15","RST0", "RST1","RST2","RST3","RST4","RST5","RST6","RST7", "SOI","EOI","SOS","DQT","DNL","DRI","DHP", "EXP","APP0","APP1","APP2","APP3","APP4","APP5", "APP6","APP7","APP8","APP9","APP10","APP11","APP12", "APP13","APP14","APP15","JPG0","JPG1","JPG2", "JPG3","JPG4","JPG5","JPG6","JPG7 SOF48","JPG8 LSE", "JPG9","JPG10","JPG11","JPG12","JPG13","COM"), Name = c("Start of Frame 0", "Start of Frame 1","Start of Frame 2","Start of Frame 3", "Define Huffman Table","Start of Frame 5", "Start of Frame 6","Start of Frame 7","JPEG Extensions", "Start of Frame 9","Start of Frame 10","Start of Frame 11", "Define Arithmetic Coding","Start of Frame 13", "Start of Frame 14","Start of Frame 15","Restart Marker 0", "Restart Marker 1","Restart Marker 2", "Restart Marker 3","Restart Marker 4","Restart Marker 5", "Restart Marker 6","Restart Marker 7","Start of Image", "End of Image","Start of Scan","Define Quantization Table", "Define Number of Lines","Define Restart Interval", "Define Hierarchical Progression", "Expand Reference Component","Application Segment 0","Application Segment 1", "Application Segment 2","Application Segment 3", "Application Segment 4","Application Segment 5", "Application Segment 6","Application Segment 7", "Application Segment 8","Application Segment 9", "Application Segment 10 PhoTags","Application Segment 11", "Application Segment 12","Application Segment 13", "Application Segment 14","Application Segment 15","JPEG Extension 0", "JPEG Extension 1","JPEG Extension 2", "JPEG Extension 3","JPEG Extension 4","JPEG Extension 5", "JPEG Extension 6","JPEG Extension 7 JPEG-LS", "JPEG Extension 8 JPEG-LS Extension","JPEG Extension 9", "JPEG Extension 10","JPEG Extension 11","JPEG Extension 12", "JPEG Extension 13","Comment"), Description = c("Baseline DCT", "Extended Sequential DCT","Progressive DCT", "Lossless (sequential)",NA,"Differential sequential DCT", "Differential progressive DCT","Differential lossless (sequential)", NA,"Extended sequential DCT, Arithmetic coding", "Progressive DCT, Arithmetic coding", "Lossless (sequential), Arithmetic coding",NA, "Differential sequential DCT, Arithmetic coding", "Differential progressive DCT, Arithmetic coding", "Differential lossless (sequential), Arithmetic coding",NA,NA,NA,NA,NA,NA,NA,NA,NA, NA,NA,NA,"(Not common)",NA,"(Not common)", "(Not common)", "JFIF – JFIF JPEG image AVI1 – Motion JPEG (MJPG)", "EXIF Metadata, TIFF IFD format, JPEG Thumbnail (160×120) Adobe XMP","ICC color profile, FlashPix", "(Not common) JPS Tag for Stereoscopic JPEG images", "(Not common)","(Not common)", "(Not common) NITF Lossles profile","(Not common)","(Not common)","(Not common)", "(Not common) ActiveObject (multimedia messages / captions)", "(Not common) HELIOS JPEG Resources (OPI Postscript)", "Picture Info (older digicams), Photoshop Save for Web: Ducky","Photoshop Save As: IRB, 8BIM, IPTC", "(Not common)","(Not common)","(Not common)", "(Not common)","(Not common)","(Not common)", "(Not common)","(Not common)","(Not common)","Lossless JPEG", "Lossless JPEG Extension Parameters","(Not common)", "(Not common)","(Not common)","(Not common)", "(Not common)",NA) ) jpeg_markers$Hex <- tolower(jpeg_markers$Hex) head(jpeg_markers, 15) |> knitr::kable()
library(ctypesio) jpeg_file <- system.file("img", "Rlogo.jpg", package="jpeg") jpeg <- jpeg::readJPEG(jpeg_file) plot(as.raster(jpeg))
dim(jpeg) dat <- readBin(jpeg_file, raw(), n = file.size(jpeg_file)) head(dat, 100)
A JPEG file is just a sequence of chunks. A chunk consists of
ffe0
The following code first asserts that the JPEG file starts with the "Start of Image" marker ffd8
,
then:
ffda
) is found.#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Open a connection, and tag the connection such that # values are read in **big endian** by default. #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ con <- file(jpeg_file, 'rb') |> set_endian('big') #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Read the first 2 bytes as HEX # For regular JPEG files, this should be the "Start of Image (SOI)" marker #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ soi <- read_hex(con, n = 1, size = 2) # ffd8: SOI stopifnot(soi == 'ffd8') #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Keep reading markers and the chunk data until we reach # the 'Start of Scan' marker (ffda) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ marker <- read_hex(con, n = 1, size = 2) while(length(marker) > 0 && nchar(marker) > 0) { # The relevant row from the 'jpeg_markers' data.frame info <- subset(jpeg_markers, jpeg_markers$Hex == marker) # It's possible there may be custom markers which aren't included # in my list of markers if (nrow(info) == 0) { cat("Unknown marker: ", marker, "\n") marker <- read_hex(con, n = 1, size = 2) next } # Read the length of data in this chunk and output the chunk info len <- read_uint16(con) msg <- sprintf("%s [%5i] [%s] [%s] [%s]\n", marker, len, info$Marker, info$Name, info$Description) cat(msg) # Check if we've reached the Start of Scan marker if (marker == 'ffda') { cat("Compressed image data until end of file\n") break } # Read the chunk data # In JPEG the length of each chunk includes the 2 bytes which specify # the chunk length, so read len-2 bytes from the current position chunk_data <- read_uint8(con, n = len - 2) # Process chunk data here # Read the next marker and continue marker <- read_hex(con, n = 1, size = 2) } close(con)
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.