Skip to end of metadata
Go to start of metadata

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[

To do:

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[

Zend Framework: Zend_Image Component Proposal

Proposed Component Name Zend_Image
Developer Notes http://framework.zend.com/wiki/display/ZFDEV/Zend_Image
Proposers Dolf Schimmel (Freeaqingme)
David Caunt
Zend Liaison TBD
Revision 1.0 - 1 Oct 2008: Initial Draft.
1.1 - 16 Oct 2008: Finished proposal
1.1 - 10 Jan 2009: Ready for community review
1.2 - 28 Jul 2009: Moved to ready for recommendation (wiki revision: 15)

Table of Contents

1. Overview

Zend_image is a component used for handling images.

Marcin Lulek a.k.a. Ergo2 has written an image component on which this proposal and initial codebase is based. His component does however miss an object oriented interface, and therefore it has been decided to fully refactor it. As for there is already a suitable codebase (preview of its functionality can be found here ; http://webreactor.eu/image/ ), offers of components written by others are unnecessary (appreciated though).

2. References

3. Component Requirements, Constraints, and Acceptance Criteria

  • This component will be able to resize images.
  • This component will be able to rotate images.
  • This component will be able to print a watermarks on images.
  • This component will be able to draw; eclipses, arcs, lines and polygons
  • This component will be able to convert images (I.E. from jpeg to bmp).
  • This component will be able to apply several filters, as well as adjust contrast etc.

4. Dependencies on Other Framework Components

  • GD or ImageMagick
  • Zend_Exception

5. Theory of Operation

An instance of Zend_Image will have one image resource by default. The path of this image can be specified when constructing it. It can however also be loaded from a file or string, or be created by Zend_Image itself. Once a resource has been loaded, the actions on the image can be performed, like cropping, resizing, rotating, etc.

By default Zend_Image will support two adapters, namely Zend_Image_Adapter_Gd and Zend_Image_Adapter_ImageMagick.

6. Milestones / Tasks

  • Milestone 1: Proposal finished (DONE)
  • Milestone 2: Development of prototype started
  • Milestone 3: Proposal approved
  • Milestone 4: Working prototype checked into the incubator.
  • Milestone 5: Unit tests exist, work, and are checked into SVN.
  • Milestone 6: Documentation exists.

7. Class Index

  • Zend_Image
  • Zend_Image_Color
  • Zend_Image_Point
  • Zend_Image_Chain
  • Zend_Image_Adapter_Abstract
  • Zend_Image_Adapter_Gd
  • Zend_Image_Adapter_ImageMagick
  • Zend_Image_Action_DrawLine
  • Zend_Image_Action_DrawEllipse
  • Zend_Image_Action_DrawCircle
  • Zend_Image_Action_DrawArch
  • Zend_Image_Action_DrawText
  • Zend_Image_Action_DrawPolygon
  • Zend_Image_Action_ApplyFilter
  • Zend_Image_Action_AdjustAlpha
  • Zend_Image_Action_Resize
  • Zend_Image_Action_Blend
  • Zend_Image_Action_Rotate
  • Zend_Image_Action_Brightness
  • Zend_Image_Action_Contrast
  • Zend_Image_Action_Colorize
  • Zend_Image_Adapter_Gd_Action_DrawLine
  • Zend_Image_Adapter_Gd_Action_DrawEllipse
  • Zend_Image_Adapter_Gd_Action_DrawCircle
  • Zend_Image_Adapter_Gd_Action_DrawArch
  • Zend_Image_Adapter_Gd_Action_DrawText
  • Zend_Image_Adapter_Gd_Action_DrawPolygon
  • Zend_Image_Adapter_Gd_Action_ApplyFilter
  • Zend_Image_Adapter_Gd_Action_AdjustAlpha
  • Zend_Image_Adapter_Gd_Action_Resize
  • Zend_Image_Adapter_Gd_Action_Blend
  • Zend_Image_Adapter_Gd_Action_Rotate
  • Zend_Image_Adapter_Gd_Action_Brightness
  • Zend_Image_Adapter_Gd_Action_ActionInterface_Contrast
  • Zend_Image_Adapter_Gd_Action_Colorize
  • Zend_Image_Adapter_ImageMagick_Action_DrawLine
  • Zend_Image_Adapter_ImageMagick_Action_DrawEllipse
  • Zend_Image_Adapter_ImageMagick_Action_DrawCircle
  • Zend_Image_Adapter_ImageMagick_Action_DrawArch
  • Zend_Image_Adapter_ImageMagick_Action_DrawText
  • Zend_Image_Adapter_ImageMagick_Action_DrawPolygon
  • Zend_Image_Adapter_ImageMagick_Action_ApplyFilter
  • Zend_Image_Adapter_ImageMagick_Action_AdjustAlpha
  • Zend_Image_Adapter_ImageMagick_Action_Resize
  • Zend_Image_Adapter_ImageMagick_Action_Blend
  • Zend_Image_Adapter_ImageMagick_Action_Rotate
  • Zend_Image_Adapter_ImageMagick_Action_Brightness
  • Zend_Image_Adapter_ImageMagick_Action_Contrast
  • Zend_Image_Adapter_ImageMagick_Action_Colorize

8. Use Cases

UC-01

$options = array('thickness' => 5,
'filled' => true,
'startX' => 10,
'startY' => 15,
'endX' => 50,
'endY' => 125);
$image = new Zend_Image('/path/to/image.png');
$image->draw(Zend_Image::LINE,$options);
$image->save();

UC-02

$line = new Zend_Image_Action_DrawLine();
$line->from(10,15)
->to(new Zend_Image_Point(50,125))
->setFilled(true);
$image = new Zend_Image('/path/to/image.png'); // Autodetect adapter to use
$image->draw($line);
$image->save();

UC-03

$chain = new Zend_Image_Chain();
$line = new Zend_Image_Action_DrawLine();
$line->setcoords(10,15,50,125)->setFilled(true);
$chain->add($line);
$image = new Zend_Image('/path/to/image.png',Zend_Image::GD);
$image->perform($chain);
$image->save();

UC-04

// Create new image;
$image = new Zend_Image();
$image->create(50,20); // X, Y size;

file_put_contents('/path/to/image.png',$image->get()); //
$image->save('/path/to/image.png'); // Both lines do the same

UC-05

$options = array('thickness' => 5,
'filled' => true,
'startX' => 10,
'startY' => 15,
'endX' => 50,
'endY' => 125);
$image = new Zend_Image('/path/to/image.png'); // Autodetect adapter to use
$image->drawLine($options);
$image->save();

9. Class Skeletons

Some code (meant to get an impression of the API, not to get an impression of our coding skills) can be found here: http://framework.zend.com/svn/framework/standard/branches/user/freak/ZendImage/

]]></ac:plain-text-body></ac:macro>

]]></ac:plain-text-body></ac:macro>

