std::unique_ptr constructJpeg()

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);
}