Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Completed image guide

  • Loading branch information...
commit 7f4dfbdb9d7638789a4cb81dd6bf9425328fdd6e 1 parent ea61864
@lysender lysender authored
View
7 guide/image/examples.md
@@ -0,0 +1,7 @@
+# Examples
+
+The following are mini applications that uses the [Image] module. They are very straight forward and did not include additional code such as validations and the like. They are designed to be simple and should work out of the box.
+
+* [Uploading image](examples/upload)
+* [Cropping profile images](examples/crop)
+* [Serving images with dynamic dimension](examples/dynamic)
View
141 guide/image/examples/crop.md
@@ -0,0 +1,141 @@
+# Crop Profile Image
+
+This example is very similar to our previous example and even uses the same upload logics. The only difference is that the uploaded image is cropped to square from the center whose dimension is half the original height of the image.
+
+## Controller
+
+We name our new controller as `Controller_Crop` and accessible through `/crop` URL. Assuming that your project is located in [http://localhost/kohana](http://localhost/kohana), then our crop controller is at [http://localhost/kohana/crop](http://localhost/kohana/crop).
+
+~~~
+<?php defined('SYSPATH') or die('No direct script access.');
+
+class Controller_Crop extends Controller {
+
+ public function action_index()
+ {
+ $view = View::factory('crop/index');
+ $this->response->body($view);
+ }
+
+ public function action_do()
+ {
+ $view = View::factory('crop/do');
+ $error_message = NULL;
+ $filename = NULL;
+
+ if ($this->request->method() == Request::POST)
+ {
+ if (isset($_FILES['avatar']))
+ {
+ $filename = $this->_save_image($_FILES['avatar']);
+ }
+ }
+
+ if ( ! $filename)
+ {
+ $error_message = 'There was a problem while uploading the image.
+ Make sure it is uploaded and must be JPG/PNG/GIF file.';
+ }
+
+ $view->uploaded_file = $filename;
+ $view->error_message = $error_message;
+ $this->response->body($view);
+ }
+
+ protected function _save_image($image)
+ {
+ if (
+ ! Upload::valid($image) OR
+ ! Upload::not_empty($image) OR
+ ! Upload::type($image, array('jpg', 'jpeg', 'png', 'gif')))
+ {
+ return FALSE;
+ }
+
+ $directory = DOCROOT.'uploads/';
+
+ if ($file = Upload::save($image, NULL, $directory))
+ {
+ $filename = strtolower(Text::random('alnum', 20)).'.jpg';
+
+ $img = Image::factory($file);
+
+ // Crop the image square half the height and crop from center
+ $new_height = (int) $img->height / 2;
+
+ $img->crop($new_height, $new_height)
+ ->save($directory.$filename);
+
+ // Delete the temporary file
+ unlink($file);
+
+ return $filename;
+ }
+
+ return FALSE;
+ }
+
+}
+~~~
+
+The `index` action displays the upload form whereas the `do` action will process the uploaded image and provides feedback to the user.
+
+In `do` action, it checks if the request method was `POST`, then delegates the process to `_save_image()` method which in turn performs various checks and finally crops and saves the image to the `uploads` directory.
+
+## Views
+
+For the upload form (the `index` action), the view is located at `views/crop/index.php`.
+
+~~~
+<html>
+ <head>
+ <title>Upload Profile Image</title>
+ </head>
+ <body>
+ <h1>Upload your profile image</h1>
+ <form id="upload-form" action="<?php echo URL::site('crop/do') ?>" method="post" enctype="multipart/form-data">
+ <p>Choose file:</p>
+ <p><input type="file" name="avatar" id="avatar" /></p>
+ <p><input type="submit" name="submit" id="submit" value="Upload and crop" /></p>
+ </form>
+ </body>
+</html>
+~~~
+
+View for `crop/do` action goes to `views/crop/do.php`.
+
+~~~
+<html>
+ <head>
+ <title>Upload Profile Image Result</title>
+ </head>
+ <body>
+ <?php if ($uploaded_file): ?>
+ <h1>Upload success</h1>
+ <p>
+ Here is your uploaded and cropped avatar:
+ <img src="<?php echo URL::site("/uploads/$uploaded_file") ?>" alt="Uploaded avatar" />
+ </p>
+ <?php else: ?>
+ <h1>Something went wrong with the upload</h1>
+ <p><?php echo $error_message ?></p>
+ <?php endif ?>
+ </body>
+</html>
+~~~
+
+## Screenshots
+
+Below are screenshots for this example.
+
+![Original image](crop_orig.jpg)
+
+_Original image to upload_
+
+![Upload image form](crop_form.jpg)
+
+_Upload image form_
+
+![Upload result page](crop_result.jpg)
+
+_Upload result form_
View
108 guide/image/examples/dynamic.md
@@ -0,0 +1,108 @@
+# Dynamic Image Controller
+
+In this example, we have images under `/uploads` under the webroot directory. We allow the user to render any image with dynamic dimension and is resized on the fly. It also caches the response for 1 hour to show basic caching mechanism.
+
+## Route
+
+First, we need a [Route]. This [Route] is based on this URL pattern:
+
+`/imagefly/filename/width/height` - where filename is the name of the image without the extension.
+
+This is our [Route] definition:
+
+~~~
+/**
+ * Set route for image fly
+ */
+Route::set('imagefly', 'imagefly/<image>/<width>/<height>', array('image' => '[-09a-zA-Z_]+', 'width' => '[0-9]+', 'height' => '[0-9]+'))
+ ->defaults(array(
+ 'controller' => 'imagefly',
+ 'action' => 'index'
+ ));
+~~~
+
+We ensure that the filename is only composed of letters, numbers and underscores, width and height must be numeric.
+
+## Controller
+
+Our controller simply accepts the request and capture the following parameters as defined by the [Route]:
+
+* `filename` - without the filename extension (and without dot)
+* `width`
+* `height`
+
+Then it finds the image file and when found, render it on the browser. Additional features added are browser caching.
+
+~~~
+<?php defined('SYSPATH') or die('No direct script access.');
+
+class Controller_Imagefly extends Controller {
+
+ public function action_index()
+ {
+ $file = $this->request->param('image');
+ $width = (int) $this->request->param('width');
+ $height = (int) $this->request->param('height');
+
+ $rendered = FALSE;
+ if ($file AND $width AND $height)
+ {
+ $filename = DOCROOT.'uploads/'.$file.'.jpg';
+
+ if (is_file($filename))
+ {
+ $this->_render_image($filename, $width, $height);
+ $rendered = TRUE;
+ }
+ }
+
+ if ( ! $rendered)
+ {
+ $this->response->status(404);
+ }
+ }
+
+ protected function _render_image($filename, $width, $height)
+ {
+ // Calculate ETag from original file padded with the dimension specs
+ $etag_sum = md5(base64_encode(file_get_contents($filename)).$width.','.$height);
+
+ // Render as image and cache for 1 hour
+ $this->response->headers('Content-Type', 'image/jpeg')
+ ->headers('Cache-Control', 'max-age='.Date::HOUR.', public, must-revalidate')
+ ->headers('Expires', gmdate('D, d M Y H:i:s', time() + Date::HOUR).' GMT')
+ ->headers('Last-Modified', date('r', filemtime($filename)))
+ ->headers('ETag', $etag_sum);
+
+ if (
+ $this->request->headers('if-none-match') AND
+ (string) $this->request->headers('if-none-match') === $etag_sum)
+ {
+ $this->response->status(304)
+ ->headers('Content-Length', '0');
+ }
+ else
+ {
+ $result = Image::factory($filename)
+ ->resize($width, $height)
+ ->render('jpg');
+
+ $this->response->body($result);
+ }
+ }
+}
+~~~
+
+When the parameters are invalid or the filename does not exists, it simply returns 404 not found error.
+
+The rendering of image uses some caching mechanism. One by setting the max age and expire headers and second by using etags.
+
+## Screenshots
+
+Visiting [http://localhost/kohana/imagefly/kitteh/400/400](http://localhost/kohana/imagefly/kitteh/400/400) yields:
+
+![Kitten 400x400](dynamic-400.jpg)
+
+Visiting [http://localhost/kohana/imagefly/kitteh/600/500](http://localhost/kohana/imagefly/kitteh/600/500) yields:
+
+![Kitten 400x400](dynamic-600.jpg)
View
139 guide/image/examples/upload.md
@@ -0,0 +1,139 @@
+# Upload Image
+
+The following example shows how to handle uploading of an image, resize it and save it to a file. Be sure you have enabled the [Image] module as discussed in getting started guide.
+
+Assuming you are creating a web application that allows your members to upload their profile picture (avatar), the steps below explains it how.
+
+## Controller
+
+First we need to create a controller that handles the requests for uploading an image. We will name it `Controller_Avatar` and accessible through `/avatar` URL. Assuming that your project is located in [http://localhost/kohana](http://localhost/kohana), then our avatar controller is at [http://localhost/kohana/avatar](http://localhost/kohana/avatar).
+
+For simplicity, the upload form will be on `index` action and `upload` action will process the uploaded file. This is what our controller now looks like. Please note that we are not using [Controller_Template], just [Controller].
+
+~~~
+<?php defined('SYSPATH') or die('No direct script access.');
+
+class Controller_Avatar extends Controller {
+
+ public function action_index()
+ {
+ $view = View::factory('avatar/index');
+ $this->response->body($view);
+ }
+
+ public function action_upload()
+ {
+ $view = View::factory('avatar/upload');
+ $error_message = NULL;
+ $filename = NULL;
+
+ if ($this->request->method() == Request::POST)
+ {
+ if (isset($_FILES['avatar']))
+ {
+ $filename = $this->_save_image($_FILES['avatar']);
+ }
+ }
+
+ if ( ! $filename)
+ {
+ $error_message = 'There was a problem while uploading the image.
+ Make sure it is uploaded and must be JPG/PNG/GIF file.';
+ }
+
+ $view->uploaded_file = $filename;
+ $view->error_message = $error_message;
+ $this->response->body($view);
+ }
+
+ protected function _save_image($image)
+ {
+ if (
+ ! Upload::valid($image) OR
+ ! Upload::not_empty($image) OR
+ ! Upload::type($image, array('jpg', 'jpeg', 'png', 'gif')))
+ {
+ return FALSE;
+ }
+
+ $directory = DOCROOT.'uploads/';
+
+ if ($file = Upload::save($image, NULL, $directory))
+ {
+ $filename = strtolower(Text::random('alnum', 20)).'.jpg';
+
+ Image::factory($file)
+ ->resize(200, 200, Image::AUTO)
+ ->save($directory.$filename);
+
+ // Delete the temporary file
+ unlink($file);
+
+ return $filename;
+ }
+
+ return FALSE;
+ }
+
+}
+~~~
+
+We have `index` and `upload` actions. `index` action will display the upload form and `upload` action will process the uploaded image and provides feedback to the user.
+
+In `upload` action, it checks if the request method was `POST`, then delegates the process to `_save_image()` method which in turn performs various checks and finally resize and save the image to the `uploads` directory.
+
+## Views
+
+For the upload form (the `index` action), the view is located at `views/avatar/index.php`.
+
+~~~
+<html>
+ <head>
+ <title>Upload Avatar</title>
+ </head>
+ <body>
+ <h1>Upload your avatar</h1>
+ <form id="upload-form" action="<?php echo URL::site('avatar/upload') ?>" method="post" enctype="multipart/form-data">
+ <p>Choose file:</p>
+ <p><input type="file" name="avatar" id="avatar" /></p>
+ <p><input type="submit" name="submit" id="submit" value="Upload" /></p>
+ </form>
+ </body>
+</html>
+~~~
+
+Take note of the action attribute. It points to our `avatar/upload` action whose code goes to `views/avatar/upload.php`.
+
+~~~
+<html>
+ <head>
+ <title>Upload Avatar Result</title>
+ </head>
+ <body>
+ <?php if ($uploaded_file): ?>
+ <h1>Upload success</h1>
+ <p>
+ Here is your uploaded avatar:
+ <img src="<?php echo URL::site("/uploads/$uploaded_file") ?>" alt="Uploaded avatar" />
+ </p>
+ <?php else: ?>
+ <h1>Something went wrong with the upload</h1>
+ <p><?php echo $error_message ?></p>
+ <?php endif ?>
+ </body>
+</html>
+~~~
+
+When the upload is successfull, a success message is displayed with the uploaded image displayed. Otherwise, when it fails, it displays an error message.
+
+## Screenshots
+
+Below are screenshots for this example.
+
+![Upload image form](upload_form.jpg)
+
+_Upload image form_
+
+![Upload result page](upload_result.jpg)
+
+_Upload result form_
View
2  guide/image/index.md
@@ -1,6 +1,6 @@
# Image
-Kohana 3.x provides a simple yet powerful image manipulation module. The [Image] module provides features that allows your application to resize, images, crop, rotate, flip and many more.
+Kohana 3.x provides a simple yet powerful image manipulation module. The [Image] module provides features that allows your application to resize images, crop, rotate, flip and many more.
## Drivers
View
5 guide/image/menu.md
@@ -1,3 +1,6 @@
## [Image]()
- [Using](using)
-- [Examples](examples)
+- [Examples](examples)
+ - [Upload Image](examples/upload)
+ - [Crop Profile Image](examples/crop)
+ - [Dynamic Image Controller](examples/dynamic)
View
84 guide/image/using.md
@@ -16,3 +16,87 @@ Once an instance is created, you can now manipulate the image by using the follo
## Resize
Resize the image to the given size. Either the width or the height can be omitted and the image will be resized proportionally.
+
+Using the image object above, we can resize our image to say 150x150 pixels with automatic scaling using the code below:
+
+~~~
+$img->resize(150, 150, Image::AUTO);
+~~~
+
+The parameters are `width`, `height` and `master` dimension respectively. With `AUTO` master dimension, the image is resized by either width or height depending on which is closer to the specified dimension.
+
+Other examples:
+
+~~~
+// Resize to 200 pixels on the shortest side
+$img->resize(200, 200);
+
+// Resize to 200x200 pixels, keeping aspect ratio
+$img->resize(200, 200, Image::INVERSE);
+
+// Resize to 500 pixel width, keeping aspect ratio
+$img->resize(500, NULL);
+
+// Resize to 500 pixel height, keeping aspect ratio
+$img->resize(NULL, 500);
+
+// Resize to 200x500 pixels, ignoring aspect ratio
+$img->resize(200, 500, Image::NONE);
+~~~
+
+## Render
+
+You can render the image object directly to the browser using the [Image::render()] method.
+
+~~~
+$img = Image::factory(DOCROOT.'uploads/colorado-farm-1920x1200.jpg');
+
+header('Content-Type: image/jpeg');
+
+echo $img->resize(300, 300)
+ ->render('jpg');
+~~~
+
+What it did is resize a 1920x1200 wallpaper image into 300x300 proportionally and render it to the browser. If you are trying to render the image in a controller action, you can do instead:
+
+~~~
+$img = Image::factory(DOCROOT.'uploads/colorado-farm-1920x1200.jpg');
+
+$this->response->headers('Content-Type', 'image/jpg');
+
+$this->response->body(
+ $img->resize(300, 300)
+ ->render()
+);
+~~~
+
+## Save To File
+
+[Image::save()] let's you save the image object to a file. It has two parameters: `filename` and `quality`. If `filename` is omitted, the original file used will be overwritten instead. The `quality` parameter is an integer from 1-100 which indicates the quality of image to save which defaults to 100.
+
+On our example above, instead of rendering the file to the browser, you may want to save it somewhere instead. To do so, you may:
+
+~~~
+$img = Image::factory(DOCROOT.'uploads/colorado-farm-1920x1200.jpg');
+
+$filename = DOCROOT.'uploads/img-'.uniqid().'.jpg';
+
+$img->resize(300, 300)
+ ->save($filename, 80);
+~~~
+
+What we do is resize the image and save it to file reducing quality to 80% and save it to the upload directory using a unique filename.
+
+## Other Methods
+
+There are more methods available for the [Image] module which provides powerfull features that are best describe in the API documentation. Here are some of them:
+
+* [Image::background()] - Set the background color of an image.
+* [Image::crop()] - Crop an image to the given size.
+* [Image::flip()] - Flip the image along the horizontal or vertical axis.
+* [Image::reflection()] - Add a reflection to an image.
+* [Image::rotate()] - Rotate the image by a given amount.
+* [Image::sharpen()] - Sharpen the image by a given amount.
+* [Image::watermark()] - Add a watermark to an image with a specified opacity.
+
+Next: [Examples](examples)
View
BIN  media/guide/image/Thumbs.db
Binary file not shown
View
BIN  media/guide/image/crop_form.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  media/guide/image/crop_orig.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  media/guide/image/crop_result.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  media/guide/image/dynamic-400.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  media/guide/image/dynamic-600.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  media/guide/image/upload_form.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  media/guide/image/upload_result.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Please sign in to comment.
Something went wrong with that request. Please try again.