Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preserving metadata #39

Closed
jarodium opened this issue Apr 10, 2021 · 6 comments
Closed

Preserving metadata #39

jarodium opened this issue Apr 10, 2021 · 6 comments

Comments

@jarodium
Copy link

jarodium commented Apr 10, 2021

Hello

I facing a strange issue with VIPS. Here's what i'm doing:

  1. Pickup any image ( between JPG and PNG ).
  2. Copy it to the /tmp/ folder with tempnam().
  3. Add XMP metadata to the temp image using Imagick ( using the profiles functions (setImageProfile/getImageProfile("xmp")) and DomDocument.
  4. Saving the image to the final destination with VIPS.

I use the following when saving the image with VIPS ( see bellow )

  $image =  \Jcupitt\Vips\Image::newFromFile('/tmp/image',['access' => 'sequential']);
  $image->writeToFile($destination.".webp");

I figure that I need to save webp while keeping profile information from the original file ( somehow online exif viewers complain the image doesn't have any ). I have found out that vips has functions to set profile ( "vips_profile_set, function in gate", but the docs show there is no link for it at this time.

Does anyone know a way I can maintain the XMP metadata or write it again into the destination file using only vips? Some servers may not have Imagick with Webp support and I don't want to risk it by opening the file and add XMP again (with Imagemagick), plus I save that extra step.

Thank you in advance.
Best regards

@jcupitt
Copy link
Member

jcupitt commented Apr 10, 2021

Hi @jarodium,

You can set XMP on an image like this:

#!/usr/bin/php
<?php

require __DIR__ . '/vendor/autoload.php';
use Jcupitt\Vips;

$im = Vips\Image::newFromFile($argv[1], ["access" => "sequential"]);

# set some xmp metadata
# you must make a private copy of the image before you modify metadata 
$im = $im->copy();
$blob_type = Vips\Utils::typeFromName("VipsBlob");
$im->setType($blob_type, "xmp-data", "some xmp metadata");

$im->writeToFile($argv[2]);

I can run like this:

$ ./add-xmp.php ~/pics/k2.jpg x.webp

And I see XMP on the output image:

$ vipsheader -a x.webp
x.webp: 1450x2048 uchar, 3 bands, srgb, webpload
width: 1450
height: 2048
bands: 3
format: uchar
coding: none
interpretation: srgb
xoffset: 0
yoffset: 0
xres: 1
yres: 1
filename: x.webp
vips-loader: webpload
exif-data: 186 bytes of binary data
resolution-unit: in
exif-ifd0-Orientation: 1 (Top-left, Short, 1 components, 2 bytes)
exif-ifd0-XResolution: 72009/1000 (72.009, Rational, 1 components, 8 bytes)
exif-ifd0-YResolution: 72009/1000 (72.009, Rational, 1 components, 8 bytes)
exif-ifd0-ResolutionUnit: 2 (Inch, Short, 1 components, 2 bytes)
exif-ifd0-YCbCrPositioning: 1 (Centered, Short, 1 components, 2 bytes)
exif-ifd2-ExifVersion: Exif Version 2.1 (Exif Version 2.1, Undefined, 4 components, 4 bytes)
exif-ifd2-ComponentsConfiguration: Y Cb Cr - (Y Cb Cr -, Undefined, 4 components, 4 bytes)
exif-ifd2-FlashpixVersion: FlashPix Version 1.0 (FlashPix Version 1.0, Undefined, 4 components, 4 bytes)
exif-ifd2-ColorSpace: 65535 (Uncalibrated, Short, 1 components, 2 bytes)
exif-ifd2-PixelXDimension: 1450 (1450, Long, 1 components, 4 bytes)
exif-ifd2-PixelYDimension: 2048 (2048, Long, 1 components, 4 bytes)
orientation: 1
xmp-data: 17 bytes of binary data

The docs are here:

https://libvips.github.io/php-vips/docs/classes/Jcupitt-Vips-Image.html#method_setType

@jarodium
Copy link
Author

jarodium commented Apr 10, 2021

Hello @jcupitt

Thank you very much.
I don't suppose there is a getType for xmp data, wouldn't it? At least in the docs I don't see it.
That way I can kiss imagick goodbye xD

I will fiddle with this and let you know how did it turned out.
In the mean time I will close this issue.

Once again
Thanks xD

@jcupitt
Copy link
Member

jcupitt commented Apr 10, 2021

Do you mean you want to read XMP from an image? Sure, use get, eg.:

#!/usr/bin/php
<?php

require __DIR__ . '/vendor/autoload.php';
use Jcupitt\Vips;

$im = Vips\Image::newFromFile($argv[1], ["access" => "sequential"]);

# print existing xmp metadata, if any
if ($im->typeOf("xmp-data") != 0) {
  echo "xmp metadata detected\n";
  $data = $im->get("xmp-data");
  echo "xmp-data = '$data'\n";
}

# set some xmp metadata
# you must make a private copy of the image before you modify metadata 
$im = $im->copy();
$blob_type = Vips\Utils::typeFromName("VipsBlob");
$im->setType($blob_type, "xmp-data", "some more xmp metadata");

$im->writeToFile($argv[2]);

@jarodium
Copy link
Author

jarodium commented Apr 15, 2021

Hello @jcupitt

Your code is working.
Had some issues with the web environment, but since I reloaded apache and make sure vips.ini was there in the modules loaded, this code is working.

Thank you once again for your help.

@jarodium
Copy link
Author

Hello @jcupitt

I was making some tests with this code:

for ($i=1; $i<=4; $i++) {

        $metadata = uniqid();

        echo "Attempt $i :<br>";
        echo "writing $metadata<br>";

        $im = Jcupitt\Vips\Image::newFromFile("downloads/teste.webp", ["access" => "sequential"]);
        $im = $im->copy();
        
        $blob_type = Jcupitt\Vips\Utils::typeFromName("VipsBlob");
        $im->setType($blob_type, "xmp-data", $metadata);
        $im->writeToFile("downloads/teste.webp");


        if ($im->typeOf("xmp-data") != 0) {
                echo "xmp metadata detected<br>\n";
                $data = $im->get("xmp-data");
                echo "xmp-data = '$data'\n";
        }
}

My goal is to write metatada to the same file that I opened, so I figured, using your code above, that I would overwrite the file.

The problem is that the image is becoming corrupted ( 0 bytes size ) and, i'm not sure if this is due to the fact we now have to make copy() or if Vips is still "holding" the working image and any attempts to write will corrupt it.

I've also tried to remove copy() from the code, but still I get corruption.

The loop is intended to check if the file has updated the metadata from the file, since I will be using a CMS to update the file's metadata ( and present it in the website, like a caption for example ).

Error message follows:

Attempt 1 :
writing 6079856cb50ad
Fatal error: Uncaught Jcupitt\Vips\Exception: VipsForeignLoad: "downloads/teste.webp" 
is not a known file format in /var/www/html/backoffice/vendor/jcupitt/vips/src/Image.php:778 Stack trace: #0 
/var/www/html/backoffice/vendor/jcupitt/vips/src/Image.php(801): Jcupitt\Vips\Image::errorVips() [X]1 
/var/www/html/backoffice/vendor/jcupitt/vips/src/Image.php(879): Jcupitt\Vips\Image::errorIsArray(-1) [X]2 
/var/www/html/backoffice/_teste.php(20): Jcupitt\Vips\Image::newFromFile('downloads/teste...', Array) [X]3 {main} 
thrown in /var/www/html/backoffice/vendor/jcupitt/vips/src/Image.php on line 778

When I run your code (write with a php script, read with another script ) separately, it works well.

I'm using an webp file from here

One course of action is to copy the file to another file, and then remove the working image and copy the new one over the working image.

I will check if I have the same issue with png and jpg files and update this ticket.

Also, I would like to take this chance to ask these questions:

  1. Is there, or will be, a removeType? I think setType with a null should work or I could take a look at the remove('xmp-data') from the docs.

  2. Does you xmp-metatada writing code adds to, or overwrites the previous metadata on the file?

Best regards

@jarodium jarodium reopened this Apr 16, 2021
@jcupitt
Copy link
Member

jcupitt commented Apr 16, 2021

You can't read from and write to the same file. libvips is a streaming library, so the read doesn't actually happen until after the write starts.

Yes, you can $im->remove("xmp-data");, check the docs:

https://libvips.github.io/php-vips/docs/classes/Jcupitt-Vips-Image.html#method_remove

Yes, setting a value replaces the old value. It's just like a hash table or associative array.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants