Jump to content

don't want create images with GD-lib, - and some more needs


horst
 Share

Recommended Posts

Hhm, I don't want use the GD2-lib at some point because it lacks in quality.

Also I want to add Metadata (IPTC, XMP, ...) back to resized images. (It's just curious, I'm not aware of any CMS, Blog or even webdriven Photogallery that takes care of this!)

I need to know a way how to bypass PW-internal image-sizing. This must not be necessary for a complete PW-site, but possibly could.

It is mandatory for images added to a specific Part (Template? / Gallery?) of the site.

I want to:

- read Metadata

- resize image with alternate ImageProcessor

- write back Metadata

Any ideas or starting points for this?

To be more clear: I know how to do the image-processing, but not how to integrate the alternate process into PW.

Link to comment
Share on other sites

I think the biggest hurdle here is that the GD2 functions are hardcoded into /core/ImageSizer.php

What you might want to do is see if you can edit that to use something else (I'm guessing you might be thinking of something like ImageMagick?) on a test installation and then if that works out then I guess (lots of guessing) ryan would need to abstract that class and still have so that GD2 is the default and any alternatives can be downloaded as additional modules that override it.

I think that's how it could work, but to get started I think editing that file how you like to see what you can achieve would be good :)

Link to comment
Share on other sites

ok, I've had already copied the ImageSizer.php
 
ImageMagick I never have used. All what I've heard about is that there are many Versions out with different Bugs. And it uses much memory and cpu.
 
I've worked with the NETPBM some time ago and it produces very good results. It is a set of commandline apps what one has to pipe together.

Link to comment
Share on other sites

I've always had good luck with ImageMagick, but didn't implement it in ProcessWire because it's not near as universal as GD2 and requires an exec(), which is something I didn't want the core to rely on. But would totally support inclusion of other libraries for resizing. Admittedly, I've been pretty happy with the quality of GD2's output (at least, after tweaking the quality settings), but if there are visible quality or size benefits to NETPBM or ImageMagick then it would seem to make sense. 

Attached is the ImageSizerInterface. If you make your NETPBM class implement this interface, then I can convert ImageSizer to be an injected dependency, enabling the image sizer library to be configurable per installation. The crop options are a relatively recent addition, and I don't think that many people are using them or know about them, so if difficult to implement, they aren't crucial to have at this point. 

ImageSizerInterface.php

  • Like 1
Link to comment
Share on other sites

Short info about progress:
I've setup a test with nearly 30 very different images:
 
downsized from original dimensions to 1200, 700, 300 px in one step
 
and for following qualities: 100, 96, 93, 90, 85, 80
 
there are no differences in filesize or they are less than 1%
 
to my surprise the quality of GD2 is much better than I have had in mind (maybe I've remembered the GD1 ??, - to my apologize: I've done all image processing locally with Photoshop for the last - ?? - oh god, it seems to be true: for the last 6-7 years)
 
In very dark parts of images both libs show good differences with details, also details of highkey parts are nearly equal with both image processors. Only the sharpness of Netpbm is a little bit better than with GD. But it's that little that it is hard to see when placing to images besides. (when switching in an imageviewer one can see it).

(a table comparing imagesizes is here)

---


intermediate conclusion: I will focus on GD2 and do some tests with sharpening and multi-step-sizing,
also high prior is on Metadata reading and writing
on schedule with less prior maybe Watermarking with alpha-transparency-png.
 
I think, best way to writeback metadata is to build a module that hooks in before image-size process starts and once again after image-sizer has finished:

  public function init() {
    $this->addHook('WHAT IS THE RIGHT HOOK FOR THIS?', $this, 'readMetadata');
    $this->addHookAfter('AND FOR THIS?', $this, 'writeMetadata');
  }

Is this the right way? And if yes, how are the names for the HOOKs?
Any advice is welcome. :)

  • Like 1
Link to comment
Share on other sites

One option I would like to see is support for imagemagick through the pecl imagick package. It gets around the need for exec and gives all the power of imagemagick. And if the server has IM compiled with rsvg it does a fantastic job of handling and rasterizing vector images.

Link to comment
Share on other sites

@horst: like Soma pointed out above, there are no hookable methods in ImageSizer at the moment. Obvious solution would be to make ImageSizer resize method hookable. So far Ryan has added these in various cases based on proper use cases, so you might want to ask for that :)

Taking things a bit further, I've never really needed image metadata for anything (it just hasn't been relevant to what I've been doing, I'm not a photographer and have never developed a proper gallery of any kind), but if this is something that a lot more people would use and benefit from then it might make sense to consider it as a core addition. Perhaps something similar to what you see in PageImage right after resize call; check a config option and act accordingly?

Just thinking out loud.

By the way, PHP's exif_read_data() only reads one metadata format, while other libraries attempt to support many others too. This area seems to be kind of fragmented, with many vendors having their own "standards", or am I just misjudging things based on a few minutes of research? :)

Link to comment
Share on other sites

...

Taking things a bit further, I've never really needed image metadata for anything (I'm in no way against this, these just haven't been relevant to what I've been doing, I'm not a photographer and haven't ever really developed a proper gallery of any kind), but if this something that a lot more people would use and benefit from then it might make sense to consider it as a core addition. Perhaps something similar to what you see in PageImage right after resize call; check a config option and act accordingly?

