]> git.andy128k.dev Git - ipf.git/commitdiff
cleanup
authorAndrey Kutejko <andy128k@gmail.com>
Sat, 18 Jul 2015 15:36:23 +0000 (18:36 +0300)
committerAndrey Kutejko <andy128k@gmail.com>
Sat, 18 Jul 2015 15:36:23 +0000 (18:36 +0300)
ipf/http/request.php
ipf/http/response.php
ipf/http/response/json.php
ipf/http/response/redirect.php
ipf/image.php [deleted file]
ipf/image/image.php [new file with mode: 0644]

index 14082e0ff8c10ee32afabfea134cdff316bc0035..d6395eb0b561ab37864e542838edc38e93c5bedc 100644 (file)
@@ -18,10 +18,10 @@ class IPF_HTTP_Request
 
     public function __construct()
     {
-        $this->POST =& $_POST;
-        $this->GET =& $_GET;
-        $this->REQUEST =& $_REQUEST;
-        $this->COOKIE =& $_COOKIE;
+        $this->POST = $_POST;
+        $this->GET = $_GET;
+        $this->REQUEST = $_REQUEST;
+        $this->COOKIE = $_COOKIE;
         $this->FILES = self::saneFiles($_FILES);
         $this->method = $_SERVER['REQUEST_METHOD'];
         $this->uri = $_SERVER['REQUEST_URI'];
@@ -42,8 +42,8 @@ class IPF_HTTP_Request
             $this->path_info = $_SERVER['PATH_INFO'];
         else
             $this->path_info = '/';
-        
-        $this->SERVER =& $_SERVER;
+
+        $this->SERVER = $_SERVER;
         $this->is_secure = !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off';
     }
 
