MilkyWiki EditExifInC Edit MetaEdit Search
easyexifなどは有名だが、殆どはexifの読み込みのみ。
書き込みができるものを探す
https://github.com/10imaging/exif
exifの読み込みと書き込み。ドキュメントはあまりない。
以下サンプルソース、ヘッダーしか書いてくれないので上書きするとか・・・。
todo: gps情報があるものだけを編集する。
#include <iostream>
#include <fstream>
#include <vector>
#include "exif.h"
int main() {
// a jpeg file
std::ifstream file("image.jpg", std::ios::binary | std::ios::ate);
std::streamsize size = file.tellg();
file.seekg(0, std::ios::beg);
std::vector<char> buf(size);
file.read(buf.data(), size);
file.close();
std::cout << "start remove gps of image.jpg" << std::endl;
exif::EXIFInfo exif;
exif.readEXIF((unsigned char*)buf.data(), buf.size());
std::cout << "read complete" << std::endl;
// erase gps directory entirely (excep version, 01-1F)
for (int i = 1; i < 0x1F; i++) {
exif.removeEntry(i, GPS_IFD_DIRECTORY);
}
unsigned char* nbuf;
unsigned long nsize;
std::cout << "removed gps data" << std::endl;
exif.encodeJPEGHeader(&nbuf, &nsize);
std::cout << "encoded jpeg header" << std::endl;
// write the new jpeg file with gps removed
std::ofstream wfile("output.jpg", std::ios::binary);
wfile.write((char*)nbuf, nsize);
std::cout << "write completed" << std::endl;
wfile.close();
return 0;
}
またライブラリのget_valが間違っていて範囲外アクセスを引き起こしているらしい。
/**
* Get the value from the entry itself or write the value in the data buffer and return the address of the data
* @param entry Input entry to get value from
* @param buf Starting address of the EXIF buffer for getting the data buffer address
* @param dataOffset Offset of data buffer from EXIF buffer
* @return Either the actual value of the entry or the address where the value is stored
*/
u_int32_t get_val(exif::IFEntry entry, unsigned char *buf, u_int32_t *dataOffset) {
u_int32_t dataAddr = *dataOffset - EXIF_START;
//LOGD("Entry %x format %d length %d",entry.tag(),entry.format(),entry.length());
unsigned char *dataBuf = &buf[*dataOffset];
int offset = 0;
switch (entry.format()) {
case ENTRY_FORMAT_BYTE:
case ENTRY_FORMAT_UNDEFINED:
if (entry.val_byte().size() > 4) {
memcpy(dataBuf, entry.val_byte().data(), entry.val_byte().size());
*dataOffset += entry.val_byte().size();
} else {
uint32_t value = 0;
for (unsigned long i = 0; i < entry.val_byte().size() && i < 4; i++) {
value |= (uint32_t)entry.val_byte()[i] << (8 * (3 - i));
}
return value;
}
break;
case ENTRY_FORMAT_ASCII:
if (entry.length() > 4) { // Use original length since we might have removed the \0
memcpy(dataBuf, entry.val_string().c_str(), entry.val_string().length());
if (entry.length() - entry.val_string().length() == 1) { // account for the \0
dataBuf[entry.length() - 1] = 0;
}
*dataOffset += entry.length();
} else {
uint32_t value = 0;
for (unsigned long i = 0; i < entry.val_string().size() && i < 4; i++) {
value |= (uint32_t)(unsigned char)entry.val_string()[i] << (8 * (3 - i));
}
return value;
}
break;
case ENTRY_FORMAT_SHORT:
if (entry.val_short().size() > 2) {
for (unsigned long i=0; i<entry.val_short().size(); i++) {
offset += write_buffer_2(&dataBuf[offset],entry.val_short().at(i));
}
*dataOffset += offset;
} else {
uint32_t value = 0;
if (entry.val_short().size() > 0) {
value |= (uint32_t)entry.val_short()[0] << 16;
}
if (entry.val_short().size() > 1) {
value |= entry.val_short()[1];
}
return value;
}
break;
case ENTRY_FORMAT_LONG:
if (entry.val_long().size() > 1) {
for (unsigned long i=0; i<entry.val_long().size(); i++) {
offset += write_buffer_4(&dataBuf[offset],entry.val_long().at(i));
}
*dataOffset += offset;
} else {
return entry.val_long().empty() ? 0 : entry.val_long().front();
}
break;
case ENTRY_FORMAT_RATIONAL:
for (unsigned long i=0; i<entry.val_rational().size(); i++) {
offset += write_buffer_4(&dataBuf[offset], entry.val_rational().at(i).numerator);
offset += write_buffer_4(&dataBuf[offset], entry.val_rational().at(i).denominator);
}
*dataOffset += offset;
break;
case ENTRY_FORMAT_SRATIONAL:
for (unsigned long i=0; i<entry.val_srational().size(); i++) {
offset += write_buffer_4(&dataBuf[offset], (u_int32_t) entry.val_srational().at(i).numerator);
offset += write_buffer_4(&dataBuf[offset], (u_int32_t) entry.val_srational().at(i).denominator);
}
*dataOffset += offset;
break;
default:
ERROR("Unsupported format %d",entry.format());
return 0;
}
return dataAddr;
}
Back Last Update: Sun, 17 May 2026 16:43:11 +0900