Math ops for Resolution tags

Started by mazeckenrode, February 01, 2021, 04:14:57 PM

Previous topic - Next topic

mazeckenrode

This is more experimentation than necessity, but I'm looking for a way to write as many of the following tags as possible, as applicable, based on one set of input values, which might be 2 = inches and 600, for example:

EXIF:ResolutionUnit
EXIF:XResolution
EXIF:YResolution
XMP:ResolutionUnit
XMP:XResolution
XMP:YResolution

JFIF:ResolutionUnit
JFIF:XResolution
JFIF:YResolution

PNG:PixelUnits
PNG:PixelsPerUnitX
PNG:PixelsPerUnitY


The EXIF and XMP tags are easy enough, as they accept my input values as-are.

JFIF is throwing me for a loop, as when I feed it 600 for XResolution and YResolution, it apparently writes 300. Both tags are defined as int16u, which, as far as I can tell, means they should accept any integer value up to 32,767, right? Am I doing something wrong?

The PNG tags are another animal yet, as the only valid unit values are 0 = Unknown or 1 = meters, so I'd have to perform a calculation on my input value of 600 to get something acceptable for use in PixelsPerUnitX/Y. The basic calulation would be 600 ÷ 0.0254 = 23,622.047244094488188976377952756, so I'd also need to get that rounded to the nearest integer (preferred), or just lose the decimal portion (can live with it if I have to).

In a search for examples of math calculations in ExifTool command lines in the forums here, I see some in which calculations are performed on values taken from existing tags, but that wouldn't be the case for my purposes. My minimal, basic research into Perl math functions tells me that int() would ordinarily be used to truncate the decimal portion of a value, and sprint() would be used to round a value. Can I perform the necessary calculation within an ExifTool command line, and if so, can someone show me what that would look like?

StarGeek

Quote from: mazeckenrode on February 01, 2021, 04:14:57 PM
JFIF is throwing me for a loop, as when I feed it 600 for XResolution and YResolution, it apparently writes 300. Both tags are defined as int16u, which, as far as I can tell, means they should accept any integer value up to 32,767, right? Am I doing something wrong?

I'm not sure why it isn't working for you.  It's sets accurately to 600 here, though I am getting a bit tricky in how I set it.
C:\>exiftool -P -overwrite_original -jfif:?Resolution=600 -exif:?Resolution=600 -xmp:?Resolution=600 y:\!temp\Test4.jpg
    1 image files updated

C:\>exiftool -g1 -a -s -?resolution y:\!temp\Test4.jpg
---- JFIF ----
XResolution                     : 600
YResolution                     : 600
---- IFD0 ----
XResolution                     : 600
YResolution                     : 600
---- XMP-tiff ----
XResolution                     : 600
YResolution                     : 600


QuoteThe basic calulation would be 600 ÷ 0.0254 = 23,622.047244094488188976377952756, so I'd also need to get that rounded to the nearest integer (preferred), or just lose the decimal portion (can live with it if I have to).

That's a bit trickier, as you can't put arbitrary code as part of setting a static value.  But you can get tricky and make a tag with the -userParam option and then do operations on that.  I used 150 resolution so I can show rounding options
C:\>exiftool -P -overwrite_original -userparam MyPixels=150 "-PixelsPerUnit?<${MyPixels;$_/=0.0254;$_=int($_)}"  y:/!temp/x.png
    1 image files updated

C:\>exiftool -g1 -a -s -PixelsPerUnit?  y:/!temp/x.png
---- PNG-pHYs ----
PixelsPerUnitX                  : 5905
PixelsPerUnitY                  : 5905

C:\>exiftool -P -overwrite_original -userparam MyPixels=150 "-PixelsPerUnit?<${MyPixels;$_/=0.0254;$_=int($_+.5)}"  y:/!temp/x.png
    1 image files updated

C:\>exiftool -g1 -a -s -PixelsPerUnit?  y:/!temp/x.png
---- PNG-pHYs ----
PixelsPerUnitX                  : 5906
PixelsPerUnitY                  : 5906

C:\>exiftool -P -overwrite_original -userparam MyPixels=150 "-PixelsPerUnit?<${MyPixels;sprintf('%d',$_/=0.0254)}"  y:/!temp/x.png
    1 image files updated