index 429a652307f1c09cde1a96551e99bd085b86573e..3ae357664ee13a8238541f3c9355d5dc74cf1fc9 100644 (file)
@@ -8,57 +8,53 @@ class IPF_HTTP_Response
     public $status_code = 200;
     public $cookies = array();
     public $status_code_list = array(
-                                     '100' => 'CONTINUE',
-                                     '101' => 'SWITCHING PROTOCOLS',
-                                     '200' => 'OK',
-                                     '201' => 'CREATED',
-                                     '202' => 'ACCEPTED',
-                                     '203' => 'NON-AUTHORITATIVE INFORMATION',
-                                     '204' => 'NO CONTENT',
-                                     '205' => 'RESET CONTENT',
-                                     '206' => 'PARTIAL CONTENT',
-                                     '300' => 'MULTIPLE CHOICES',
-                                     '301' => 'MOVED PERMANENTLY',
-                                     '302' => 'FOUND',
-                                     '303' => 'SEE OTHER',
-                                     '304' => 'NOT MODIFIED',
-                                     '305' => 'USE PROXY',
-                                     '306' => 'RESERVED',
-                                     '307' => 'TEMPORARY REDIRECT',
-                                     '400' => 'BAD REQUEST',
-                                     '401' => 'UNAUTHORIZED',
-                                     '402' => 'PAYMENT REQUIRED',
-                                     '403' => 'FORBIDDEN',
-                                     '404' => 'NOT FOUND',
-                                     '405' => 'METHOD NOT ALLOWED',
-                                     '406' => 'NOT ACCEPTABLE',
-                                     '407' => 'PROXY AUTHENTICATION REQUIRED',
-                                     '408' => 'REQUEST TIMEOUT',
-                                     '409' => 'CONFLICT',
-                                     '410' => 'GONE',
-                                     '411' => 'LENGTH REQUIRED',
-                                     '412' => 'PRECONDITION FAILED',
-                                     '413' => 'REQUEST ENTITY TOO LARGE',
-                                     '414' => 'REQUEST-URI TOO LONG',
-                                     '415' => 'UNSUPPORTED MEDIA TYPE',
-                                     '416' => 'REQUESTED RANGE NOT SATISFIABLE',
-                                     '417' => 'EXPECTATION FAILED',
-                                     '500' => 'INTERNAL SERVER ERROR',
-                                     '501' => 'NOT IMPLEMENTED',
-                                     '502' => 'BAD GATEWAY',
-                                     '503' => 'SERVICE UNAVAILABLE',
-                                     '504' => 'GATEWAY TIMEOUT',
-                                     '505' => 'HTTP VERSION NOT SUPPORTED'
-                                     );
+        '100' => 'CONTINUE',
+        '101' => 'SWITCHING PROTOCOLS',
+        '200' => 'OK',
+        '201' => 'CREATED',
+        '202' => 'ACCEPTED',
+        '203' => 'NON-AUTHORITATIVE INFORMATION',
+        '204' => 'NO CONTENT',
+        '205' => 'RESET CONTENT',
+        '206' => 'PARTIAL CONTENT',
+        '300' => 'MULTIPLE CHOICES',
+        '301' => 'MOVED PERMANENTLY',
+        '302' => 'FOUND',
+        '303' => 'SEE OTHER',
+        '304' => 'NOT MODIFIED',
+        '305' => 'USE PROXY',
+        '306' => 'RESERVED',
+        '307' => 'TEMPORARY REDIRECT',
+        '400' => 'BAD REQUEST',
+        '401' => 'UNAUTHORIZED',
+        '402' => 'PAYMENT REQUIRED',
+        '403' => 'FORBIDDEN',
+        '404' => 'NOT FOUND',
+        '405' => 'METHOD NOT ALLOWED',
+        '406' => 'NOT ACCEPTABLE',
+        '407' => 'PROXY AUTHENTICATION REQUIRED',
+        '408' => 'REQUEST TIMEOUT',
+        '409' => 'CONFLICT',
+        '410' => 'GONE',
+        '411' => 'LENGTH REQUIRED',
+        '412' => 'PRECONDITION FAILED',
+        '413' => 'REQUEST ENTITY TOO LARGE',
+        '414' => 'REQUEST-URI TOO LONG',
+        '415' => 'UNSUPPORTED MEDIA TYPE',
+        '416' => 'REQUESTED RANGE NOT SATISFIABLE',
+        '417' => 'EXPECTATION FAILED',
+        '500' => 'INTERNAL SERVER ERROR',
+        '501' => 'NOT IMPLEMENTED',
+        '502' => 'BAD GATEWAY',
+        '503' => 'SERVICE UNAVAILABLE',
+        '504' => 'GATEWAY TIMEOUT',
+        '505' => 'HTTP VERSION NOT SUPPORTED',
+    );
 
-    function __construct($content='', $mimetype=null)
+    function __construct($content='', $mimetype='text/html; charset=utf-8')
     {
-        if (is_null($mimetype)) {
-            $mimetype = IPF::get('mimetype', 'text/html').'; charset=utf-8';
-        }
         $this->content = $content;
         $this->headers['Content-Type'] = $mimetype;
-        $this->headers['X-Powered-By'] = 'IPF - http://ipf.icmconsulting.com/';
         $this->status_code = 200;
         $this->cookies = array();
     }
