Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions src/common/exif.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2442,6 +2442,27 @@ gboolean dt_exif_read(dt_image_t *img,
}
}

int dt_exif_write_exv(uint8_t *blob,
uint32_t size,
const char *path,
const int compressed)
{
try
{
std::unique_ptr<Exiv2::Image> image(Exiv2::ImageFactory::create(Exiv2::ImageType::exv, WIDEN(path)));
image->writeMetadata();
}
catch(const Exiv2::AnyError &e)
{
dt_print(DT_DEBUG_IMAGEIO,
"[exiv2 dt_exif_write_blob] %s: %s",
path,
e.what());
return 0;
}
return 1;
}

int dt_exif_write_blob(uint8_t *blob,
uint32_t size,
const char *path,
Expand Down
6 changes: 6 additions & 0 deletions src/common/exif.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ int dt_exif_read_blob(uint8_t **blob, const char *path, const dt_imgid_t imgid,
/** Reads exif tags that are not cached in the database */
void dt_exif_img_check_additional_tags(dt_image_t *img, const char *filename);

/** create empty metadata file */
int dt_exif_write_exv(uint8_t *blob,
uint32_t size,
const char *path,
const int compressed);

/** write blob to file exif. merges with existing exif information.*/
int dt_exif_write_blob(uint8_t *blob, uint32_t size, const char *path, const int compressed);

Expand Down
14 changes: 7 additions & 7 deletions src/imageio/format/jxl.c
Original file line number Diff line number Diff line change
Expand Up @@ -309,8 +309,8 @@ int write_image(struct dt_imageio_module_data_t *data,
if(exif && exif_len > 0)
LIBJXL_ASSERT(JxlEncoderUseBoxes(encoder));

/* TODO: workaround; remove when exiv2 implements JXL BMFF write support and use dt_exif_write_blob() after
* closing file instead */
// /* TODO: workaround; remove when exiv2 implements JXL BMFF write support and use dt_exif_write_blob() after
// * closing file instead */
if(exif && exif_len > 0)
{
// Prepend the 4 byte (zero) offset to the blob before writing
Expand All @@ -319,8 +319,8 @@ int write_image(struct dt_imageio_module_data_t *data,
if(!exif_buf)
JXL_FAIL("could not allocate Exif buffer of size %zu", (size_t)(exif_len + 4));
memmove(exif_buf + 4, exif, exif_len);
// Exiv2 < 0.28 doesn't support Brotli compressed boxes
LIBJXL_ASSERT(JxlEncoderAddBox(encoder, "Exif", exif_buf, exif_len + 4, JXL_FALSE));
// Exiv2 >= 0.28 (released 2023-05-08) supports Brotli compressed boxes
LIBJXL_ASSERT(JxlEncoderAddBox(encoder, "Exif", exif_buf, exif_len + 4, JXL_TRUE));
}

/* TODO: workaround; remove when exiv2 implements JXL BMFF write support and update flags() */
Expand All @@ -332,13 +332,13 @@ int write_image(struct dt_imageio_module_data_t *data,
if(xmp_string
&& (xmp_len = strlen(xmp_string)) > 0)
{
// Exiv2 < 0.28 doesn't support Brotli compressed boxes
// Exiv2 >= 0.28 (released 2023-05-08) supports Brotli compressed boxes
LIBJXL_ASSERT(JxlEncoderAddBox(encoder, "xml ",
(const uint8_t *)xmp_string, xmp_len, JXL_FALSE));
(const uint8_t *)xmp_string, xmp_len, JXL_TRUE));
}
}

JxlPixelFormat pixel_format = { 3, JXL_TYPE_FLOAT, JXL_NATIVE_ENDIAN, 0 };
f JxlPixelFormat pixel_format = { 3, JXL_TYPE_FLOAT, JXL_NATIVE_ENDIAN, 0 };

// Fix pixel stride
const size_t pixels_size = width * height * 3 * sizeof(float);
Expand Down
51 changes: 38 additions & 13 deletions src/imageio/imageio.c
Original file line number Diff line number Diff line change
Expand Up @@ -1436,7 +1436,7 @@ gboolean dt_imageio_export_with_flags(const dt_imgid_t imgid,
if(!ignore_exif
&& (!strcmp(format->mime(NULL), "image/avif")
|| !strcmp(format->mime(NULL), "image/x-exr")
|| !strcmp(format->mime(NULL), "image/jxl")
// || !strcmp(format->mime(NULL), "image/jxl")
|| !strcmp(format->mime(NULL), "image/x-xcf")))
{
const int32_t meta_all =
Expand All @@ -1446,6 +1446,40 @@ gboolean dt_imageio_export_with_flags(const dt_imgid_t imgid,
md_flags_set = metadata ? (metadata->flags & meta_all) == meta_all : FALSE;
}

uint8_t *exif_profile0 = NULL; // Exif data should be 65536 bytes
// max, but if original size is
// close to that, adding new tags
// could make it go over that... so
// let it be and see what happens
// when we write the image
char pathname[PATH_MAX] = { 0 };
gboolean from_cache = TRUE;
dt_image_full_path(imgid, pathname, sizeof(pathname), &from_cache);

// last param is dng mode, it's false here
const int length0 = dt_exif_read_blob(&exif_profile0, pathname, imgid, sRGB,
processed_width, processed_height, FALSE);

char* exv_filename = g_malloc(strlen(filename) + 5);
snprintf(exv_filename, strlen(filename) + 5, "%s%s", filename, ".exv");

// empty metadata file (XXX call write_blob inside there for us)
dt_exif_write_exv(exif_profile0, length0, exv_filename, 1);

// write data into metadata file
dt_exif_write_blob(exif_profile0, length0, exv_filename, 1);

free(exif_profile0);

/* now write xmp into that container, if possible */
if(copy_metadata
&& (format->flags(format_params) & FORMAT_FLAGS_SUPPORT_XMP))
{
dt_exif_xmp_attach_export(imgid, exv_filename, metadata, &dev, &pipe);
// no need to cancel the export if this fail
}

// write image including filtered metadata from .exv
if(!ignore_exif && md_flags_set)
{
uint8_t *exif_profile = NULL; // Exif data should be 65536 bytes
Expand All @@ -1454,12 +1488,8 @@ gboolean dt_imageio_export_with_flags(const dt_imgid_t imgid,
// could make it go over that... so
// let it be and see what happens
// when we write the image
char pathname[PATH_MAX] = { 0 };
gboolean from_cache = TRUE;
dt_image_full_path(imgid, pathname, sizeof(pathname), &from_cache);

// last param is dng mode, it's false here
const int length = dt_exif_read_blob(&exif_profile, pathname, imgid, sRGB,
const int length = dt_exif_read_blob(&exif_profile, exv_filename, imgid, sRGB,
processed_width, processed_height, FALSE);

res = (format->write_image(format_params, filename, outbuf, icc_type,
Expand All @@ -1475,16 +1505,11 @@ gboolean dt_imageio_export_with_flags(const dt_imgid_t imgid,
&pipe, export_masks)) != 0;
}

g_free(exv_filename);

if(res)
goto error;

/* now write xmp into that container, if possible */
if(copy_metadata
&& (format->flags(format_params) & FORMAT_FLAGS_SUPPORT_XMP))
{
dt_exif_xmp_attach_export(imgid, filename, metadata, &dev, &pipe);
// no need to cancel the export if this fail
}

dt_dev_pixelpipe_cleanup(&pipe);
dt_dev_cleanup(&dev);
Expand Down