Slide 1

Slide 1 text

Introduction to Imagine image processing for PHP 5.3+ Sunday, October 16, 11

Slide 2

Slide 2 text

Image processing in PHP is hard Sunday, October 16, 11

Slide 3

Slide 3 text

There are many existing tools • GD • Imagick (ImageMagick extension) • Gmagick (GraphicsMagick extension) • Cairo http://www.imagemagick.org/ http://www.graphicsmagick.org/ Sunday, October 16, 11

Slide 4

Slide 4 text

• not testable • inconsistent • have cluttered apis • not intuitive Existing tools Sunday, October 16, 11

Slide 5

Slide 5 text

Resize in GD

Slide 6

Slide 6 text

Resize in GD

Slide 7

Slide 7 text

Resize in GD

Slide 8

Slide 8 text

Resize in GD

Slide 9

Slide 9 text

Resize in GD

Slide 10

Slide 10 text

Resize in GD

Slide 11

Slide 11 text

Resize in GD

Slide 12

Slide 12 text

Resize in Imagick adaptiveResizeImage($width, $height); // write to disk $image->writeImage('/path/to/resized/image.png'); Sunday, October 16, 11

Slide 13

Slide 13 text

Resize in Imagick adaptiveResizeImage($width, $height); // write to disk $image->writeImage('/path/to/resized/image.png'); Sunday, October 16, 11

Slide 14

Slide 14 text

Resize in Imagick adaptiveResizeImage($width, $height); // write to disk $image->writeImage('/path/to/resized/image.png'); Sunday, October 16, 11

Slide 15

Slide 15 text

Resize in Imagick adaptiveResizeImage($width, $height); // write to disk $image->writeImage('/path/to/resized/image.png'); Sunday, October 16, 11

Slide 16

Slide 16 text

Resize in Imagick adaptiveResizeImage($width, $height); // write to disk $image->writeImage('/path/to/resized/image.png'); Sunday, October 16, 11

Slide 17

Slide 17 text

Existing tools don’t cut it Sunday, October 16, 11

Slide 18

Slide 18 text

Imagine... • all drivers implemented the same interfaces • code could be reused with any driver • there were interfaces for mocking in tests • API was simple and intuitive Sunday, October 16, 11

Slide 19

Slide 19 text

STOP Sunday, October 16, 11

Slide 20

Slide 20 text

Imagine for PHP 5.3+ stop imagining, it is all there Sunday, October 16, 11

Slide 21

Slide 21 text

Imagine for PHP 5.3+ Inspired by Python’s PIL http://www.pythonware.com/products/pil/ Sunday, October 16, 11

Slide 22

Slide 22 text

Resize in Imagine (GD) open('/path/to/image.png') ->resize(new Imagine\Image\Box($width, $height)) ->save('/path/to/resized/image.png'); Sunday, October 16, 11

Slide 23

Slide 23 text

Resize in Imagine (Imagick) open('/path/to/image.png') ->resize(new Imagine\Image\Box($width, $height)) ->save('/path/to/resized/image.png'); Sunday, October 16, 11

Slide 24

Slide 24 text

Consistency 1. identify operations 2. split into groups 3. implement per driver Sunday, October 16, 11

Slide 25

Slide 25 text

Operations • resize • rotate • crop • save • copy • paste • apply mask • ellipse • polygon • line • dot • arc • pie slice • text Sunday, October 16, 11

Slide 26

Slide 26 text

manipulations Operations • resize • rotate • crop • save • copy • paste • apply mask • ellipse • polygon • line • dot • arc • pie slice • text Sunday, October 16, 11

Slide 27

Slide 27 text

Operations • resize • rotate • crop • save • copy • paste • apply mask • ellipse • polygon • line • dot • arc • pie slice • text drawings Sunday, October 16, 11

Slide 28

Slide 28 text

Example Sunday, October 16, 11

Slide 29

Slide 29 text

Thumbnail Sunday, October 16, 11

Slide 30

Slide 30 text

