-
Notifications
You must be signed in to change notification settings - Fork 529
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
[FEATURE] Introduce image metadata #266
Conversation
* {@inheritdoc} | ||
*/ | ||
public function __construct(ImageInterface $image) { | ||
$exifData = exif_read_data('data://image/jpeg;base64,' . base64_encode($image->get('jpg'))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe better defer reading the exif data until actually needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@staabm the AbstractImage is instantiating the ExifMetadata only when you retrieve it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually it is only needed when getOrientation
is called not yet when this object is created
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@stof got it right at least as far as I intended how it should work; the problem with a getOrientation
lazy-load is IMO the fact that it's rather unnice, because when later that model matures, with other getters, you would need an initialization step every time.
But I'll push a follow-up with that.
I think the metadata should be reset when the image gets modified. and it should also be reset when cloning |
Oh, and please fix the coding standards according to PSR-2 (the PHP-CS-Fixer tool should be able to fix most of it for you) |
@stof ,
ok, will do. |
This introduces `metadata` as a gettable property of the `ImageInterface` and its implementations, in order to carry initial image metadata along the lifecycle. The distributed implementation determines the metadata by the image's EXIF information, but it not limited to this in the future. This is a preparation for #222 and related to #190.
@stof, I decided to not reset it on cloning and modifying, but to clone the metadata if the image itself is cloned. |
Just back to keyboard, I need a bit time to review this, thanks for your contribution ! |
Well, I do think metadata should be key/value informations about the state of the image when opening it. I've also a note about reading metadata from with I was thinking about reading metadata before the What's your opinion about this ? |
Argh now I know why I had it designed that way on the first draft: exactly that's why ;) So, since I initially intended to prepare most on constructing, I'm 👍 on that. |
If the file is a filesystem file : To avoid this kind of overhead in case exif metadata are not used at all, we could think about a metadata load strategy with a default implementation to a BasicMetadataStrategy that would not perform any call on image constructor, just get a file path for example. |
yes of cource; but that would mean we unfortunately have to add that to every implementation of I actually wanted to implement a (//edit: btw, why is the IRC channel that empty? :-( ) |
Updating \Imagine\Image\ImagineInterface::open, ::load and ::read is not a problem as default strategy would be seamless (only load the filepath (if provided) as the only metadata). Are you okay to work on such strategy implementation ? |
@romainneutron but what would decide what actual loading strategy to use, or, whether exif or "not"? |
I've propose a MetadataReaderInterface in https://github.com/afoeder/Imagine/pull/1 This solves the issues mentioned above. Using exif metadata reader is easy :
A reader returns a MetadataBag that implements ArrayAccess and is injected at image construction. Feedback appreciated |
*/ | ||
protected function initialize() | ||
{ | ||
$exifData = exif_read_data('data://image/jpeg;base64,' . base64_encode($this->image->get('jpg'))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in case the image is big, this will use a lot of memory (base64 will use 33% more memory than the image has in size).
Would it make sense to dump the image to a file (if it is not already one) and let exif_read_data
read from the file? This would not eat php's memory, but might be slower.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
another alternative would be to use a stream-filter for base64-encoding. this will help against memory limitations without the need to dump the file.. use something like the following with an in-memory stream:
stream_filter_append($fh, 'convert.base64-encode');
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep, that's right.
I've propose an enhancement on top of this PR (see https://github.com/afoeder/Imagine/pull/1) that address this comment (in case ImagineInterface::open
is used)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your proposition is smart. I'll fix my PR with it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@staabm I've tried your proposition, but as long as exif_read_data
does not accept streams, the data URI must be computed before calling this function. I can't figure how we could you stream_filter_append
as you mentioned. See :
$stream = fopen('php://memory','r+');
fwrite($stream, $data);
rewind($stream);
stream_filter_append($stream, 'convert.base64-encode', STREAM_FILTER_READ);
exif_read_data('data://image/jpg;base64,' . stream_get_contents($stream));
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@evert any idea whats going on in the example above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using the stream filter doesn't make much sense here. You're not saving any memory by letting a stream filter do the encoding, rather than base64 encode, because the input ($data
) and the output (the data://
url) are still strings.
However, i think the reason the stream filter is failing, is because you probably need to use STREAM_FILTER_WRITE
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ohhh right, it won't save memory until exif_read_data
will accept a stream.... Will try your fix nevertheless, thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tested it now and it works when used like this:
$data = str_repeat('lalaaaa', 5000);
$stream = fopen('php://memory','r+');
stream_filter_append($stream, 'convert.base64-encode', STREAM_FILTER_WRITE);
fwrite($stream, $data);
rewind($stream);
var_dump(stream_get_contents($stream));
I measured memory consumption with the teststring $data = str_repeat('lalaaaa', 5000);
and it seems that using the in-memory stream consumes even more memory - I think mainly because of the buffer not beeing free'd yet.
To put it into a nutshell: atm there is no benefit when using streams here. I would leave it as is, until exif_read_data
supports streams or someone encounters the problem of insufficient memory and then one could reconsider using a tempfile for this to cut memory consumption by ~75%
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm available for contract work to write a pure-php implemenation for reading exif data using streams ;) should be no more than 5 hours
@afoeder What's the status on this PR, I don't find you fork on your profile. Did you gave up ? Can I re-open this PR on my account and finish what we begin ? |
@romainneutron yes, I somehow gave up since I had no actual clue how you meant it to be implemented; and, I seem to have unlearnt how to use vanilla PHP with things like finding interface implementors, DI etc... |
I did a PR on your repo weeks ago. |
yep, sure! |
Replaced by #304 |
This introduces
metadata
as a gettable property ofthe
ImageInterface
and its implementations, in orderto carry initial image metadata along the lifecycle.
The distributed implementation determines the metadata
by the image's EXIF information, but it not limited to
this in the future.
This is a preparation for #222 and related to #190.