C:\>exiftool -g1 -a -s -PixelsPerUnit?  y:/!temp/x.png
---- PNG-pHYs ----
PixelsPerUnitX                  : 5906
PixelsPerUnitY                  : 5906


"It didn't work" isn't helpful. What was the exact command used and the output.
Read FAQ #3 and use that cmd
Please use the Code button for exiftool output

Please include your OS/Exiftool version/filetype

mazeckenrode

Quote from: StarGeek on February 01, 2021, 04:41:41 PM
I'm not sure why it isn't working for you. It's sets accurately to 600 here, though I am getting a bit tricky in how I set it.

My original command line attempt, which resulted in JFIF:X/YResolution values of 300, was this:

ExifTool -EXIF:ResolutionUnit=inches -EXIF:XResolution=600 -EXIF:YResolution=600 -XMP:ResolutionUnit=inches -XMP:XResolution=600 -XMP:YResolution=600 -JFIF:ResolutionUnit=inches -JFIF:XResolution=600 -JFIF:YResolution=600 .

However, all subsequent attempts, using the same command line or your method, now result in 600. No idea why, but don't change the channel yet...

Quote
But you can get tricky and make a tag with the -userParam option and then do operations on that. I used 150 resolution so I can show rounding options

Everything looks great from your examples — thanks much. When I try a command line based on your third example, substituting 600 for 150, my PNG file does not change. I've tried it multiple times now, with the same results, using this command line:

ExifTool -PNG:PixelUnits=meters -userparam MyPixels=600 "-PNG:PixelsPerUnit?<${MyPixels;sprintf('%d',$_/=0.0254)}" .

Something to with single quote marks and/or single % on Windows maybe? I played around with those, but failed to make it work.

This, based on your first example, did work:

ExifTool -PNG:PixelUnits=meters -userparam MyPixels=600 "-PixelsPerUnit?<${MyPixels;$_/=0.0254;$_=sprintf($_)}"  .

Note, however, that your example used int($_), not sprintf($_), so it's possibly accidental that the command line above wrote the correct values. Haven't worked the nitty gritty out yet, but if you spot anything, I'm all ears.

StarGeek

My examples were using Windows CMD.  If you're using PS, then I think you have to swap double/single quotes.  Also, bat file needs double %.
"It didn't work" isn't helpful. What was the exact command used and the output.
Read FAQ #3 and use that cmd
Please use the Code button for exiftool output

Please include your OS/Exiftool version/filetype

mazeckenrode

I'm also using Windows CMD. I've now found out that this works:

ExifTool -PNG:PixelUnits=meters -userparam MyPixels=600 "-PixelsPerUnit?<${MyPixels;sprintf('%d',$_/=0.0254)}"  .

But neither of these (specifying GROUP or FAMILY 1 GROUP names for the PixelsPerUnit) do:

ExifTool -PNG:PixelUnits=meters -userparam MyPixels=600 "-PNG:PixelsPerUnit?<${MyPixels;sprintf('%d',$_/=0.0254)}"  .

ExifTool -PNG:PixelUnits=meters -userparam MyPixels=600 "-PNG-pHYs:PixelsPerUnit?<${MyPixels;sprintf('%d',$_/=0.0254)}"  .

Why would that be? Bug or unintentional omission? For what it's worth, my preference is to always specify the GROUP name (helps me keep track of what's what when reading or editing my code at a later date), except where leaving it out allows multiple groups tags to be written.

StarGeek

It looks like you can't use a Group names for those tags.  Phil would have to explain why.  There is a note about these tags on the PNG page.
"It didn't work" isn't helpful. What was the exact command used and the output.
Read FAQ #3 and use that cmd
Please use the Code button for exiftool output

Please include your OS/Exiftool version/filetype

mazeckenrode

Quote from: StarGeek on February 01, 2021, 08:48:17 PM
It looks like you can't use a Group names for those tags.

But you can with PixelUnits, which also part of the PNG-pHYs family 1 group.

Quote
There is a note about these tags on the PNG page.

Yep, saw that. And you can delete all three tags by specifying the family 1 group name:

exiftool -PNG-pHYs:All="" .

Phil Harvey

Quote from: StarGeek on February 01, 2021, 08:48:17 PM
It looks like you can't use a Group names for those tags.  Phil would have to explain why.

