I'm having trouble when try to attach original exif data back to image after rotating it by GD image.
How I rotate image
rotatedImage = gdImageRotateInterpolated(image, (360-rotationDeg)%360, 0);
imgBuffer = (unsigned char *)gdImageJpegPtr(rotatedImage, &imgSize, 85);
Then I have a function try to write extracted exif data from original image to rotated one by combine image buffer with exif buffer but I can't still see Exif data while inspecting the image. I'm using libexif
writeExifData(unsigned char* &imageBuffer, int &size, ExifData* exifData) {
if (!exifData) {
return;
}
TRACE("Image Size: %d", size);
// save exif data into buffer
unsigned char* buf = NULL;
unsigned int bufSize = 0;
exif_data_save_data(exifData, &buf, &bufSize);
std::vector<unsigned char> combinedBuffer(size + bufSize);
// Copy the image buffer
std::copy(imageBuffer, imageBuffer + size, combinedBuffer.begin());
// Copy the EXIF buffer
std::copy(buf, buf + bufSize, combinedBuffer.begin() + size);
unsigned char* newImageBuffer = (unsigned char*)malloc(combinedBuffer.size());
memcpy(newImageBuffer, combinedBuffer.data(), combinedBuffer.size());
imageBuffer = newImageBuffer;
size = combinedBuffer.size();
}
Any other way that I can have new image buffer include all Exif data from original image?
The JPEG image format consists of a number of segments using tag-length-value encoding. Furthermore, APP1 data for EXIF is supposed to come right after the SOI marker in the file, which is the first two bytes of your JPEG.
exif_save_data
produces the "value" part but you need to wrap that in a segment yourself.
Thus, you can do the following:
struct jpeg_header {
uint16_t soi;
uint16_t app1;
uint16_t exif_len;
} jh = { htobe16(0xFFD8), htobe16(0xFFE1), htobe16(2 + bufSize) };
unsigned char* newImageBuffer = (unsigned char*)malloc(sizeof(jh) + size - 2 /* duplicate SOI */);
unsigned char* write = newImageBuffer;
write = std::copy(reinterpret_cast<unsigned char *>(&jh), reinterpret_cast<unsigned char *>(&jh) + sizeof(jh), write);
write = std::copy(buf, buf+bufSize, write);
write = std::copy(imageBuffer+2, imageBuffer+size, write);
return newImageBuffer;
If you do not have access to htobe16
you can use htons
as well.