Skip to content

Commit a95cde3

Browse files
committed
Update README and metadata support docs
Refactor and condense README.md to clarify project scope, transfer/edit capabilities, tooling, build options, and usage; reorganize sections, add links to detailed docs, and simplify wording. Rewrite docs/metadata_support.md to standardize status labels, clean up coverage snapshot and container/family tables, and improve readability of the metadata support matrix. These changes are editorial and documentation-only improvements to make supported features and transfer status easier to understand.
1 parent c59f09d commit a95cde3

9 files changed

Lines changed: 2608 additions & 1482 deletions

README.md

Lines changed: 122 additions & 459 deletions
Large diffs are not rendered by default.

docs/metadata_support.md

Lines changed: 142 additions & 258 deletions
Large diffs are not rendered by default.

docs/metadata_transfer_plan.md

Lines changed: 261 additions & 645 deletions
Large diffs are not rendered by default.

src/openmeta/metadata_transfer.cc

Lines changed: 455 additions & 0 deletions
Large diffs are not rendered by default.

src/python/openmeta/python/metatransfer.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -214,9 +214,9 @@ def main(argv: list[str]) -> int:
214214
help="output directory for --unsafe-write-payloads",
215215
)
216216
ap.add_argument("--target-jxl", action="store_true", help="target JPEG XL metadata emit summary")
217-
ap.add_argument("--target-webp", action="store_true", help="target WebP metadata chunk emit summary")
217+
ap.add_argument("--target-webp", action="store_true", help="target WebP metadata transfer")
218218
ap.add_argument("--target-png", action="store_true", help="target PNG metadata transfer")
219-
ap.add_argument("--target-jp2", action="store_true", help="target JP2 metadata box emit summary")
219+
ap.add_argument("--target-jp2", action="store_true", help="target JP2 metadata transfer")
220220
ap.add_argument("--target-heif", action="store_true", help="target HEIF metadata transfer")
221221
ap.add_argument("--target-avif", action="store_true", help="target AVIF metadata transfer")
222222
ap.add_argument("--target-cr3", action="store_true", help="target CR3 metadata transfer")
@@ -406,15 +406,16 @@ def main(argv: list[str]) -> int:
406406
or args.target_tiff
407407
or args.target_webp
408408
or args.target_png
409+
or args.target_jp2
409410
or args.target_jxl
410411
or args.target_heif
411412
or args.target_avif
412413
or args.target_cr3
413414
):
414415
ap.error(
415416
"--output requires --target-jpeg, --target-tiff, --target-webp, "
416-
"--target-png, --target-jxl, --target-heif, --target-avif, or "
417-
"--target-cr3"
417+
"--target-png, --target-jp2, --target-jxl, --target-heif, "
418+
"--target-avif, or --target-cr3"
418419
)
419420
if args.dump_c2pa_binding and (
420421
args.target_tiff
@@ -531,6 +532,7 @@ def main(argv: list[str]) -> int:
531532
and (
532533
args.target_webp
533534
or args.target_png
535+
or args.target_jp2
534536
or args.target_jxl
535537
or args.target_heif
536538
or args.target_avif

src/tools/metatransfer.cc

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,9 @@ namespace {
100100
" --target-jpeg <path> Target JPEG stream for edit/apply phase\n"
101101
" --target-tiff <path> Target TIFF stream for edit/apply phase\n"
102102
" --target-png Target PNG metadata transfer\n"
103-
" --target-jp2 Target JP2 metadata box emit summary\n"
103+
" --target-jp2 Target JP2 metadata transfer\n"
104104
" --target-jxl Target JPEG XL metadata emit summary\n"
105-
" --target-webp Target WebP metadata chunk emit summary\n"
105+
" --target-webp Target WebP metadata transfer\n"
106106
" --target-heif Target HEIF metadata transfer\n"
107107
" --target-avif Target AVIF metadata transfer\n"
108108
" --target-cr3 Target CR3 metadata transfer\n"
@@ -1997,6 +1997,9 @@ main(int argc, char** argv)
19971997
const bool need_png_edit = options.prepare.target_format
19981998
== TransferTargetFormat::Png
19991999
&& (dry_run || !output_path.empty());
2000+
const bool need_jp2_edit = options.prepare.target_format
2001+
== TransferTargetFormat::Jp2
2002+
&& (dry_run || !output_path.empty());
20002003
const bool need_jxl_edit = options.prepare.target_format
20012004
== TransferTargetFormat::Jxl
20022005
&& (dry_run || !output_path.empty());
@@ -2358,7 +2361,8 @@ main(int argc, char** argv)
23582361
exec_options.jpeg_edit = edit_plan_opts;
23592362
exec_options.edit_requested = need_jpeg_edit || need_tiff_edit
23602363
|| need_webp_edit || need_png_edit
2361-
|| need_jxl_edit || need_bmff_edit;
2364+
|| need_jp2_edit || need_jxl_edit
2365+
|| need_bmff_edit;
23622366
exec_options.edit_apply = !dry_run && !output_path.empty();
23632367
if (use_output_writer) {
23642368
exec_options.edit_output_writer = &output_writer;
@@ -3502,6 +3506,76 @@ main(int argc, char** argv)
35023506
}
35033507

35043508
if (prepared.bundle.target_format == TransferTargetFormat::Jp2) {
3509+
if (exec.edit_requested) {
3510+
if (exec.edit_plan_status == TransferStatus::Ok) {
3511+
std::printf(
3512+
" jp2_edit: status=%s input=%llu output=%llu\n",
3513+
transfer_status_name(exec.edit_plan_status),
3514+
static_cast<unsigned long long>(exec.edit_input_size),
3515+
static_cast<unsigned long long>(exec.edit_output_size));
3516+
} else {
3517+
std::printf(" jp2_edit: status=%s\n",
3518+
transfer_status_name(exec.edit_plan_status));
3519+
}
3520+
if (!exec.edit_plan_message.empty()) {
3521+
std::printf(" jp2_edit_message=%s\n",
3522+
exec.edit_plan_message.c_str());
3523+
}
3524+
if (exec.edit_plan_status != TransferStatus::Ok) {
3525+
any_failed = true;
3526+
}
3527+
}
3528+
3529+
if (!output_path.empty()) {
3530+
if (!force && output_exists) {
3531+
std::fprintf(stderr,
3532+
" jp2_edit_apply: exists: %s (use --force)\n",
3533+
output_path.c_str());
3534+
any_failed = true;
3535+
continue;
3536+
}
3537+
if (!dry_run) {
3538+
std::printf(
3539+
" jp2_edit_apply: status=%s code=%s emitted=%u skipped=%u errors=%u\n",
3540+
transfer_status_name(exec.edit_apply.status),
3541+
emit_transfer_code_name(exec.edit_apply.code),
3542+
exec.edit_apply.emitted, exec.edit_apply.skipped,
3543+
exec.edit_apply.errors);
3544+
if (!exec.edit_apply.message.empty()) {
3545+
std::printf(" jp2_edit_apply_message=%s\n",
3546+
exec.edit_apply.message.c_str());
3547+
}
3548+
if (exec.edit_apply.status != TransferStatus::Ok) {
3549+
any_failed = true;
3550+
continue;
3551+
}
3552+
if (use_output_writer) {
3553+
if (output_writer.finish() != TransferStatus::Ok) {
3554+
std::fprintf(stderr,
3555+
" jp2_edit_apply: write_failed: %s\n",
3556+
output_path.c_str());
3557+
any_failed = true;
3558+
continue;
3559+
}
3560+
} else if (!write_file_bytes(
3561+
output_path,
3562+
std::span<const std::byte>(
3563+
exec.edited_output.data(),
3564+
exec.edited_output.size()))) {
3565+
std::fprintf(stderr,
3566+
" jp2_edit_apply: write_failed: %s\n",
3567+
output_path.c_str());
3568+
any_failed = true;
3569+
continue;
3570+
}
3571+
std::printf(" output=%s bytes=%llu\n", output_path.c_str(),
3572+
static_cast<unsigned long long>(
3573+
use_output_writer
3574+
? output_writer.bytes_written()
3575+
: exec.edited_output.size()));
3576+
}
3577+
}
3578+
35053579
std::printf(
35063580
" compile: status=%s code=%s ops=%u skipped=%u errors=%u\n",
35073581
transfer_status_name(exec.compile.status),

tests/cli_metatransfer_smoke_test.cmake

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ set(_dump_dir "${WORK_DIR}/payloads")
2020
set(_edited_jpg "${WORK_DIR}/edited.jpg")
2121
set(_target_jxl "${WORK_DIR}/target.jxl")
2222
set(_edited_jxl "${WORK_DIR}/edited.jxl")
23+
set(_target_jp2 "${WORK_DIR}/target.jp2")
24+
set(_edited_jp2 "${WORK_DIR}/edited.jp2")
2325
set(_jxl_handoff "${WORK_DIR}/jxl_encoder_handoff.omjxic")
2426
set(_split_jpg "${WORK_DIR}/split_injected.jpg")
2527
set(_target_tif "${WORK_DIR}/target.tif")
@@ -107,6 +109,19 @@ if(NOT _rv_write_jxl EQUAL 0)
107109
"failed to write target jxl fixture (${_rv_write_jxl})\nstdout:\n${_out_write_jxl}\nstderr:\n${_err_write_jxl}")
108110
endif()
109111

112+
# Minimal JP2 target: signature + ftyp + free box.
113+
execute_process(
114+
COMMAND python3 -c
115+
"from pathlib import Path; u32=lambda v:(v).to_bytes(4,'big'); box=lambda t,p:u32(8+len(p))+t+p; ftyp=b'jp2 '+u32(0)+b'jp2 '; sig=u32(12)+b'jP '+u32(0x0D0A870A); Path(r'''${_target_jp2}''').write_bytes(sig+box(b'ftyp', ftyp)+box(b'free', bytes([0x11,0x22,0x33])))"
116+
RESULT_VARIABLE _rv_write_jp2
117+
OUTPUT_VARIABLE _out_write_jp2
118+
ERROR_VARIABLE _err_write_jp2
119+
)
120+
if(NOT _rv_write_jp2 EQUAL 0)
121+
message(FATAL_ERROR
122+
"failed to write target jp2 fixture (${_rv_write_jp2})\nstdout:\n${_out_write_jp2}\nstderr:\n${_err_write_jp2}")
123+
endif()
124+
110125
#Minimal classic TIFF target(II + 42 + IFD0 at offset 8 with 0 entries)
111126
execute_process(
112127
COMMAND python3 -c
@@ -1361,6 +1376,84 @@ if(NOT _rv_jxl_edit_check EQUAL 0)
13611376
"metatransfer jxl edit output check failed\nstdout:\n${_out_jxl_edit}\nstderr:\n${_err_jxl_edit}\ncheck_stderr:\n${_err_jxl_edit_check}")
13621377
endif()
13631378

1379+
execute_process(
1380+
COMMAND "${METATRANSFER_BIN}" --no-build-info
1381+
--target-jp2
1382+
--no-xmp
1383+
--no-icc
1384+
--no-iptc
1385+
"${_jpg}"
1386+
RESULT_VARIABLE _rv_jp2
1387+
OUTPUT_VARIABLE _out_jp2
1388+
ERROR_VARIABLE _err_jp2
1389+
)
1390+
if(NOT _rv_jp2 EQUAL 0)
1391+
message(FATAL_ERROR
1392+
"metatransfer jp2 summary failed (${_rv_jp2})\nstdout:\n${_out_jp2}\nstderr:\n${_err_jp2}")
1393+
endif()
1394+
if(NOT _out_jp2 MATCHES "compile: status=ok")
1395+
message(FATAL_ERROR
1396+
"metatransfer jp2 summary missing compile ok\nstdout:\n${_out_jp2}\nstderr:\n${_err_jp2}")
1397+
endif()
1398+
if(NOT _out_jp2 MATCHES "emit: status=ok")
1399+
message(FATAL_ERROR
1400+
"metatransfer jp2 summary missing emit ok\nstdout:\n${_out_jp2}\nstderr:\n${_err_jp2}")
1401+
endif()
1402+
if(NOT _out_jp2 MATCHES "jp2_box Exif count=1")
1403+
message(FATAL_ERROR
1404+
"metatransfer jp2 summary missing Exif box summary\nstdout:\n${_out_jp2}\nstderr:\n${_err_jp2}")
1405+
endif()
1406+
1407+
execute_process(
1408+
COMMAND "${METATRANSFER_BIN}" --no-build-info
1409+
--source-meta "${_jpg}"
1410+
--target-jp2
1411+
--no-xmp
1412+
--no-icc
1413+
--no-iptc
1414+
--output "${_edited_jp2}" --force
1415+
"${_target_jp2}"
1416+
RESULT_VARIABLE _rv_jp2_edit
1417+
OUTPUT_VARIABLE _out_jp2_edit
1418+
ERROR_VARIABLE _err_jp2_edit
1419+
)
1420+
if(NOT _rv_jp2_edit EQUAL 0)
1421+
message(FATAL_ERROR
1422+
"metatransfer jp2 edit failed (${_rv_jp2_edit})\nstdout:\n${_out_jp2_edit}\nstderr:\n${_err_jp2_edit}")
1423+
endif()
1424+
if(NOT _out_jp2_edit MATCHES "jp2_edit: status=ok")
1425+
message(FATAL_ERROR
1426+
"metatransfer jp2 edit missing jp2_edit ok\nstdout:\n${_out_jp2_edit}\nstderr:\n${_err_jp2_edit}")
1427+
endif()
1428+
if(NOT _out_jp2_edit MATCHES "jp2_edit_apply: status=ok")
1429+
message(FATAL_ERROR
1430+
"metatransfer jp2 edit missing jp2_edit_apply ok\nstdout:\n${_out_jp2_edit}\nstderr:\n${_err_jp2_edit}")
1431+
endif()
1432+
if(NOT EXISTS "${_edited_jp2}")
1433+
message(FATAL_ERROR
1434+
"metatransfer jp2 edit did not write output\nstdout:\n${_out_jp2_edit}\nstderr:\n${_err_jp2_edit}")
1435+
endif()
1436+
1437+
execute_process(
1438+
COMMAND "${METATRANSFER_BIN}" --no-build-info
1439+
--target-jp2
1440+
--no-xmp
1441+
--no-icc
1442+
--no-iptc
1443+
"${_edited_jp2}"
1444+
RESULT_VARIABLE _rv_jp2_roundtrip
1445+
OUTPUT_VARIABLE _out_jp2_roundtrip
1446+
ERROR_VARIABLE _err_jp2_roundtrip
1447+
)
1448+
if(NOT _rv_jp2_roundtrip EQUAL 0)
1449+
message(FATAL_ERROR
1450+
"metatransfer jp2 roundtrip summary failed (${_rv_jp2_roundtrip})\nstdout:\n${_out_jp2_roundtrip}\nstderr:\n${_err_jp2_roundtrip}")
1451+
endif()
1452+
if(NOT _out_jp2_roundtrip MATCHES "jp2_box Exif count=1")
1453+
message(FATAL_ERROR
1454+
"metatransfer jp2 roundtrip summary missing Exif box summary\nstdout:\n${_out_jp2_roundtrip}\nstderr:\n${_err_jp2_roundtrip}")
1455+
endif()
1456+
13641457
execute_process(
13651458
COMMAND "${METATRANSFER_BIN}" --no-build-info
13661459
--target-webp

0 commit comments

Comments
 (0)