Thumbnail open('/path/to/google/logo.png') ->thumbnail(new Imagine\Image\Box(100, 100), $mode) ->save('/path/to/google/logo/thumbnail.png'); Sunday, October 16, 11

Slide 31

Slide 31 text

Reflection Sunday, October 16, 11

Slide 32

Slide 32 text

Reflection open('/path/to/google/logo.png'); $size = $logo->getSize(); $canvas = $imagine->create( new Imagine\Image\Box($size->getWidth(), $size->getHeight() * 2), new Imagine\Image\Color('000', 100) ); $reflection = $logo->copy() ->flipVertically() ->applyMask( $imagine->create($size) ->fill( new Imagine\Image\Fill\Gradient\Vertical( $size->getHeight(), new Imagine\Image\Color(array(127, 127, 127)), new Imagine\Image\Color('fff') ) ) ); $canvas->paste($logo, new Imagine\Image\Point(0, 0)) ->paste($reflection, new Imagine\Image\Point(0, $size->getHeight())) ->save('/path/to/google/logo/reflection.png'); Sunday, October 16, 11

Slide 33

Slide 33 text

Reflection open('/path/to/google/logo.png'); $size = $logo->getSize(); $canvas = $imagine->create( new Imagine\Image\Box($size->getWidth(), $size->getHeight() * 2), new Imagine\Image\Color('000', 100) ); $reflection = $logo->copy() ->flipVertically() ->applyMask( $imagine->create($size) ->fill( new Imagine\Image\Fill\Gradient\Vertical( $size->getHeight(), new Imagine\Image\Color(array(127, 127, 127)), new Imagine\Image\Color('fff') ) ) ); $canvas->paste($logo, new Imagine\Image\Point(0, 0)) ->paste($reflection, new Imagine\Image\Point(0, $size->getHeight())) ->save('/path/to/google/logo/reflection.png'); open image to reflect and remember its size Sunday, October 16, 11

Slide 34

Slide 34 text

Reflection open('/path/to/google/logo.png'); $size = $logo->getSize(); $canvas = $imagine->create( new Imagine\Image\Box($size->getWidth(), $size->getHeight() * 2), new Imagine\Image\Color('000', 100) ); $reflection = $logo->copy() ->flipVertically() ->applyMask( $imagine->create($size) ->fill( new Imagine\Image\Fill\Gradient\Vertical( $size->getHeight(), new Imagine\Image\Color(array(127, 127, 127)), new Imagine\Image\Color('fff') ) ) ); $canvas->paste($logo, new Imagine\Image\Point(0, 0)) ->paste($reflection, new Imagine\Image\Point(0, $size->getHeight())) ->save('/path/to/google/logo/reflection.png'); create empty canvas to fit image and reflection Sunday, October 16, 11

Slide 35

Slide 35 text

Reflection open('/path/to/google/logo.png'); $size = $logo->getSize(); $canvas = $imagine->create( new Imagine\Image\Box($size->getWidth(), $size->getHeight() * 2), new Imagine\Image\Color('000', 100) ); $reflection = $logo->copy() ->flipVertically() ->applyMask( $imagine->create($size) ->fill( new Imagine\Image\Fill\Gradient\Vertical( $size->getHeight(), new Imagine\Image\Color(array(127, 127, 127)), new Imagine\Image\Color('fff') ) ) ); $canvas->paste($logo, new Imagine\Image\Point(0, 0)) ->paste($reflection, new Imagine\Image\Point(0, $size->getHeight())) ->save('/path/to/google/logo/reflection.png'); make a copy of source, flipped vertically Sunday, October 16, 11

Slide 36

Slide 36 text

open('/path/to/google/logo.png'); $size = $logo->getSize(); $canvas = $imagine->create( new Imagine\Image\Box($size->getWidth(), $size->getHeight() * 2), new Imagine\Image\Color('000', 100) ); $reflection = $logo->copy() ->flipVertically() ->applyMask( $imagine->create($size) ->fill( new Imagine\Image\Fill\Gradient\Vertical( $size->getHeight(), new Imagine\Image\Color(array(127, 127, 127)), new Imagine\Image\Color('fff') ) ) ); $canvas->paste($logo, new Imagine\Image\Point(0, 0)) ->paste($reflection, new Imagine\Image\Point(0, $size->getHeight())) ->save('/path/to/google/logo/reflection.png'); Reflection create image like the one above Sunday, October 16, 11

