aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRalph Amissah <ralph.amissah@gmail.com>2026-08-26 22:44:05 -0400
committerRalph Amissah <ralph.amissah@gmail.com>2026-08-28 10:02:05 -0400
commitb2aaf09e46d6c7450311c5f684f3d811521b3ad1 (patch)
tree8c80691b95e77286fa694af858db39360a7ca01b
parent.ssp digests: report missing or unreadable image (diff)
.ssp digest: add image file's own pixel dimensions
Complete image file digest identity record: add px:<width>x<height> to the .ssp image record, read from the image file header (imageformats.read_image_info, no decode): .image: won_benkler_2_1.png sha256:5BA4...D128 bytes:93861 px:420x342 (The w##h## dimensions in the markup are display dimensions, not the file's: they are author set, or where given as w0h0 are derived by _image_dimensions and capped to a maximum display width, and they become the width/height attributes of the output format image display). (assisted by Claude-Code)
-rw-r--r--org/ocda_functions.org18
-rw-r--r--org/ocda_obj_setter.org2
-rw-r--r--org/out_src_abstraction_ocda_ssp.org18
-rw-r--r--src/sisudoc/ocda/abstraction/ssp.d18
-rw-r--r--src/sisudoc/ocda/meta/metadoc_from_src_functions.d18
-rw-r--r--src/sisudoc/ocda/meta/metadoc_object_setter.d3
6 files changed, 67 insertions, 10 deletions
diff --git a/org/ocda_functions.org b/org/ocda_functions.org
index 4745bc5..71d1b97 100644
--- a/org/ocda_functions.org
+++ b/org/ocda_functions.org
@@ -3448,6 +3448,24 @@ SHA_256_Hashes_ obj_digest(M)(
writeln("WARNING, image not found or unreadable: ", filename,
"\n ", file_with_path);
}
+ /+ ↓ the image file's own pixel dimensions, which are not the display
+ dimensions carried by the markup (w##h##): those are author set, or
+ where given as w0h0 are derived by _image_dimensions and capped to
+ a maximum display width. Header read only, no decode.
+ +/
+ if (!_file_info.fileMissing) {
+ import imageformats;
+ int _w, _h, _chans;
+ try {
+ read_image_info(file_with_path, _w, _h, _chans);
+ _file_info.imageWidth = _w;
+ _file_info.imageHeight = _h;
+ } catch (Exception ex) {
+ debug(images) {
+ writeln("image dimensions not read: ", filename);
+ }
+ }
+ }
return _file_info;
}
obj.metainfo.sha256.text = obj.text.sha256Of;
diff --git a/org/ocda_obj_setter.org b/org/ocda_obj_setter.org
index 8e7a67c..f16e133 100644
--- a/org/ocda_obj_setter.org
+++ b/org/ocda_obj_setter.org
@@ -54,6 +54,8 @@ struct ST_file_name_hash_size_ {
ubyte[32] fileHash_sha256;
ulong fileSize;
bool fileMissing = false; // file not found or unreadable, fileHash_sha256 & fileSize unset
+ int imageWidth = 0; // actual pixel dimensions of the
+ int imageHeight = 0; // file, not the display dimensions carried in the markup (w##h##)
}
struct SHA_256_Hashes_ {
char[] summary;
diff --git a/org/out_src_abstraction_ocda_ssp.org b/org/out_src_abstraction_ocda_ssp.org
index d2bb8a4..64af5cc 100644
--- a/org/out_src_abstraction_ocda_ssp.org
+++ b/org/out_src_abstraction_ocda_ssp.org
@@ -268,10 +268,13 @@ template spineAbstractionTxt() {
}
}
/+ ↓ images, repeatable record, one per image in order of appearance:
- .image: <filename> sha256:<HEX> bytes:<n>
- filename first (the object's handle on the image), remaining fields
- self-describing key:value tokens so that further fields (e.g. dim:)
- can be added later without invalidating existing readers
+ .image: <filename> sha256:<HEX> bytes:<n> px:<width>x<height>
+ .image: <filename> missing:true
+ filename first (the object's handle on the image), remaining fields
+ self-describing key:value tokens so that further fields can be
+ added later without invalidating existing readers. px: is the
+ file's own pixel size, not the display dimensions (w##h##) which
+ the object text already carries
+/
if (obj.metainfo.sha256.images.length > 0) {
foreach (i; obj.metainfo.sha256.images) {
@@ -280,7 +283,12 @@ template spineAbstractionTxt() {
~ " missing:true"
: ".image: " ~ i.fileName
~ " sha256:" ~ i.fileHash_sha256.toHexString.to!string
- ~ " bytes:" ~ i.fileSize.to!string;
+ ~ " sha256:" ~ i.fileHash_sha256.toHexString.to!string
+ ~ " bytes:" ~ i.fileSize.to!string
+ ~ ((i.imageWidth > 0 && i.imageHeight > 0)
+ ? " px:" ~ i.imageWidth.to!string
+ ~ "x" ~ i.imageHeight.to!string
+ : "");
}
}
/+ ↓ text attributes +/
diff --git a/src/sisudoc/ocda/abstraction/ssp.d b/src/sisudoc/ocda/abstraction/ssp.d
index ea76d71..25cc467 100644
--- a/src/sisudoc/ocda/abstraction/ssp.d
+++ b/src/sisudoc/ocda/abstraction/ssp.d
@@ -286,10 +286,13 @@ template spineAbstractionTxt() {
}
}
/+ ↓ images, repeatable record, one per image in order of appearance:
- .image: <filename> sha256:<HEX> bytes:<n>
- filename first (the object's handle on the image), remaining fields
- self-describing key:value tokens so that further fields (e.g. dim:)
- can be added later without invalidating existing readers
+ .image: <filename> sha256:<HEX> bytes:<n> px:<width>x<height>
+ .image: <filename> missing:true
+ filename first (the object's handle on the image), remaining fields
+ self-describing key:value tokens so that further fields can be
+ added later without invalidating existing readers. px: is the
+ file's own pixel size, not the display dimensions (w##h##) which
+ the object text already carries
+/
if (obj.metainfo.sha256.images.length > 0) {
foreach (i; obj.metainfo.sha256.images) {
@@ -298,7 +301,12 @@ template spineAbstractionTxt() {
~ " missing:true"
: ".image: " ~ i.fileName
~ " sha256:" ~ i.fileHash_sha256.toHexString.to!string
- ~ " bytes:" ~ i.fileSize.to!string;
+ ~ " sha256:" ~ i.fileHash_sha256.toHexString.to!string
+ ~ " bytes:" ~ i.fileSize.to!string
+ ~ ((i.imageWidth > 0 && i.imageHeight > 0)
+ ? " px:" ~ i.imageWidth.to!string
+ ~ "x" ~ i.imageHeight.to!string
+ : "");
}
}
/+ ↓ text attributes +/
diff --git a/src/sisudoc/ocda/meta/metadoc_from_src_functions.d b/src/sisudoc/ocda/meta/metadoc_from_src_functions.d
index 6e4aec3..6a000ea 100644
--- a/src/sisudoc/ocda/meta/metadoc_from_src_functions.d
+++ b/src/sisudoc/ocda/meta/metadoc_from_src_functions.d
@@ -3208,6 +3208,24 @@ template docAbstractionFunctions() {
writeln("WARNING, image not found or unreadable: ", filename,
"\n ", file_with_path);
}
+ /+ ↓ the image file's own pixel dimensions, which are not the display
+ dimensions carried by the markup (w##h##): those are author set, or
+ where given as w0h0 are derived by _image_dimensions and capped to
+ a maximum display width. Header read only, no decode.
+ +/
+ if (!_file_info.fileMissing) {
+ import imageformats;
+ int _w, _h, _chans;
+ try {
+ read_image_info(file_with_path, _w, _h, _chans);
+ _file_info.imageWidth = _w;
+ _file_info.imageHeight = _h;
+ } catch (Exception ex) {
+ debug(images) {
+ writeln("image dimensions not read: ", filename);
+ }
+ }
+ }
return _file_info;
}
obj.metainfo.sha256.text = obj.text.sha256Of;
diff --git a/src/sisudoc/ocda/meta/metadoc_object_setter.d b/src/sisudoc/ocda/meta/metadoc_object_setter.d
index 7abde64..a88f491 100644
--- a/src/sisudoc/ocda/meta/metadoc_object_setter.d
+++ b/src/sisudoc/ocda/meta/metadoc_object_setter.d
@@ -105,6 +105,9 @@ template ObjectSetter() {
string fileName;
ubyte[32] fileHash_sha256;
ulong fileSize;
+ bool fileMissing = false; // file not found or unreadable, fileHash_sha256 & fileSize unset
+ int imageWidth = 0; // actual pixel dimensions of the
+ int imageHeight = 0; // file, not the display dimensions carried in the markup (w##h##)
}
struct SHA_256_Hashes_ {
char[] summary;