@@ -80,31 +76,18 @@ class IPF_HTTP_Response
 
     function outputHeaders()
     {
-        if (!defined('IN_UNIT_TESTS')) {
-            header('HTTP/1.1 '.$this->status_code.' '
-                   .$this->status_code_list[$this->status_code],
-                   true, $this->status_code);
-            foreach ($this->headers as $header => $ch) {
-                header($header.': '.$ch);
-            }
-            if ($this->short_session)
-               $exp = 0;
-            else
-               $exp = time()+31536000; 
-            foreach ($this->cookies as $cookie => $data) {
-                // name, data, expiration, path, domain, secure, http only
-                setcookie($cookie, $data, 
-                          $exp, 
-                          IPF::get('cookie_path', '/'), 
-                          IPF::get('cookie_domain', null), 
-                          IPF::get('cookie_secure', false), 
-                          IPF::get('cookie_httponly', true)); 
-            }
-        } else {
-            $_COOKIE = array();
-            foreach ($this->cookies as $cookie => $data) {
-                $_COOKIE[$cookie] = $data;
-            }
+        header('HTTP/1.1 '.$this->status_code.' '
+               .$this->status_code_list[$this->status_code],
+               true, $this->status_code);
+        foreach ($this->headers as $header => $ch) {
+            header($header.': '.$ch);
+        }
+        foreach ($this->cookies as $cookie => $data) {
+            setcookie($cookie, $data, time() + 31536000,
+                IPF::get('cookie_path', '/'),
+                IPF::get('cookie_domain', null),
+                IPF::get('cookie_secure', false),
+                IPF::get('cookie_httponly', true));
         }
     }
 
index 8d0a89c31db0a4013d96c81e7a74eb22d2aedd90..97fddf904b62a5a1871aed89e6ce657d05910007 100644 (file)
@@ -1,8 +1,9 @@
 <?php
 
-class IPF_HTTP_Response_Json extends IPF_HTTP_Response{
-    function __construct($content){
-        //parent::__construct(json_encode($content),'application/javascript');
+class IPF_HTTP_Response_Json extends IPF_HTTP_Response
+{
+    function __construct($content)
+    {
         parent::__construct(json_encode($content),'application/json');
     }
 }
index 051a2b5fe36fd354e947ee334b01f380ef5c6a1f..4c68c179badad752811cd91adeff349e7a98b7f3 100644 (file)
@@ -4,7 +4,7 @@ class IPF_HTTP_Response_Redirect extends IPF_HTTP_Response
 {
     function __construct($url)
     {
-        $content = sprintf(__('<a href="%s">Please, click here to be redirected</a>.'), $url);
+        $content = sprintf('<a href="%s">%s</a>', $url, __('Please, click here to be redirected.'));
         parent::__construct($content);
         $this->headers['Location'] = $url;
         $this->status_code = 302;
diff --git a/ipf/image.php b/ipf/image.php
deleted file mode 100644 (file)
index 56f9b1e..0000000
+++ /dev/null
@@ -1,259 +0,0 @@
-<?php
-
-class IPF_Image
-{
-    private $image, $width, $height, $type, $path;
-
-    public static function load($path)
-    {
-        $imageInfo = getimagesize($path);
-        if (!$imageInfo)
-            throw new Exception('Cannot open '.$path.' image file');
-
-        $type = $imageInfo[2];
-
-        if ($type == IMAGETYPE_JPEG)
-            $image = imagecreatefromjpeg($path);
-        else if ($type == IMAGETYPE_GIF)
-            $image = imagecreatefromgif($path);
-        else if ($type == IMAGETYPE_PNG)
-            $image = imagecreatefrompng($path);
-        else
-            throw new Exception('Unknown image format '.$path);
-
-        imagealphablending($image, false);
-        imagesavealpha($image, true);
-
-        return new IPF_Image($image, $imageInfo[0], $imageInfo[1], $type, $path);
-    }
-
-    public static function create($width, $height)
-    {
-        $image = imagecreatetruecolor($width, $height);
-        return new IPF_Image($image, $width, $height);
-    }
-
-    public function __construct($image, $width=null, $height=null, $type=null, $path=null)
-    {
-        $this->image = $image;
-        $this->width = ($width !== null) ? $width : imagesx($image);
-        $this->height = ($height !== null) ? $height : imagesy($image);
-        $this->type = $type;
-        $this->path = $path;
-    }
-
-    public function __destruct()
-    {
-        imagedestroy($this->image);
-    }
-
-    private static function detectType($filename)
-    {
-        if (preg_match('/\.je?pg$/i', $filename))
-            return IMAGETYPE_JPEG;
-        if (preg_match('/\.gif$/i', $filename))
-            return IMAGETYPE_GIF;
-        if (preg_match('/\.png$/i', $filename))
-            return IMAGETYPE_PNG;
-        return null;
-    }
-
-    public function save($filename=null)
-    {
-        $type = null;
-        if ($filename) {
-            $type = self::detectType($filename);
-            if (!$type)
-                $type = IMAGETYPE_JPEG;
-        } else {
-            $filename = $this->path;
-            if ($this->type)
-                $type = $this->type;
-            else
-                $type = self::detectType($filename);
-        }
-
-        if (!$filename)
-            throw new Exception('No filename given.');
-
-        if ($type == IMAGETYPE_JPEG)
-            imagejpeg($this->image, $filename);
-        elseif ($type == IMAGETYPE_GIF)
-            imagegif($this->image, $filename);
-        elseif ($type == IMAGETYPE_PNG)
-            imagepng($this->image, $filename);
-        else
-            throw new Exception('Unknown file type.');
-    }
-
-    private function color($color)
-    {
-        return imagecolorallocatealpha($this->image,
-            ($color >> 16) & 0xFF,
-            ($color >> 8) & 0xFF,
-            $color & 0xFF,
-            ($color >> 24) & 0x7F);
-    }
-
-    public function fill($x, $y, $width, $height, $color)
-    {
-        imagefilledrectangle($this->image, $x, $y, $width, $height, $this->color($color));
-    }
-
-    public function rotate($angle, $color=0x7F000000)
-    {
-        $image = imagerotate($this->image, $angle, $color);
-        return new IPF_Image($image);
-    }
-
-    public function copy(IPF_Image $image, $dstX, $dstY)
-    {
-        imagecopy($this->image, $image->image, $dstX, $dstY, 0, 0, $image->width, $image->height);
-    }
-
-    public function copyPart(IPF_Image $image, $dstX, $dstY, $srcX, $srcY, $width, $height)
-    {
-        imagecopy($this->image, $image->image, $dstX, $dstY, $srcX, $srcY, $width, $height);
-    }
-
-    public function copyScale(IPF_Image $image, $dstX=0, $dstY=0, $dstWidth=null, $dstHeight=null, $srcX=0, $srcY=0, $srcWidth=null, $srcHeight=null)
-    {
-        if ($dstWidth === null)
-            $dstWidth = $this->width;
-        if ($dstHeight === null)
-            $dstHeight = $this->height;
-        if ($srcWidth === null)
-            $srcWidth = $image->width;
-        if ($srcHeight === null)
-            $srcHeight = $image->height;
-        imagecopyresampled($this->image, $image->image, $dstX, $dstY, $srcX, $srcY, $dstWidth, $dstHeight, $srcWidth, $srcHeight);
-    }
-
-    public function diagonalWatermark(IPF_Image $watermark)
-    {
-        $result = IPF_Image::create($this->width, $this->height);
-        $result->copy($this, 0, 0);
-
-        $w_repeat = ceil(hypot($this->width, $this->height) / (float)$watermark->width);
-        $angle = atan2($this->height, $this->width);
-        $wmr = $watermark->rotate(-$angle * 180 / M_PI);
-
-        $dx = $watermark->width * cos($angle);
-        $dy = $watermark->width * sin($angle);
-
-        for ($i = 0; $i < $w_repeat; ++$i) {
-            $result->copy($wmr, $dx * ($i - 0.5), $dy * ($i - 0.5));
-        }
-        return $result;
-    }
-
-    public function fitWidth($width, $expand=true, $shrink=true)
-    {
-        if ($this->width == $width)
-            return $this;
-        if (!$expand && $this->width < $width)
-            return $this;
-        if (!$shrink && $this->width > $width)
-            return $this;
-
-        $height = $width * $this->height / $this->width;
-
-        $result = IPF_Image::create($width, $height);
-        $result->copyScale($this);
-        return $result;
-    }
-
-    public function fitHeight($height, $expand=true, $shrink=true)
-    {
-        if ($this->height == $height)
-            return $this;
-        if (!$expand && $this->height < $height)
-            return $this;
-        if (!$shrink && $this->height > $height)
-            return $this;
-
-        $width = $height * $this->width / $this->height;
-
-        $result = IPF_Image::create($width, $height);
-        $result->copyScale($this);
-        return $result;
-    }
-
-    public function fit($width, $height, $expand=true, $shrink=true)
-    {
-        if (!$expand && $this->width < $width && $this->height < $height)
-            return $this;
-        if (!$shrink && $this->width > $width && $this->height > $height)
-            return $this;
-
-        if ($this->height * $width >= $this->width * $height) {
-            $w = $height * $this->width / $this->height;
-            $h = $height;
-        } else {
-            $w = $width;
-            $h = $width * $this->height / $this->width;
-        }
-
-        $result = IPF_Image::create($w, $h);
-        $result->copyScale($this);
-        return $result;
-    }
-
-    public function thumbnailCrop($width, $height, $gravityX=0.5, $gravityY=0.5)
-    {
-        if ($this->height * $width >= $this->width * $height) {
-            $w = $this->width;
-            $h = $this->width * $height / $width;
-        } else {
-            $w = $this->height * $width / $height;
-            $h = $this->height;
-        }
-        $x = ($this->width - $w) * $gravityX;
-        $y = ($this->height - $h) * $gravityY;
-
-        $result = IPF_Image::create($width, $height);
-        $result->copyScale($this, 0, 0, $width, $height, $x, $y, $w, $h);
-        return $result;
-    }
-
-    public function thumbnailFill($width, $height, $color=0x7F000000, $gravityX=0.5, $gravityY=0.5)
-    {
-        if ($this->height * $width >= $this->width * $height) {
-            $w = $height * $this->width / $this->height;
-            $h = $height;
-        } else {
-            $w = $width;
-            $h = $width * $this->height / $this->width;
-        }
-        $x = ($width - $w) * $gravityX;
-        $y = ($height - $h) * $gravityY;
-
-        $result = IPF_Image::create($width, $height);
-        $result->fill(0, 0, $width, $height, $color);
-        $result->copyScale($this, $x, $y, $w, $h);
-        return $result;
-    }
-
-    public function replaceColor($from, $to, $colorOnly=true)
-    {
-             $from = $this->color($from);
-             $to = $this->color($to);
-        if ($colorOnly) {
-            $from = $from & 0xFFFFFF;
-            $to = $to & 0xFFFFFF;
-             }
-             for ($y = 0; $y < $this->height; ++$y) {
-                       for ($x = 0; $x < $this->width; ++$x) {
-                                 $at = imagecolorat($this->image, $x, $y);
-                if ($colorOnly) {
-                                     if (($at & 0xFFFFFF) === $from)
-                                         imagesetpixel($this->image, $x, $y, $to | ($at & 0x7F000000));
-                                 } else {
-                                     if ($at === $from)
-                                         imagesetpixel($this->image, $x, $y, $to);
-                                 }
-                       }
-             }
-    }
-}
-
diff --git a/ipf/image/image.php b/ipf/image/image.php
new file mode 100644 (file)
index 0000000..df7895b
--- /dev/null
@@ -0,0 +1,259 @@
+<?php
+
+class IPF_Image
+{
+    private $image, $width, $height, $type, $path;
+
+    public static function load($path)
+    {
+        $imageInfo = getimagesize($path);
+        if (!$imageInfo)
+            throw new Exception('Cannot open '.$path.' image file');
+
+        $type = $imageInfo[2];
+
+        if ($type == IMAGETYPE_JPEG)
+            $image = imagecreatefromjpeg($path);
+        else if ($type == IMAGETYPE_GIF)
+            $image = imagecreatefromgif($path);
+        else if ($type == IMAGETYPE_PNG)
+            $image = imagecreatefrompng($path);
+        else
+            throw new Exception('Unknown image format '.$path);
+
+        imagealphablending($image, false);
+        imagesavealpha($image, true);
+
+        return new IPF_Image($image, $imageInfo[0], $imageInfo[1], $type, $path);
+    }
+
+    public static function create($width, $height)
+    {
+        $image = imagecreatetruecolor($width, $height);
+        return new IPF_Image($image, $width, $height);
+    }
+
+    public function __construct($image, $width=null, $height=null, $type=null, $path=null)
+    {
+        $this->image = $image;
+        $this->width = ($width !== null) ? $width : imagesx($image);
+        $this->height = ($height !== null) ? $height : imagesy($image);
+        $this->type = $type;
+        $this->path = $path;
+    }
+
+    public function __destruct()
+    {
+        imagedestroy($this->image);
+    }
+
+    private static function detectType($filename)
+    {
+        if (preg_match('/\.je?pg$/i', $filename))
+            return IMAGETYPE_JPEG;
+        if (preg_match('/\.gif$/i', $filename))
+            return IMAGETYPE_GIF;
+        if (preg_match('/\.png$/i', $filename))
+            return IMAGETYPE_PNG;
+        return null;
+    }
+
+    public function save($filename=null)
+    {
+        $type = null;
+        if ($filename) {
+            $type = self::detectType($filename);
+            if (!$type)
+                $type = IMAGETYPE_JPEG;
+        } else {
+            $filename = $this->path;
+            if ($this->type)
+                $type = $this->type;
+            else
+                $type = self::detectType($filename);
+        }
+
+        if (!$filename)
+            throw new Exception('No filename given.');
+
+        if ($type == IMAGETYPE_JPEG)
+            imagejpeg($this->image, $filename);
+        elseif ($type == IMAGETYPE_GIF)
+            imagegif($this->image, $filename);
+        elseif ($type == IMAGETYPE_PNG)
+            imagepng($this->image, $filename);
+        else
+            throw new Exception('Unknown file type.');
+    }
+
+    private function color($color)
+    {
+        return imagecolorallocatealpha($this->image,
+            ($color >> 16) & 0xFF,
+            ($color >> 8) & 0xFF,
+            $color & 0xFF,
+            ($color >> 24) & 0x7F);
+    }
+
+    public function fill($x, $y, $width, $height, $color)
+    {
+        imagefilledrectangle($this->image, $x, $y, $width, $height, $this->color($color));
+    }
+
+    public function rotate($angle, $color=0x7F000000)
+    {
+        $image = imagerotate($this->image, $angle, $color);
+        return new IPF_Image($image);
+    }
+
+    public function copy(IPF_Image $image, $dstX, $dstY)
+    {
+        imagecopy($this->image, $image->image, $dstX, $dstY, 0, 0, $image->width, $image->height);
+    }
+
+    public function copyPart(IPF_Image $image, $dstX, $dstY, $srcX, $srcY, $width, $height)
+    {
+        imagecopy($this->image, $image->image, $dstX, $dstY, $srcX, $srcY, $width, $height);
+    }
+
+    public function copyScale(IPF_Image $image, $dstX=0, $dstY=0, $dstWidth=null, $dstHeight=null, $srcX=0, $srcY=0, $srcWidth=null, $srcHeight=null)
+    {
+        if ($dstWidth === null)
+            $dstWidth = $this->width;
+        if ($dstHeight === null)
+            $dstHeight = $this->height;
+        if ($srcWidth === null)
+            $srcWidth = $image->width;
+        if ($srcHeight === null)
+            $srcHeight = $image->height;
+        imagecopyresampled($this->image, $image->image, $dstX, $dstY, $srcX, $srcY, $dstWidth, $dstHeight, $srcWidth, $srcHeight);
+    }
+
+    public function diagonalWatermark(IPF_Image $watermark)
+    {
+        $result = IPF_Image::create($this->width, $this->height);
+        $result->copy($this, 0, 0);
+
+        $w_repeat = ceil(hypot($this->width, $this->height) / (float)$watermark->width);
+        $angle = atan2($this->height, $this->width);
+        $wmr = $watermark->rotate(-$angle * 180 / M_PI);
+
+        $dx = $watermark->width * cos($angle);
+        $dy = $watermark->width * sin($angle);
+
+        for ($i = 0; $i < $w_repeat; ++$i) {
+            $result->copy($wmr, $dx * ($i - 0.5), $dy * ($i - 0.5));
+        }
+        return $result;
+    }
+
+    public function fitWidth($width, $expand=true, $shrink=true)
+    {
+        if ($this->width == $width)
+            return $this;
+        if (!$expand && $this->width < $width)
+            return $this;
+        if (!$shrink && $this->width > $width)
+            return $this;
+
+        $height = $width * $this->height / $this->width;
+
+        $result = IPF_Image::create($width, $height);
+        $result->copyScale($this);
+        return $result;
+    }
+
+    public function fitHeight($height, $expand=true, $shrink=true)
+    {
+        if ($this->height == $height)
+            return $this;
+        if (!$expand && $this->height < $height)
+            return $this;
+        if (!$shrink && $this->height > $height)
+            return $this;
+
+        $width = $height * $this->width / $this->height;
+
+        $result = IPF_Image::create($width, $height);
+        $result->copyScale($this);
+        return $result;
+    }
+
+    public function fit($width, $height, $expand=true, $shrink=true)
+    {
+        if (!$expand && $this->width < $width && $this->height < $height)
+            return $this;
+        if (!$shrink && $this->width > $width && $this->height > $height)
+            return $this;
+
+        if ($this->height * $width >= $this->width * $height) {
+            $w = $height * $this->width / $this->height;
+            $h = $height;
+        } else {
+            $w = $width;
+            $h = $width * $this->height / $this->width;
+        }
+
+        $result = IPF_Image::create($w, $h);
+        $result->copyScale($this);
+        return $result;
+    }
+
+    public function thumbnailCrop($width, $height, $gravityX=0.5, $gravityY=0.5)
+    {
+        if ($this->height * $width >= $this->width * $height) {
+            $w = $this->width;
+            $h = $this->width * $height / $width;
+        } else {
+            $w = $this->height * $width / $height;
+            $h = $this->height;
+        }
+        $x = ($this->width - $w) * $gravityX;
+        $y = ($this->height - $h) * $gravityY;
+
+        $result = IPF_Image::create($width, $height);
+        $result->copyScale($this, 0, 0, $width, $height, $x, $y, $w, $h);
+        return $result;
+    }
+
+    public function thumbnailFill($width, $height, $color=0x7F000000, $gravityX=0.5, $gravityY=0.5)
+    {
+        if ($this->height * $width >= $this->width * $height) {
+            $w = $height * $this->width / $this->height;
+            $h = $height;
+        } else {
+            $w = $width;
+            $h = $width * $this->height / $this->width;
+        }
+        $x = ($width - $w) * $gravityX;
+        $y = ($height - $h) * $gravityY;
+
+        $result = IPF_Image::create($width, $height);
+        $result->fill(0, 0, $width, $height, $color);
+        $result->copyScale($this, $x, $y, $w, $h);
+        return $result;
+    }
+
+    public function replaceColor($from, $to, $colorOnly=true)
+    {
+        $from = $this->color($from);
+        $to = $this->color($to);
+        if ($colorOnly) {
+            $from = $from & 0xFFFFFF;
+            $to = $to & 0xFFFFFF;
+        }
+        for ($y = 0; $y < $this->height; ++$y) {
+            for ($x = 0; $x < $this->width; ++$x) {
+                $at = imagecolorat($this->image, $x, $y);
+                if ($colorOnly) {
+                    if (($at & 0xFFFFFF) === $from)
+                        imagesetpixel($this->image, $x, $y, $to | ($at & 0x7F000000));
+                } else {
+                    if ($at === $from)
+                        imagesetpixel($this->image, $x, $y, $to);
+                }
+            }
+        }
+    }
+}
+