Slide 37

Slide 37 text

open('/path/to/google/logo.png'); $size = $logo->getSize(); $canvas = $imagine->create( new Imagine\Image\Box($size->getWidth(), $size->getHeight() * 2), new Imagine\Image\Color('000', 100) ); $reflection = $logo->copy() ->flipVertically() ->applyMask( $imagine->create($size) ->fill( new Imagine\Image\Fill\Gradient\Vertical( $size->getHeight(), new Imagine\Image\Color(array(127, 127, 127)), new Imagine\Image\Color('fff') ) ) ); $canvas->paste($logo, new Imagine\Image\Point(0, 0)) ->paste($reflection, new Imagine\Image\Point(0, $size->getHeight())) ->save('/path/to/google/logo/reflection.png'); Reflection replace white regions with transparency Sunday, October 16, 11

Slide 38

Slide 38 text

open('/path/to/google/logo.png'); $size = $logo->getSize(); $canvas = $imagine->create( new Imagine\Image\Box($size->getWidth(), $size->getHeight() * 2), new Imagine\Image\Color('000', 100) ); $reflection = $logo->copy() ->flipVertically() ->applyMask( $imagine->create($size) ->fill( new Imagine\Image\Fill\Gradient\Vertical( $size->getHeight(), new Imagine\Image\Color(array(127, 127, 127)), new Imagine\Image\Color('fff') ) ) ); $canvas->paste($logo, new Imagine\Image\Point(0, 0)) ->paste($reflection, new Imagine\Image\Point(0, $size->getHeight())) ->save('/path/to/google/logo/reflection.png'); Reflection place original logo on top of created canvas place reflection underneath it Sunday, October 16, 11

Slide 39

Slide 39 text

Piechart Sunday, October 16, 11

Slide 40

Slide 40 text

Piechart increase($volume); $bg = new Imagine\Image\Color('000000', 100); $color1 = new Imagine\Image\Color('FFEF78'); $color2 = new Imagine\Image\Color('8A834B'); $color3 = new Imagine\Image\Color('8A554B'); $color4 = new Imagine\Image\Color('D94616'); $color5 = new Imagine\Image\Color('FEB48D'); $chart = $imagine->create($canvas, $bg); for ($i = $volume; $i > 0; $i--) { $shift = $center->move($i); $chart->draw() ->pieSlice($shift, $size, -10, 70, $color1->darken(68), true) ->pieSlice($shift, $size, 70, 160, $color2->darken(68), true) ->pieSlice($shift, $size, 160, 170, $color3->darken(68), true) ->pieSlice($shift, $size, 170, 210, $color4->darken(68), true) ->pieSlice($shift, $size, 210, 350, $color5->darken(68), true); } $chart->draw() ->pieSlice($center, $size, -10, 70, $color1, true) ->pieSlice($center, $size, 70, 160, $color2, true) ->pieSlice($center, $size, 160, 170, $color3, true) ->pieSlice($center, $size, 170, 210, $color4, true) ->pieSlice($center, $size, 210, 350, $color5, true); $chart->save('/path/to/chart.png'); Sunday, October 16, 11

Slide 41

Slide 41 text

