]> git.mxchange.org Git - quix0rs-gnu-social.git/blobdiff - lib/imagefile.php
Merge remote-tracking branch 'upstream/master' into social-master
[quix0rs-gnu-social.git] / lib / imagefile.php
index 80cd9023cd8f2bbbf8a821630ee5f001fc9c3c97..1a23d7b5ab9f9f8535d46e9d5ab49d7bb742b2d1 100644 (file)
@@ -53,10 +53,24 @@ class ImageFile
     var $width;
     var $rotate=0;  // degrees to rotate for properly oriented image (extrapolated from EXIF etc.)
     var $animated = null;  // Animated image? (has more than 1 frame). null means untested
+    var $mimetype = null;   // The _ImageFile_ mimetype, _not_ the originating File object
 
-    function __construct($id=null, $filepath=null, $type=null, $width=null, $height=null)
+    protected $fileRecord = null;
+
+    function __construct($id, $filepath)
     {
         $this->id = $id;
+        if (!empty($this->id)) {
+            $this->fileRecord = new File();
+            $this->fileRecord->id = $this->id;
+            if (!$this->fileRecord->find(true)) {
+                // If we have set an ID, we need that ID to exist!
+                throw new NoResultException($this->fileRecord);
+            }
+        }
+
+        // These do not have to be the same as fileRecord->filename for example,
+        // since we may have generated an image source file from something else!
         $this->filepath = $filepath;
         $this->filename = basename($filepath);
 
@@ -73,9 +87,10 @@ class ImageFile
             throw new UnsupportedMediaException(_('Unsupported image format.'), $this->filepath);
         }
 