Labels:
None
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Oct 03, 2008

    <p>I have created something we use here at work, something that can be conisdered to look like this.</p>

    <p>Zend_Image<br />
    Zend_Image_Adapter<br />
    Zend_Image_Exception extends Zend_Exception<br />
    Zend_Image_Adapter_Abstract<br />
    Zend_Image_Adapter_Exception extends Zend_Exception<br />
    Zend_Image_Adapter_Gd2 extends Zend_Image_Adapter_Abstract<br />
    Zend_Image_Adapter_Imagemagic extends Zend_Image_Adapter_Abstract</p>

    <p>Where the Zend_Image_Adapter_Abstract has these functions</p>

    <ul>
    <li>abstract open($filePath)</li>
    <li>abstract save($destination = null, $newFilename = null, $quality = 90)</li>
    <li>abstract display($quality = 90)</li>
    <li>abstract resize($width = null, $height = null)</li>
    <li>abstract rotate($angle)</li>
    <li>abstract crop($width, $height = null, $xPos = 0, $yPos = null)</li>
    <li>abstract watermark($watermarkImage, $positionX = 0, $positionY = 0, $watermarkImageOpacity = 30, $repeat = false)</li>
    <li>abstract _refreshInfo - used to get width and height</li>
    <li>public preDisplay</li>
    <li>public cropResize($width, $height = null, $xPos = 0, $yPos = null)</li>
    <li>public getWidth</li>
    <li>public getHeight</li>
    <li>public getImageType - returns int, one of the php IMAGETYPE constants</li>
    <li>public getFileBasename</li>
    <li>public getFileSize</li>
    <li>public getFileMimeTypee</li>
    <li>public getHandler</li>
    <li>public setWatermarkPosition</li>
    <li>public getWatermarkPosition</li>
    <li>public setCropPosition</li>
    <li>public getCropPosition</li>
    <li>public setWatermarkWidth</li>
    <li>public getWatermarkWidth</li>
    <li>public setWatermarkHeight</li>
    <li>public getWatermarkHeight</li>
    <li>public setKeepProportion</li>
    <li>protected refreshInfo - gets pathinfo and filesize</li>
    </ul>

    <p>I can send you these files and you can use them as a guide, if you like. We have finished the Gd2 adapter, so there code to review, and more to be written in the Imagemagic adapter.</p>

    <p>plz let me know</p>

  2. Oct 06, 2008

    <p>+1 for Helgi</p>

    <p>I think the work you made so far could be an excellent base for such a Zend_Image component. I'd be really interested in contributing making it become an official ZF component.</p>

    <p>Dolf, Helgi, please don't hesitate to get in touch!</p>

  3. Oct 13, 2008

    <p>there is work undertaken for zend image by me - ie. there is a prototype that works with gd2 and has cosidrable functionality.</p>

    <p>Helgi Hrafn Halldórsson - your proposal wont get past evaluation , there were 3 proposals so far and all were rejected they were all similar to what you did.</p>

    <p><a class="external-link" href="http://webreactor.eu/image/">http://webreactor.eu/image/</a> - here are some results from the prototype ive sent to Dolf Schimmel, it still lacks the object oriented interface - we discussed that and it will appear in the proposal probably soon, we have an idea how it should look like.</p>

  4. Oct 28, 2008

    <p>LOL, how many people have written something like this since Zend Framework doesn't have it? I myself wrote a component similar to Heigi's a couple years ago. In fact, the method signatures look so similar our code is probably nearly identical! Although this was before IMagick was updated, so it used ImageMagick's own MagickWand for PHP extension.</p>

  5. Jan 10, 2009

    <p>Class skeletons or a repository link?</p>

    <p>Two minor naming-related things:</p>

    <p>1. ImageMagick, not Imagemagick</p>

    <p>2. It seems everyone is solving the abstract/interface namespace problem differently. The current naming conventions specify that interfaces should be named like Zend_Image_Object_Line_Interface, not Zend_Image_ObjectInterface_Line. Since there has been no conclusion yet about what the 2.0 naming convention will look like, I would stick with the existing convention for now.</p>

    1. Jul 28, 2009

      <p>Tnx for the reply!</p>

      <p>What class skeletons are concerned, there are so many classes, that it makes no sense to type them all out here in advance. I will however post a link to a repository soon here.</p>

      <p>1. All occurences with 'Imagemagick' were replaced by 'ImageMagick'.</p>

      <p>2. I never realized / thought that there's a convention for this (= stupid of me). I don't feel like sticking to this convention however, because then you'd get like a lot of files all in their own directory, instead of having a few dirs with a lot of files. What do you think about that? (I realize that conventions are there with a reason, and if you all want me to, I will stick to this one <ac:emoticon ac:name="wink" /> ).</p>

      <p>Edit (Jul.28 2009): Zend_Image will be compliant with the coding standards that are in effect when the component is promoted to trunk (if it ever gets accepted).</p>

  6. Jan 11, 2009

    <p>this looks good, and i am very keen to see this component in incubator.</p>

    <p>Questions:<br />
    1. What is the difference between Zend_Image_Line and Zend_Image_Object_Line class?<br />
    2. Is there an error in use case3 line3? it looks strange (missing pointer and function)<br />
    3. How is the adapter specified in UC4?<br />
    4. Could the Zend_Image wrapper around the adapter maybe implement plugin loader or something and offer a __call intercept for options? That way it would be possible to add drawing and/or other functionality by the user that would otherwise be written around the API.</p>

    1. Jan 11, 2009

      <p>1. Zend_Image_Line was a typo/mistake, should have been Zend_Image_Object_Line, which has now been replaced by Zend_Image_Action_DrawLine.<br />
      2. Yup, there's a huge error there...solved.<br />
      3. It is autodetected, by checking what functions are available.<br />
      4. Will do!</p>

  7. Jan 10, 2009

    <p>I'm very excited about seeing the code in a future repository.</p>

    <p>I have a few suggestions though:</p>

    <p>How about adding a Zend_Image_Layer or Zend_Image_Object_Layer. This would be able to hold an arbitrary amount of Zend_Image_Object_*'s.</p>

    <p>To add to that, I'm not sure how you are going to implement the different Zend_Image_Object_* classes, but with the previous suggestion in mind, it would be nice if the actual rendering of the different objects in an image with a specific adapter, would only occur if render()/save() type methods are called.</p>

    <p>This way, you would be able to store 'blueprints' (for lack of a better word) of the image in a storage mechanism (in some kind of language like xml) and alter its contents afterwards. You could even use them as templates this way. With the Layer suggestion in mind, you would also be able to alter the 'z-index' of layers later on and call operations on a collection of objects in one go.</p>

    <p>Consider something like the following:</p>

    <ac:macro ac:name="code"><ac:default-parameter>php</ac:default-parameter><ac:plain-text-body><![CDATA[

    $image = new Zend_Image();

    // add a layer (second argument is z-index)
    $layer1 = $image->add( Zend_Image::LAYER, 3, 'non unique name of the layer' );

    // OR perhaps this way (first argument is z-index)
    $layer1 = $image->addLayer( 3, 'non unique name of the layer' );

    // add some objects
    $layer1->add( Zend_Image::LINE, ... );
    $layer1->add( Zend_Image::POLYGON, ... );

    // resize all the objects in the layer at once to a relative size
    $layer1->resize( '50', '20', Zend_Image::UNIT_PERCENTAGE, Zend_Image::ADJUST_RELATIVE )

    // move all the objects the in layer at once to an absolute position
    $layer1->move( '50', '20', Zend_Image::UNIT_PIXEL, Zend_Image::ADJUST_ABSOLUTE )

    // new layer
    $layer2 = $image->add( Zend_Image::LAYER, 6, 'non unique name of the layer' );

    // set z-index to 1
    $layer2->setZIndex( 1 );

    // get the 'blueprint' of the image in XML with something like getRaw()
    $rawImage = $image->getRaw( Zend_Image::FORMAT_XML );

    // or perhaps even save the image 'raw'
    $image->save( 'path/to/rawimagedata.xml', Zend_Image::FORMAT_XML );

    // save image 'blueprint' in DB
    $stmt = $db->prepare( 'INSERT INTO raw_image SET content = :rawImage' );
    $stmt->execute( array( ':rawImage' => $rawImage ) );

    ]]></ac:plain-text-body></ac:macro>

    <p>I think there are still some flaws in this approach (like, what do you do with image data that is bitmap data already), but hopefully you catch my drift.</p>

    1. Jan 11, 2009

      <p>There is a possiblity for the chaining of actions, also, one will be able to apply watermarks with this component. Because of these two things, I am not really convinced what you describe may come in handy, can you understand?</p>

  8. Jan 11, 2009

    <p>Hi,<br />
    I think that these component is really useful and should be in Zend Framework. Now my opinion, it will be great to have some possibility how to write simple plugins for this. I think that Zend_Image_Chain is good basic stone but much better will be something like these</p>

    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    Zend_Image_Plugin_Interface // interface

    My_Zend_Image_Plugin_Galery implements Zend_Image_Plugin_Interface/Abstract {

    public function setParams($params)

    Unknown macro: { .... // can be in Zend_Image_Plugin_Abstract abstract probably }

    public function proceed(array $options)

    Unknown macro: { .... // some code using Zend_Image_Chain maybe ?? }

    }

    ]]></ac:plain-text-body></ac:macro>
    <p>now if you implement method __call wisely will be possible write something like these</p>

    <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
    $image = new Zend_Image('/path/to/image.png',Zend_Image::GD);
    $image->gallery(); // $image->pluginGallery(); or something like these
    $image->save();
    ]]></ac:plain-text-body></ac:macro>

    <p>The main advantage is that will be very simple share these plugins because it will be in one file.</p>

  9. Jan 13, 2009

    <p>Is it possible to use the same method signatures like the already available Zend_Pdf drawing functions? </p>

    <p>Zend_Pdf offers also methods for colors (Zend_Pdf_Color_GrayScale/Rgb/Cmyk/Html), transparency, fonts (Zend_Pdf_Font and Zend_Pdf_Resource_Font), line drawing styles and fill styles.</p>

    <p>Remi</p>

    1. Jul 28, 2009

      <p>After having a small discussion with David Caunt we decided that we would indeed implement similar methods. Not all though, for the simple reason an image is something different than a pdf file/page.</p>

  10. Jan 17, 2009

    <p>UC-02 says:<br />
    ...<br />
    $image = new Zend_Image('/path/to/image.png'); // Autodetect adapter to use<br />
    ...</p>

    <p>How will the autodetection work? I.e. will it be 'IM -> GD -> exception', or 'GD -> IM -> exception' by default? There should be a static method to specify the default order, Zend_Image::setDefaultAdapterOrder(array $order), which could be called from the bootstrap. In any sense an exception should be thrown if no adapter have been found at the end of the chain.</p>

    <p>As for what should be the default order, I don't have any useful input. ImageMagick seems to be packed with features and useful for existing images, while GD seems to be easier for drawing. Someone who knows should say more about this. The choice (and the reason for it) should be documented in the manual.</p>

    <p>Metanote:<br />
    Is this proposal really ready for review? I miss a more textual description of the design, and the choices for it, and I also miss class skeletons (yes, browsing the linked page is too cumbersome). I'm not trying to be picky here, but this proposal doesn't say much <ac:emoticon ac:name="smile" /></p>

    1. Jan 21, 2009

      <p>In my opinion the automatic order should not be changable.<br />
      This leads just to irritations.</p>

      <p>When someone really has both extensions installed and wants to use this one he should set an option. Something like:</p>
      <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[
      $image = new Zend_Image(array('image' => '/path/to/image.img', 'adapter' => 'gd'));
      ]]></ac:plain-text-body></ac:macro>

      <p>This way you can simply configure what you want within a external configuration file or by using Zend_Config.<br />
      Having Options is in most parts a better approach then having static function calls.</p>

      1. Sep 11, 2009

        <p>So, it was our intention of not providing any means for this due to complexity (we thought). But somehow we came to a point where we just implemented it <ac:emoticon ac:name="laugh" /> (no, it was not complex at all).</p>

        <p>If you prefer to use ImageMagick over the GD adapter, you can do:</p>
        <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[$image = new Zend_Image::factory(array('adapters' => array('ImageMagick')));
        // or:
        Zend_Image::setAdapter('ImageMagick');
        $image = Zend_Image::factory();]]></ac:plain-text-body></ac:macro>

        <p>Alternatively you can force Zend_Image to use one particular adapter. So that only ImageMagick will be used, even when GD is not available:</p>
        <ac:macro ac:name="code"><ac:plain-text-body><![CDATA[$image = new Zend_Image::factory(array('adapters' => array('ImageMagick'), 'adapters_force' => true));
        // or:
        Zend_Image::setAdapter('ImageMagick', true);
        $image = Zend_Image::factory();
        ]]></ac:plain-text-body></ac:macro>

        <p>When forcing a certain adapter, or when there's none available (read: usable on the system) a Zend_Image_Exception will be thrown.</p>

  11. Feb 06, 2009

    <p>It'd be great to see this added to the framework. I'm sure countless developers here have written similar components, therefore this would be very helpful to many. Gets my vote. </p>

  12. Jul 23, 2009

    <p>Is this proposal still being worked on? If not it's something I might be interested in developing.</p>

    1. Jul 23, 2009

      <p>For the past few months it wasn't being worked on. I however started working on it again as of today, and the proposal will be ready for recommendation soon.</p>

      <p>If you're willing to contribute, feel free to contact me.</p>

  13. Jul 27, 2009

    <p>I would love to help. I started working on my own this weekend.</p>

    <p><a href="http://ranza.svn.beanstalkapp.com/zend_image/trunk/">Verk_Image</a><br />
    This is really a work in progress! <ac:emoticon ac:name="smile" /></p>

    <p>Though i still think you should put actions in folders insted. Say filters go in Zend_Image_Filter_<ac:link><ri:page ri:content-title="filtername" /></ac:link> and the adapter filter would go in Zend_Image_Adapter_<ac:link><ri:page ri:content-title="adapter" /></ac:link><em>Filter</em><ac:link><ri:page ri:content-title="filter" /></ac:link></p>

    <p>Same goes for Draw and such. It would make the thing more consistent, at least i think</p>

    1. Jul 28, 2009

      <p>That is what the original plan was (see the history of this page). However, this would overcomplicate (is that English?) stuff like magic methods. Therefore we decided to turn it all into actions. By the end of the day applyFilter is an action <ac:emoticon ac:name="wink" /></p>

  14. Aug 15, 2009

    <p>Hello!</p>

    <p>I am really interested in this component (it's nothing new to say that I've been working on something similar too) and would be glad to contribute to it in case you guys need a helping hand.</p>

    <p>There's a library for batch image processing that I have written and it could be put to good use here. </p>

  15. Oct 08, 2009

    <p>I saw that your adapter Zend_Image_Adapter_ImageMagick is an adapter for the Imagick php extension.</p>

    <p>I think it would be clearer if this will be named Zend_Image_Adapter_Imagick and the adapter Zend_Image_Adapter_ImageMagick could use ImageMagick directly (by exec).</p>

  16. Oct 08, 2009

    <ac:macro ac:name="note"><ac:parameter ac:name="title">Zend Acceptance</ac:parameter><ac:rich-text-body>
    <p>This proposal is accepted for immediate development in the standard incubator. We request that the following actions are taken during development:</p>

    <ul>
    <li>Rename "Arch" to "Arc"</li>
    <li>Rename classes to follow current coding standards (interfaces end in <component>Interface, abstract classes in <component>Abstract)</li>
    <li>Please keep in communication with the developers who are currently working on charting and graphing capabilities to ensure the API you create is usable by them.</li>
    </ul>
    </ac:rich-text-body></ac:macro>

  17. Aug 19, 2010

    <p>For this proposal, feel free to use the functions in this library which handles things like resizing (with different resize modes - eg. crop, proportional, etc), reading, writing, format conversion, compression:
    <a class="external-link" href="http://github.com/balupton/balphp/blob/master/trunk/lib/core/functions/_image.funcs.php">http://github.com/balupton/balphp/blob/master/trunk/lib/core/functions/_image.funcs.php</a><br />
    They have proven to be very stable over the years</p>

  18. Mar 21, 2011

    <p>Is this component still being actively worked on?</p>