Piechart increase($volume); $bg = new Imagine\Image\Color('000000', 100); $color1 = new Imagine\Image\Color('FFEF78'); $color2 = new Imagine\Image\Color('8A834B'); $color3 = new Imagine\Image\Color('8A554B'); $color4 = new Imagine\Image\Color('D94616'); $color5 = new Imagine\Image\Color('FEB48D'); $chart = $imagine->create($canvas, $bg); for ($i = $volume; $i > 0; $i--) { $shift = $center->move($i); $chart->draw() ->pieSlice($shift, $size, -10, 70, $color1->darken(68), true) ->pieSlice($shift, $size, 70, 160, $color2->darken(68), true) ->pieSlice($shift, $size, 160, 170, $color3->darken(68), true) ->pieSlice($shift, $size, 170, 210, $color4->darken(68), true) ->pieSlice($shift, $size, 210, 350, $color5->darken(68), true); } $chart->draw() ->pieSlice($center, $size, -10, 70, $color1, true) ->pieSlice($center, $size, 70, 160, $color2, true) ->pieSlice($center, $size, 160, 170, $color3, true) ->pieSlice($center, $size, 170, 210, $color4, true) ->pieSlice($center, $size, 210, 350, $color5, true); $chart->save('/path/to/chart.png'); get imagine, define chart 3d volume and size Sunday, October 16, 11

Slide 42

Slide 42 text

Piechart increase($volume); $bg = new Imagine\Image\Color('000000', 100); $color1 = new Imagine\Image\Color('FFEF78'); $color2 = new Imagine\Image\Color('8A834B'); $color3 = new Imagine\Image\Color('8A554B'); $color4 = new Imagine\Image\Color('D94616'); $color5 = new Imagine\Image\Color('FEB48D'); $chart = $imagine->create($canvas, $bg); for ($i = $volume; $i > 0; $i--) { $shift = $center->move($i); $chart->draw() ->pieSlice($shift, $size, -10, 70, $color1->darken(68), true) ->pieSlice($shift, $size, 70, 160, $color2->darken(68), true) ->pieSlice($shift, $size, 160, 170, $color3->darken(68), true) ->pieSlice($shift, $size, 170, 210, $color4->darken(68), true) ->pieSlice($shift, $size, 210, 350, $color5->darken(68), true); } $chart->draw() ->pieSlice($center, $size, -10, 70, $color1, true) ->pieSlice($center, $size, 70, 160, $color2, true) ->pieSlice($center, $size, 160, 170, $color3, true) ->pieSlice($center, $size, 170, 210, $color4, true) ->pieSlice($center, $size, 210, 350, $color5, true); $chart->save('/path/to/chart.png'); get center of the chart account for size of 3d volume in canvas Sunday, October 16, 11

Slide 43

Slide 43 text

Piechart increase($volume); $bg = new Imagine\Image\Color('000000', 100); $color1 = new Imagine\Image\Color('FFEF78'); $color2 = new Imagine\Image\Color('8A834B'); $color3 = new Imagine\Image\Color('8A554B'); $color4 = new Imagine\Image\Color('D94616'); $color5 = new Imagine\Image\Color('FEB48D'); $chart = $imagine->create($canvas, $bg); for ($i = $volume; $i > 0; $i--) { $shift = $center->move($i); $chart->draw() ->pieSlice($shift, $size, -10, 70, $color1->darken(68), true) ->pieSlice($shift, $size, 70, 160, $color2->darken(68), true) ->pieSlice($shift, $size, 160, 170, $color3->darken(68), true) ->pieSlice($shift, $size, 170, 210, $color4->darken(68), true) ->pieSlice($shift, $size, 210, 350, $color5->darken(68), true); } $chart->draw() ->pieSlice($center, $size, -10, 70, $color1, true) ->pieSlice($center, $size, 70, 160, $color2, true) ->pieSlice($center, $size, 160, 170, $color3, true) ->pieSlice($center, $size, 170, 210, $color4, true) ->pieSlice($center, $size, 210, 350, $color5, true); $chart->save('/path/to/chart.png'); colors of pie slices and background Sunday, October 16, 11

Slide 44

Slide 44 text

