Tidypics Wishlist

Mentioned so far:

  1. Better uploading
  2. Lightbox
  3. Tagging like Facebook
  4. Better/configurable activty pushes with photos

 

  • Not sure if somebody mentioned these ones yet:

    * Integration with the Files and/or Tinymce plug-ins so that embedding media/files pulls both Files and Tidypics pictures

    * Storage quota per user (for Tidypics and for Tidypics+Files combined)

    * Upload file size limit (kind of implemented already... but it will have to be reworked if a new uploader is used)

  • I came up with a hack that uses imagemagick's convert command to create the thumbnails for new uploads.  It works great.

    Tested it on a 2900x4300px file that is 5.5MB and it worked like a charm.

    If someone wants to see the code let me know and I can post it.

    Dev's: any chance you'd add the code in the mainline?  I don't know the internals of elgg yet so it is a hack and i'm just skipping the current thumbnail generation code and running the convert's after the thumbnail information is setup so the thumbnails on disk don't get overwritten by the thumbnail creation code.  I'm not quite sure how to make this fit elegantly, but it works for me!

  • @fgroese -- can you post your code? I'm not sure we should force people to use imagemagick since not all web hosting companies have it, but we can at least have the option to use imagemagick when it is available. When it's not, we can revert to GD.

  •  

    Here you go.

    I edited upload.php and removed the first attempt at creating thumbnails and added in another call to create thumbnails after the thumbnail objects are setup and saved.  I'm not sure what all happens with those objects but it appears they are required so elgg can find the thumbnails later.  Just having the files there is not good enough.

    For the actual resizing code, I copied the get_resized_image_from_existing_file() function from the elgg core (engine/lib/filestore.php line 703).  I placed it into the tidypics actions dir in a file called resize.php which I require in upload.php.  This is where I made the modifications to call imagemagick.  The code isn't very clean, but it works.

    One thing I noticed is that the thumbnail on the edit screen immediately following the upload can look skewed, but when you actually view the album, all the proportions are right.

    I'm including the whole upload.php and resize.php:

    upload.php

    <?php
        /**
         * Elgg multi-image uploader action
        *
        * This will upload up to 10 images at at time to an album
         */

        global $CONFIG;
        require_once(dirname(__FILE__)."/resize.php");
           
        // Get common variables
        $access_id = (int) get_input("access_id");
        $container_guid = (int) get_input('container_guid', 0);
        if (!$container_guid)
            $container_guid == $_SESSION['user']->getGUID();
               
        $not_uploaded = array();
        $uploaded_images = array();   

        foreach($_FILES as $key => $sent_file) {
            if (!empty($sent_file['name'])) {
                $name = $_FILES[$key]['name'];
                $mime = $_FILES[$key]['type'];
               
                //make sure file is an image
                if ($mime == 'image/jpeg' || $mime == 'image/gif' || $mime == 'image/png' || $mime == 'image/pjpeg') {
                    //this will save to users folder in /image/ and organize by photo album
                    $prefix = "image/" . $container_guid . "/";
                    $file = new ElggFile();
                    $filestorename = strtolower(time().$name);
                    $file->setFilename($prefix.$filestorename);
                    $file->setMimeType($mime);   
                    $file->originalfilename = $name;   
                    $file->subtype="image";   
                    $file->access_id = $access_id;   
                    if ($container_guid) {
                        $file->container_guid = $container_guid;
                    }               
                    $file->open("write");
                    $file->write(get_uploaded_file($key));
                    $file->close();
                    $result = $file->save();

                    if ($result) { //file was saved; now create some thumbnails
                        //get maximum file size from plugin settings
                        if (get_plugin_setting('maxfilesize','tidypics')) {
                            if (((int) get_plugin_setting('maxfilesize','tidypics')) < 1 || ((int) get_plugin_setting('maxfilesize','tidypics')) > 1048576) {
                                $maxfilesize = 10240; //if file size is less than 1KB or greater than 1GB, default to 10MB
                            } else {
                                $maxfilesize = (int) get_plugin_setting('maxfilesize','tidypics');
                            }
                        } else {
                            $maxfilesize = 10240; //if the file size limit is not set, default to 10MB
                        }
                        $maxfilesize = 1024 * $maxfilesize; //convert to bytes
                           
                        //check file size and remove picture if it exceeds the maximum
                        if (filesize($file->getFilenameOnFilestore())<= $maxfilesize) {
                            array_push($uploaded_images, $file->guid);
           
                            // Generate thumbnail
                            //TODO: This code needs a complete rewrite - hardcoded to ~2.5 MB
                            if (filesize($file->getFilenameOnFilestore())<= 2500000) {
                                try {
                                    //$thumblarge = get_resized_image_from_existing_file($file->getFilenameOnFilestore(),600,600, false);
                                } catch (Exception $e) { $thumblarge = false; }
                               
                                try {
                                    //$thumbsmall = get_resized_image_from_existing_file($file->getFilenameOnFilestore(),153,153, true);
                                } catch (Exception $e) { $thumbsmall = false; }
                               
                                try {
                                    //$thumbnail = get_resized_image_from_existing_file($file->getFilenameOnFilestore(),60,60, true);
                                } catch (Exception $e) { $thumbnail = false; }
                            }
                           
                            // gfroese: i'm just faking this out so the proper records are created for the thumbnails
                            // I don't understand what $thumb->write does but it seems to actually create the file so
                            // I had to move the imagemagick call beneath this.  I'm sure someone else can make this
                            // much better.
                            $thumbnail = true;
                            $thumblarge = true;
                            $thumbsmall = true;

                            if ($thumbnail) {
                                $thumb = new ElggFile();
                                $thumb->setMimeType($mime);
                                $thumb->setFilename($prefix."thumb".$filestorename);
                                $thumb->open("write");
                                if ($thumb->write($thumbnail)) {
                                    $file->thumbnail = $prefix."thumb".$filestorename;
                                } else {
                                    $thumb->delete();
                                }
                                $thumb->close();
                            }
                           
                            if ($thumbsmall) {
                                $thumb = new ElggFile();
                                $thumb->setMimeType($mime);
                                $thumb->setFilename($prefix."smallthumb".$filestorename);
                                $thumb->open("write");
                                if ($thumb->write($thumbsmall)) {
                                    $file->smallthumb = $prefix."smallthumb".$filestorename;
                                } else {
                                    $thumb->delete();
                                }
                                $thumb->close();
                            }
                           
                            if ($thumblarge) {
                                $thumb = new ElggFile();
                                $thumb->setMimeType($mime);
                                $thumb->setFilename($prefix."largethumb".$filestorename);
                                $thumb->open("write");
                                if ($thumb->write($thumblarge)) {
                                    $file->largethumb = $prefix."largethumb".$filestorename;
                                } else {
                                    $thumb->delete();
                                }
                                $thumb->close();
                            }

                            //gfroese: build the actual thumbnails now
                            try {
                                $thumblarge = tp_resize($file->getFilenameOnFilestore(), "largethumb", 600, 600, false);
                            } catch (Exception $e) { $thumblarge = false; }
                            try {
                                $thumbsmall = tp_resize($file->getFilenameOnFilestore(), "smallthumb", 153, 153, false);
                            } catch (Exception $e) { $thumbsmall = false; }
                            try {
                                $thumbnail = tp_resize($file->getFilenameOnFilestore(), "thumb", 60, 60, false);
                            } catch (Exception $e) { $thumbnail = false; }
                           
                        } else { //file exceeds file size limit, so delete it
                            $file->delete();
                            array_push($not_uploaded, $name);
                        } //end of file size check
                    } else { //file was not saved for some unknown reason
                        array_push($not_uploaded, $name);
                    } //end of file saved check and thumbnail creation
                } else { // file is not a supported image type
                    array_push($not_uploaded, $name);
                } //end of mimetype block
            } //end of file name empty check
        } //end of for loop
       
        if (count($not_uploaded) == 0) {
            system_message(elgg_echo("images:saved"));
        } else {
            $error = elgg_echo("image:uploadfailed") . '<br />';
            foreach($not_uploaded as $im_name){
                $error .= ' [' . $im_name . ']  ';
            }
            $error .= '  ' . elgg_echo("image:notimage");
            register_error($error);
        } //end of upload check
       
        if (count($uploaded_images)>0) {
            // successful upload so check if this is a new album and throw river event if so
            $album = get_entity($container_guid);
            if ($album->new_album == 1) {
                if (function_exists('add_to_river'))
                    add_to_river('river/object/album/create', 'create', $album->owner_guid, $album->guid);
                $album->new_album = 0;
            }
       
            forward($CONFIG->wwwroot . 'mod/tidypics/edit_multi.php?files=' . implode('-', $uploaded_images)); //forward to multi-image edit page
        } else {
            forward(get_input('forward_url', $_SERVER['HTTP_REFERER'])); //upload failed, so forward to previous page
        }

    ?>

    resize.php

    <?php

    function greg_test() {
        echo "worked\n";
    }
    /*
             * Gets the jpeg contents of the resized version of an already uploaded image
             * (Returns false if the uploaded file was not an image)
             *
             * @param string $input_name The name of the file input field on the submission form
         * @param string $output_name The name of the file to write the result to
             * @param int $maxwidth The maximum width of the resized image
             * @param int $maxheight The maximum height of the resized image
             * @param true|false $square If set to true, will take the smallest of maxwidth and maxheight and use it to set the dimensions on all size; the image will be cropped.
             * @return false|mixed The contents of the resized image, or false on failure
             */
            function tp_resize($input_name, $prefix, $maxwidth, $maxheight, $square = false, $x1 = 0, $y1 = 0, $x2 = 0, $y2 = 0) {
                    $params = array(
                        "input_name"=>$input_name,
                        "output_name"=>$output_name,
                        "maxwidth"=>$maxwidth,
                        "maxheight"=>$maxheight,
                        "square"=>$square,
                        "x1"=>$x1,
                        "y1"=>$y1,
                        "x2"=>$x2,
                        "y2"=>$y2);
                   
                    $path = pathinfo($input_name);
                    $output_name = $path["dirname"] . "/$prefix" . $path["filename"] . "." . $path["extension"];
                   
                    // Get the size information from the image
                    if ($imgsizearray = getimagesize($input_name)) {

                            // Get width and height
                            $width = $imgsizearray[0];
                            $height = $imgsizearray[1];
                            $newwidth = $width;
                            $newheight = $height;
                           
                            // Square the image dimensions if we're wanting a square image
                            if ($square) {
                                    if ($width < $height) {
                                            $height = $width;
                                    } else {
                                            $width = $height;
                                    }
                                   
                                    $newwidth = $width;
                                    $newheight = $height;
                                   
                            }

                            if ($width > $maxwidth) {
                                    $newheight = floor($height * ($maxwidth / $width));
                                    $newwidth = $maxwidth;
                            }
                            if ($newheight > $maxheight) {
                                    $newwidth = floor($newwidth * ($maxheight / $newheight));
                                    $newheight = $maxheight;
                            }

                            $accepted_formats = array(
                                                                                            'image/jpeg' => 'jpeg',
                                                                                            'image/png' => 'png',
                                                                                            'image/gif' => 'gif'
                                                                            );
                            // If it's a file we can manipulate ...
                            if (array_key_exists($imgsizearray['mime'],$accepted_formats)) {

    //                                $function = "imagecreatefrom" . $accepted_formats[$imgsizearray['mime']];
    //                                $newimage = imagecreatetruecolor($newwidth,$newheight);
                                   
    //                                if (is_callable($function) && $oldimage = $function($input_name)) {
                                            // Crop the image if we need a square
                                            if ($square) {
                                                    if ($x1 == 0 && $y1 == 0 && $x2 == 0 && $y2 ==0) {
                                                            $widthoffset = floor(($imgsizearray[0] - $width) / 2);
                                                            $heightoffset = floor(($imgsizearray[1] - $height) / 2);
                                                    } else {
                                                            $widthoffset = $x1;
                                                            $heightoffset = $y1;
                                                            $width = ($x2 - $x1);
                                                            $height = $width;
                                                    }
                                            } else {
                                                    if ($x1 == 0 && $y1 == 0 && $x2 == 0 && $y2 ==0) {
                                                            $widthoffset = 0;
                                                            $heightoffset = 0;
                                                    } else {
                                                            $widthoffset = $x1;
                                                            $heightoffset = $y1;
                                                            $width = ($x2 - $x1);
                                                            $height = ($y2 - $y1);
                                                    }
                                            }//else {
                                                    // Resize and return the image contents!
                                                    if ($square) {
                                                            $newheight = $maxheight;
                                                            $newwidth = $maxwidth;
                                                    }
    //                                                imagecopyresampled($newimage, $oldimage, 0,0,$widthoffset,$heightoffset,$newwidth,$newheight,$width,$height);
    //                                                imagejpeg($newimage, $output_name, 100);
                                                    $command = "convert $input_name -resize ".$newwidth."x".$newheight."^ $output_name";
                                                    $command = "convert $input_name -resize ".$newwidth."x".$newheight." $output_name";
                                                    system($command);
                                                    return true;
                                                   
                                            //}

                                            // imagecopyresized($newimage, $oldimage, 0,0,0,0,$newwidth,$newheight,$width,$height);
    //                                        ob_start();
    //                                        imagejpeg($newimage, null, 90);
    //                                        $jpeg = ob_get_clean();
    //                                        return $jpeg;

    //                                }
                            }
                    }

                    return false;
            }

    ?>

  • I'd also like to have the river updated each time a user uploads an image, how can I do that?

    looks like it is just a single call to add_to_river, but I don't understand the river well enough to get it working.  I was able to get the record in the database, but it broke the river when trying to actually view it.

  • @gfroese, thanks for the ImageMagick code.  Regarding river notifications, I think they are already in the SVN and will be part of the next Tidypics release. You should join the development project to contribute code. :)  http://code.google.com/p/tidypics  Shoot me an e-mail with your gmail address if you want to join.

  • @Gabriel

    how soon will be the next release?

  • I've just managed to hack in watermarking with the user's name on the full size image (the one in the album display, not the original).

    Works great, imagemagick again, will put code into svn when I get that setup.

  • @Cim @ Demyx.com -- Cash just performed the 100th commit to the code.  We are very much ready for testing, and you can get the latest code from our Google Code project: http://code.google.com/p/tidypics

    Once we've had enough users test it and have gotten enough feedback, we will be ready for the next release.

     

  • As a reminder, it is not recommened that you run code out of svn on a production site unless you have tested it first on a test site. We try to keep things stable as we develop, but that doesn't always happen.