-        $this->type = ($info) ? $info[2]:$type;
-        $this->width = ($info) ? $info[0]:$width;
-        $this->height = ($info) ? $info[1]:$height;
+        $this->width    = $info[0];
+        $this->height   = $info[1];
+        $this->type     = $info[2];
+        $this->mimetype = $info['mime'];
 
         if ($this->type == IMAGETYPE_JPEG && function_exists('exif_read_data')) {
             // Orientation value to rotate thumbnails properly
@@ -109,9 +124,17 @@ class ImageFile
         $imgPath = null;
         $media = common_get_mime_media($file->mimetype);
         if (Event::handle('CreateFileImageThumbnailSource', array($file, &$imgPath, $media))) {
-            if (empty($file->filename)) {
+            if (empty($file->filename) && !file_exists($imgPath)) {
                 throw new UnsupportedMediaException(_('File without filename could not get a thumbnail source.'));
             }
+
+            // First some mimetype specific exceptions
+            switch ($file->mimetype) {
+            case 'image/svg+xml':
+                throw new UseFileAsThumbnailException($file->id);
+            }
+
+            // And we'll only consider it an image if it has such a media type
             switch ($media) {
             case 'image':
                 $imgPath = $file->getPath();
@@ -140,7 +163,7 @@ class ImageFile
     public function getPath()
     {
         if (!file_exists($this->filepath)) {
-            throw new ServerException('No file in ImageFile filepath');
+            throw new FileNotFoundException($this->filepath);
         }
 
         return $this->filepath;
@@ -165,6 +188,8 @@ class ImageFile
 
          case UPLOAD_ERR_NO_FILE:
             // No file; probably just a non-AJAX submission.
+            throw new ClientException(_('No file uploaded.'));
+
          default:
             common_log(LOG_ERR, __METHOD__ . ": Unknown upload error " . $_FILES[$param]['error']);
             // TRANS: Exception thrown when uploading an image fails for an unknown reason.
@@ -182,31 +207,6 @@ class ImageFile
         return new ImageFile(null, $_FILES[$param]['tmp_name']);
     }
 
-    /**
-     * Compat interface for old code generating avatar thumbnails...
-     * Saves the scaled file directly into the avatar area.
-     *
-     * @param int $size target width & height -- must be square
-     * @param int $x (default 0) upper-left corner to crop from
-     * @param int $y (default 0) upper-left corner to crop from
-     * @param int $w (default full) width of image area to crop
-     * @param int $h (default full) height of image area to crop
-     * @return string filename
-     */
-    function resize($size, $x = 0, $y = 0, $w = null, $h = null)
-    {
-        $targetType = $this->preferredType();
-        $outname = Avatar::filename($this->id,
-                                    image_type_to_extension($targetType),
-                                    $size,
-                                    common_timestamp());
-        $outpath = Avatar::path($outname);
-        $this->resizeTo($outpath, array('width'=>$size, 'height'=>$size,
-                                        'x'=>$x,        'y'=>$y,
-                                        'w'=>$w,        'h'=>$h));
-        return $outname;
-    }
-
     /**
      * Copy the image file to the given destination.
      *
@@ -255,7 +255,7 @@ class ImageFile
                 @copy($this->filepath, $outpath);
 
                 // And set chmod
-                @chmod($outpath, common_config('thumbnail', 'chmod');
+                @chmod($outpath, common_config('attachments', 'chmod'));
                 return $outpath;
             } elseif (abs($this->rotate) == 90) {
                 // Box is rotated 90 degrees in either direction,
@@ -355,7 +355,7 @@ class ImageFile
         }
 
         // Always chmod 0644 (default) to have other processes (e.g. queue daemon read it)
-        @chmod($outpath, common_config('thumbnail', 'chmod');
+        @chmod($outpath, common_config('attachments', 'chmod'));
 
         imagedestroy($image_src);
         imagedestroy($image_dest);
@@ -545,6 +545,73 @@ class ImageFile
         fclose($fh);
         return $count > 1;
     }
+
+    public function getFileThumbnail($width, $height, $crop)
+    {
+        if (!$this->fileRecord instanceof File) {
+            throw new ServerException('No File object attached to this ImageFile object.');
+        }
+
+        if ($width === null) {
+            $width = common_config('thumbnail', 'width');
+            $height = common_config('thumbnail', 'height');
+            $crop = common_config('thumbnail', 'crop');
+        }
+
+        if ($height === null) {
+            $height = $width;
+            $crop = true;
+        }
+
+        // Get proper aspect ratio width and height before lookup
+        // We have to do it through an ImageFile object because of orientation etc.
+        // Only other solution would've been to rotate + rewrite uploaded files
+        // which we don't want to do because we like original, untouched data!
+        list($width, $height, $x, $y, $w, $h) = $this->scaleToFit($width, $height, $crop);
+
+        $thumb = File_thumbnail::pkeyGet(array(
+                                            'file_id'=> $this->fileRecord->id,
+                                            'width'  => $width,
+                                            'height' => $height,
+                                        ));
+        if ($thumb instanceof File_thumbnail) {
+            return $thumb;
+        }
+
+        $filename = $this->fileRecord->filehash ?: $this->filename;    // Remote files don't have $this->filehash
+        $extension = File::guessMimeExtension($this->mimetype);
+        $outname = "thumb-{$this->fileRecord->id}-{$width}x{$height}-{$filename}." . $extension;
+        $outpath = File_thumbnail::path($outname);
+
+        // The boundary box for our resizing
+        $box = array('width'=>$width, 'height'=>$height,
+                     'x'=>$x,         'y'=>$y,
+                     'w'=>$w,         'h'=>$h);
+
+        // Doublecheck that parameters are sane and integers.
+        if ($box['width'] < 1 || $box['width'] > common_config('thumbnail', 'maxsize')
+                || $box['height'] < 1 || $box['height'] > common_config('thumbnail', 'maxsize')
+                || $box['w'] < 1 || $box['x'] >= $this->width
+                || $box['h'] < 1 || $box['y'] >= $this->height) {
+            // Fail on bad width parameter. If this occurs, it's due to algorithm in ImageFile->scaleToFit
+            common_debug("Boundary box parameters for resize of {$this->filepath} : ".var_export($box,true));
+            throw new ServerException('Bad thumbnail size parameters.');
+        }
+
+        common_debug(sprintf('Generating a thumbnail of File id==%u of size %ux%u', $this->fileRecord->id, $width, $height));
+
+        // Perform resize and store into file
+        $this->resizeTo($outpath, $box);
+
+        // Avoid deleting the original
+        if ($this->getPath() != File_thumbnail::path($this->filename)) {
+            $this->unlink();
+        }
+        return File_thumbnail::saveThumbnail($this->fileRecord->id,
+                                      File_thumbnail::url($outname),
+                                      $width, $height,
+                                      $outname);
+    }
 }
 
 //PHP doesn't (as of 2/24/2010) have an imagecreatefrombmp so conditionally define one