Piechart increase($volume); $bg = new Imagine\Image\Color('000000', 100); $color1 = new Imagine\Image\Color('FFEF78'); $color2 = new Imagine\Image\Color('8A834B'); $color3 = new Imagine\Image\Color('8A554B'); $color4 = new Imagine\Image\Color('D94616'); $color5 = new Imagine\Image\Color('FEB48D'); $chart = $imagine->create($canvas, $bg); for ($i = $volume; $i > 0; $i--) { $shift = $center->move($i); $chart->draw() ->pieSlice($shift, $size, -10, 70, $color1->darken(68), true) ->pieSlice($shift, $size, 70, 160, $color2->darken(68), true) ->pieSlice($shift, $size, 160, 170, $color3->darken(68), true) ->pieSlice($shift, $size, 170, 210, $color4->darken(68), true) ->pieSlice($shift, $size, 210, 350, $color5->darken(68), true); } $chart->draw() ->pieSlice($center, $size, -10, 70, $color1, true) ->pieSlice($center, $size, 70, 160, $color2, true) ->pieSlice($center, $size, 160, 170, $color3, true) ->pieSlice($center, $size, 170, 210, $color4, true) ->pieSlice($center, $size, 210, 350, $color5, true); $chart->save('/path/to/chart.png'); create chart canvas with transparent background Sunday, October 16, 11

Slide 45

Slide 45 text

Piechart increase($volume); $bg = new Imagine\Image\Color('000000', 100); $color1 = new Imagine\Image\Color('FFEF78'); $color2 = new Imagine\Image\Color('8A834B'); $color3 = new Imagine\Image\Color('8A554B'); $color4 = new Imagine\Image\Color('D94616'); $color5 = new Imagine\Image\Color('FEB48D'); $chart = $imagine->create($canvas, $bg); for ($i = $volume; $i > 0; $i--) { $shift = $center->move($i); $chart->draw() ->pieSlice($shift, $size, -10, 70, $color1->darken(68), true) ->pieSlice($shift, $size, 70, 160, $color2->darken(68), true) ->pieSlice($shift, $size, 160, 170, $color3->darken(68), true) ->pieSlice($shift, $size, 170, 210, $color4->darken(68), true) ->pieSlice($shift, $size, 210, 350, $color5->darken(68), true); } $chart->draw() ->pieSlice($center, $size, -10, 70, $color1, true) ->pieSlice($center, $size, 70, 160, $color2, true) ->pieSlice($center, $size, 160, 170, $color3, true) ->pieSlice($center, $size, 170, 210, $color4, true) ->pieSlice($center, $size, 210, 350, $color5, true); $chart->save('/path/to/chart.png'); build 3d shade of the chart in darker colors Sunday, October 16, 11

Slide 46

Slide 46 text

Piechart increase($volume); $bg = new Imagine\Image\Color('000000', 100); $color1 = new Imagine\Image\Color('FFEF78'); $color2 = new Imagine\Image\Color('8A834B'); $color3 = new Imagine\Image\Color('8A554B'); $color4 = new Imagine\Image\Color('D94616'); $color5 = new Imagine\Image\Color('FEB48D'); $chart = $imagine->create($canvas, $bg); for ($i = $volume; $i > 0; $i--) { $shift = $center->move($i); $chart->draw() ->pieSlice($shift, $size, -10, 70, $color1->darken(68), true) ->pieSlice($shift, $size, 70, 160, $color2->darken(68), true) ->pieSlice($shift, $size, 160, 170, $color3->darken(68), true) ->pieSlice($shift, $size, 170, 210, $color4->darken(68), true) ->pieSlice($shift, $size, 210, 350, $color5->darken(68), true); } $chart->draw() ->pieSlice($center, $size, -10, 70, $color1, true) ->pieSlice($center, $size, 70, 160, $color2, true) ->pieSlice($center, $size, 160, 170, $color3, true) ->pieSlice($center, $size, 170, 210, $color4, true) ->pieSlice($center, $size, 210, 350, $color5, true); $chart->save('/path/to/chart.png'); draw and save the actual chart Sunday, October 16, 11

Slide 47

Slide 47 text

Simplify 1. use value objects 2. make ‘em smart Sunday, October 16, 11

Slide 48

Slide 48 text

Color lighten(127); $color->dissolve(50); $color->lighten(127)->dissolve(50); $color->getRed() $color->getGreen() $color->getBlue() $color->getAlpha() $color->isOpaque() 0 0 0 0 true Sunday, October 16, 11

Slide 49

Slide 49 text