In short: every serious photographer tags his work in his workflow but at least the public files. For this, before 2004, there was only the IPTC-Standard. In 2004 Adobe starts to take this over in its own featured XMP-format. IPTC is now integrated in XMP as IPTC-core and IPTC-extended whereas the older IPTC-Marker can/will be used in parallel, - what has confused a lot of workflow setups. In PHP-world the common workaround was / is to strip out every metadata (XMP, EXIF, IPTC) and only writeback into the older IPTC-Marker. This way all further readers, incl. Adobe's, get same infos.

By the way, PHP's exif_read_data() only reads one metadata format, while other libraries attempt to support many others too. This area seems to be kind of fragmented, with many vendors having their own "standards", or am I just misjudging things based on a few minutes of research? :)

This is right. As I've pointed to above, most of these standards are not of interest in serious image business. for me all Exifdata (without the copyright notice) is rubbish ;)

You have already pointed to the PHP-JPEG-Metadata-Toolkit what I would use for a 'big solution' whereas a small solution only needs internal PHP-functions. Combined solution could be: reading with Metadata Toolkit and writeback most important (merged) data only to IPTC-Marker. (reduces filesize, especially with small output length)

  • Like 1
Link to comment
Share on other sites

I have also used The PHP JPEG Metadata Toolkit and found it very useful for both reading and writing.

Imagemagick actually maintains metadata during image manipulations, although the requirement for exec or the PECL imagick package are still important considerations. 

So, in the end, I wonder if making use of the toolkit in a module to automatically add the metadata back in for thumbnails might be the easiest way to support this functionality for the most number of PW installs (ie hosted servers without IM).

Link to comment
Share on other sites

Actually, I think a module that allows for extracting the metadata, storing it in the database, and making it editable in the PW admin (in an expandable section below the description field) would be awesome. Any changes here could be written back to the image on save. Now if only we could get Google to stop stripping out metadata and actually read it for indexing purposes.... 

Link to comment
Share on other sites

Making ImageSizer::resize hookable seems like it's a good idea for this need. I will go ahead and make it a hookable method and should appear in the dev branch after I test a bit. 

  • Like 1
Link to comment
Share on other sites

Hi, have started to create the module, but don't get it right.

To start, I use:

	$this->addHookBefore('ImageSizer::resize', $this, 'read_metadata');
	$this->addHookAfter('ImageSizer::resize', $this, 'write_metadata');

With first tests I upload images, the hooks get called. With read_metadata I want to check if the current image is a jpeg. I try to read from $event->object->imageType like this:

public function read_metadata( HookEvent $event ) {
	$this->img = $event->object;
	$this->isOurJob = $this->img->imageType == IMAGETYPE_JPEG ? true : false;
	if( ! $this->isOurJob ) {
		return;
	}
        $filename = $event->object->filename;  // test to assign string to my var
	// ...
	$this->logActivity('have read metadata from ' . $this->img->filename );
}

I have also tried others like $event->data['object']->imageType etc. but I'm always get empty results.

Same behave with $event->object->filename: in my Editor I can see that there is the filename but it did not get assigned to my vars.

So, what I'm missing? :'(

Link to comment
Share on other sites

Is there $this->img->imageType property? There definitely should be filename though.

Check what kind of object there is coming from $event->object?

get_class($event->object);

it is class 'ImageSizer'!

Link to comment
Share on other sites

Hi, - yes it should! But it doesn't! I went a bit mad about that.
 
So, as I have no idea of what is special with PW or how it works, it maybe not very helpful when I try to debug it, but I have done it.
 
Hopefully you (or Ryan!!) may understand a bit of what I try to tell:
 
when try to assign:  $this->img = $event->object; (I step into here with debugger and list next steps with data now):

  • WireData  __get($key)    $key  is  'object' of type string
  • WireData  get($key)                        "

after that $this->img holds reference to ImageSizer == correct

now try to assign:  $filename = $this->img->filename; :

  1. Wire  __get($name)        $name   is filename of type string
     
  2. ... if($this->useFuel($useFuel)     is null ??   is this right here ??  however: it returns TRUE
     
  3. next step is:  Fuel __get($key)    $key is  "filename"  of type string

    and the function trys to return  $this->data[$key] or NULL

    whereas $this->data is array with 20 keys like: config, wire, notices, sanitizer, db, modules, fieldtypes, etc etc but no 'filename'
     
  4. so, finally i get NULL returned

This seems not to be correct at this point. attached is a screenshot of Call-Stack

Link to comment
Share on other sites

Well the imageType and filename property is protected in the imageSizer class. That's why.

ok, - fine. My skills with PHP5 are not that great. Don't know really what I've thought when viewing ImageSizer-Class?! Maybe something like: when hooking into it I can use it like the original :wacko:

I use PHP4 for about 10 years with CLI-scripts, but PHP5 is new to me.

So, have set it from protected to public and now I can read them.

Thanks! :-)

Link to comment
Share on other sites

Horst, do you need to modify imageType and filename, or just need read access to them? The best way to handle this is with getters/setters, which I can add to the class. But just wanted to make sure I understood the need. 

Link to comment
Share on other sites

Horst, do you need to modify imageType and filename, or just need read access to them? The best way to handle this is with getters/setters, which I can add to the class. But just wanted to make sure I understood the need. 

Hi Ryan, only need read-access to:

  $filename

  $extension

  $imageType

  $image

  $modified

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...