Interesting.  ExifTool bug.  I'll fix this in the next release.

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

mazeckenrode


mazeckenrode

I've been using the following command (via Directory Opus) without issue since shortly after my last post in this thread four years ago:

ExifTool -progress -echo "Setting resolution of selected JPEG/PNG/TIFF..." -m -EXIF:ResolutionUnit="{$resunit}" -EXIF:?Resolution="{$res}" -XMP:ResolutionUnit="{$resunit}" -XMP:?Resolution="{$res}" -JFIF:ResolutionUnit="{$resunit}" -JFIF:?Resolution="{$res}" -PNG:PixelUnits=meters -userparam MyPixels="{$res}" "-PNG:PixelsPerUnit?<${MyPixels;sprintf('%d',$_/=0.0254)}" {file$}

({$resunit}, {$res} and {file$} are all arguments provided via DOpus, of course.)

As far as I've noticed, just in the last few days this has resulted in the warning:

Redundant argument in sprintf for 'MyPixels'

All of my resolution tags appear to be getting written correctly. I'm currently using ExifTool v13.25, since shortly after it became available. Any idea what the redundant argument is, or why I've only started getting this warning now (assuming it's not a case of my simply having failed to pay attention to the output until now, which I have to admit is a possibility)?

Phil Harvey

I don't know why you're just seeing this warning now, but perhaps unrelated, this expression seems wrong to me:

"-PNG:PixelsPerUnit?<${MyPixels;sprintf('%d',$_/=0.0254)}"

it should be this if you want to use printf

"-PNG:PixelsPerUnit?<${MyPixels;$_=sprintf('%d',$_/0.0254)}"

But why are you using sprintf?  This should do the same thing a bit more efficiently:

"-PNG:PixelsPerUnit?<${MyPixels;$_=int($_/0.0254)}"

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

mazeckenrode

Quote from: Phil Harvey on April 19, 2025, 08:35:03 AMperhaps unrelated, this expression seems wrong to me:

"-PNG:PixelsPerUnit?<${MyPixels;sprintf('%d',$_/=0.0254)}"

That's how its usage for my stated purpose was demonstrated for me in this previous post. It DOES work — the intended resolution tags do get written correctly. Should it not? Is there a compelling reason to change it to your way?

QuoteBut why are you using sprintf?

My understanding, as stated in my first post in this topic, is that int() would ordinarily be used to truncate the decimal portion of a value, and sprint() would be used to round a value. I prefer the latter.

Phil Harvey

The sprintf in that command is doing nothing, and the floating point value is being used, but presumably this is truncated to an integer because of the storage format.  sprintf with %d would truncate to integer anyway.

So I'm saying that this:

"-PNG:PixelsPerUnit?<${MyPixels;sprintf('%d',$_/=0.0254)}"

is actually doing this

"-PNG:PixelsPerUnit?<${MyPixels;$_/=0.0254}"

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).

StarGeek

It looks like exiftool is rounding the value by default
C:\>exiftool -P -overwrite_original -PNG:PixelsPerUnit?=9.4 Y:\!temp\Test4.png
    1 image files updated

C:\>exiftool -G1 -a -s -pixelsper* Y:\!temp\Test4.png
[PNG-pHYs]      PixelsPerUnitX                  : 9
[PNG-pHYs]      PixelsPerUnitY                  : 9

C:\>exiftool -P -overwrite_original -PNG:PixelsPerUnit?=9.5 Y:\!temp\Test4.png
    1 image files updated

C:\>exiftool -G1 -a -s -pixelsper* Y:\!temp\Test4.png
[PNG-pHYs]      PixelsPerUnitX                  : 10
[PNG-pHYs]      PixelsPerUnitY                  : 10
"It didn't work" isn't helpful. What was the exact command used and the output.
Read FAQ #3 and use that cmd
Please use the Code button for exiftool output

Please include your OS/Exiftool version/filetype

Phil Harvey

You're right, ExifTool does round the value when writing an integer.  If the sprintf was used properly with %d then the value would have been truncated.  So if rounding is preferred, the proper command is

"-PNG:PixelsPerUnit?<${MyPixels;$_/=0.0254}"

- Phil
...where DIR is the name of a directory/folder containing the images.  On Mac/Linux/PowerShell, use single quotes (') instead of double quotes (") around arguments containing a dollar sign ($).