Box $box = new Imagine\Image\Box(100, 100); $box->scale(2); $box->increase(25); 100 100 200 200 125 125 Sunday, October 16, 11

Slide 50

Slide 50 text

Point $point = new Imagine\Image\Point(50, 50); Sunday, October 16, 11

Slide 51

Slide 51 text

Make it testable 1. interface end user code interactions 2. close unexpected inheritance Sunday, October 16, 11

Slide 52

Slide 52 text

Filters Sunday, October 16, 11

Slide 53

Slide 53 text

Filter

Slide 54

Slide 54 text

Filters Filter is a collection of manipulations, calculations and other operations, that can be applied to an image Sunday, October 16, 11

Slide 55

Slide 55 text

Reflection filter imagine = $imagine; } public function apply(Imagine\Image\ImageInterface $image) { $size = $image->getSize(); $canvas = new Imagine\Image\Box($size->getWidth(), $size->getHeight() * 2); $reflection = $image->copy() ->flipVertically() ->applyMask($this->getTransparencyMask($size)) ; return $this->imagine->create($canvas, new Imagine\Image\Color('fff', 100)) ->paste($image, new Imagine\Image\Point(0, 0)) ->paste($reflection, new Imagine\Image\Point(0, $size->getHeight())); } private function getTransparencyMask(Imagine\Image\BoxInterface $size) { $white = new Imagine\Image\Color('fff'); $fill = new Imagine\Image\Fill\Gradient\Vertical( $size->getHeight(), $white->darken(127), $white ); return $this->imagine->create($size) ->fill($fill) ; } } Sunday, October 16, 11

Slide 56

Slide 56 text

Reflection filter apply($imagine->open('/path/to/google/logo.png')) ->save('/path/to/google/logo/reflection.png'); Sunday, October 16, 11

Slide 57

Slide 57 text

Transformation Delayed image processing using a filter Sunday, October 16, 11

Slide 58

Slide 58 text

Transformation operate on a transformation as on a regular image, except nothing is being executed resize($resize) ->copy() ->rotate($angle, $background) ->thumbnail($size, Imagine\Image\ImageInterface::THUMBNAIL_INSET) ->save($path); Sunday, October 16, 11

Slide 59

Slide 59 text

Transformation Apply them when you’re ready apply($imagine->open('/path/to/source/image.png')); Sunday, October 16, 11

Slide 60

Slide 60 text

Transformation Or even batch process... apply($imagine->open($path)) ->save('/path/to/processed/image/'.md5($path).'.png'); } Sunday, October 16, 11

Slide 61

Slide 61 text

Imagine and Symfony2 Sunday, October 16, 11

Slide 62

Slide 62 text

Integration 1. configure 2. use in templates 3. profit Sunday, October 16, 11

Slide 63

Slide 63 text

Configure avalanche_imagine: web_root: %kernel.root_dir%/../web driver: gd filters: preview: type: thumbnail options: { size: [100, 50], mode: outbound } Sunday, October 16, 11

Slide 64

Slide 64 text

Templates Twig PHP avatar avatar Sunday, October 16, 11

Slide 65

Slide 65 text

Process first request processes image and outputs response other controller requests result in a 301 redirect to file avatar Sunday, October 16, 11

Slide 66

Slide 66 text

Summary Sunday, October 16, 11

Slide 67

Slide 67 text

To be improved • advanced operations are still not easy (look at the reflection example) • only these drivers are supported • Imagick • GD • Gmagick Sunday, October 16, 11

Slide 68

Slide 68 text

Was improved • thumbnails are easy • code is readable • foundation is solid • its available today • its gonna be great Sunday, October 16, 11

Slide 69

Slide 69 text

What’s next? • Documentation - imagine.readthedocs.org • Implement charting API (piecharts, bar-charts, linear graphs) • Add advanced filters (reflection, rounded corners, etc.) • Add effects (twirl, blur, sharpen, etc.) Sunday, October 16, 11

Slide 70

Slide 70 text

Imagine image processing reloaded https://github.com/avalanche123/Imagine Sunday, October 16, 11