This is how I implemented this using js. The marker you are looking for is the Sofn marker and the pseudocode would basically be:
- start from the first byte
- the beginning of a segment will always be
FF
followed by another byte indicating marker type (those 2 bytes are called the marker)
- if that other byte is
01
or D1
through D9
, there is no data in that segment, so proceed to next segment
- if that marker is
C0
or C2
(or any other Cn, more detail in the comments of the code), thats the Sofn marker you're looking for
- the following bytes after the marker will be P (1 byte), L (2 bytes), Height (2 bytes), Width (2 bytes) respectively
- otherwise, the next two bytes followed by it will be the length property (length of entire segment excluding the marker, 2 bytes), use that to skip to the next segment
- repeat until you find the Sofn marker
function getJpgSize(hexArr) {
let i = 0;
let marker = '';
while (i < hexArr.length) {
//ff always start a marker,
//something's really wrong if the first btye isn't ff
if (hexArr[i] !== 'ff') {
console.log(i);
throw new Error('aaaaaaa');
}
//get the second byte of the marker, which indicates the marker type
marker = hexArr[++i];
//these are segments that don't have any data stored in it, thus only 2 bytes
//01 and D1 through D9
if (marker === '01' || (!isNaN(parseInt(marker[1])) && marker[0] === 'd')) {
i++;
continue;
}
/*
sofn marker: https://www.w3.org/Graphics/JPEG/itu-t81.pdf pg 36
INFORMATION TECHNOLOGY –
DIGITAL COMPRESSION AND CODING
OF CONTINUOUS-TONE STILL IMAGES –
REQUIREMENTS AND GUIDELINES
basically, sofn (start of frame, type n) segment contains information
about the characteristics of the jpg
the marker is followed by:
- Lf [frame header length], two bytes
- P [sample precision], one byte
- Y [number of lines in the src img], two bytes, which is essentially the height
- X [number of samples per line], two bytes, which is essentially the width
... [other parameters]
sofn marker codes: https://www.digicamsoft.com/itu/itu-t81-36.html
apparently there are other sofn markers but these two the most common ones
*/
if (marker === 'c0' || marker === 'c2') {
break;
}
//2 bytes specifying length of the segment (length excludes marker)
//jumps to the next seg
i += parseInt(hexArr.slice(i + 1, i + 3).join(''), 16) + 1;
}
const size = {
height: parseInt(hexArr.slice(i + 4, i + 6).join(''), 16),
width: parseInt(hexArr.slice(i + 6, i + 8).join(''), 16),
};
return size;
}