in src/tiffFrame.cpp [66:146]
std::unique_ptr<uint8_t[]> constructJpeg(TiffTile *tile, uint64_t *size) {
/*
Tiff frames from files with missing complete jpeg tiles
require reconstruction of jpeg payload.
jpeg file format = jfif fileformat
* Tiles Missing APP0 header.
* tabels for all tiles written in jpegTables tag (shared across all tiles)
* raw tile datasetream contains just encoded image values.
* reconstruction requires
* image start tag (2 bytes)
* creating image header (APPO)
* adding tables <- table data embedded with start / end tags.
* adding pixel data. <- embedded with start / end tags.
* image end tag (2 bytes)
*/
const uint8_t *data = tile->rawBuffer();
const uint64_t rawBufferSize = tile->rawBufferSize();
const TiffDirectory *dir = tile->directory();
const int64_t tableDatasize = dir->jpegTableDataSize();
const uint8_t *tableData = dir->jpegTableData();
uint8_t APP0[] = {
0xff, 0xd8, // start of image marker
0xff, 0xe0, // APP0 marker
0x00, 0x00, // placeholder for length excluding APP0 marker
0x4A, 0x46, 0x49, 0x46, 0x00, // "JFIF" in ascii with null
0x00, // density unit; 0 = no unit
0x00, 0x00, // pixel horizontal aspect ratio
0x00, 0x00, // pixel vertical aspect ratio place holder
0x00, // thumbnail pixel horizontal; no thumbnail
0x00}; // thumbnail pixel vertical; no thumbnail
// exclude start of image and APP0 markers
setShortBigEndian(APP0, 4, sizeof(APP0) -4);
setShortBigEndian(APP0, 12, 1);
setShortBigEndian(APP0, 14, 1);
uint8_t APP14[] = {
/*
* Length of APP14 block (2 bytes)
* Block ID (5 bytes - ASCII "Adobe")
* Version Number (2 bytes - currently 100)
* Flags0 (2 bytes - currently 0)
* Flags1 (2 bytes - currently 0)
* Color transform (1 byte)
*
* Although Adobe TN 5116 mentions Version = 101, all the Adobe files
* now in circulation seem to use Version = 100, so that's what we write.
*
* We write the color transform byte as 1 if the JPEG color space is
* YCbCr, 2 if it's YCCK, 0 otherwise. Adobe's definition has to do with
* whether the encoder performed a transformation.
*/
0xff, 0xee,
0x00, 0x00, // Length Placeholder
0x41, 0x64, 0x6F, 0x62, 0x65, // Identifier: ASCII "Adobe"
0x00, 0x00, // version place holder
0x00, 0x00, // flag 1
0x00, 0x00, // flag 2
0x00}; // color transform. 0 = RGB; 1 =YCBRCR
setShortBigEndian(APP14, 2, sizeof(APP14) -2);
setShortBigEndian(APP14, 9, 100);
if (dir->isPhotoMetricYCBCR()) {
APP14[15] = 1;
}
// -6 exclude start and end markers in table data, and
// start maker in raw buffer.
*size = tableDatasize + rawBufferSize - 6 + sizeof(APP0) + sizeof(APP14);
std::unique_ptr<uint8_t[]> jpegMem = std::make_unique<uint8_t[]>(*size);
uint8_t * writeBuffer = jpegMem.get();
uint64_t bytesWritten = 0;
writeMem(writeBuffer, APP0, sizeof(APP0), &bytesWritten);
writeMem(writeBuffer, APP14, sizeof(APP14), &bytesWritten);
writeMem(writeBuffer, &(tableData[2]), tableDatasize - 4, &bytesWritten);
writeMem(writeBuffer, &(data[2]), rawBufferSize - 2, &bytesWritten);
return std::move(jpegMem);
}