forum.coppermine-gallery.net

Support => cpg1.5 plugins => cpg1.5.x Support => cpg1.5 plugin contributions => Topic started by: Timos-Welt on December 16, 2009, 02:23:34 pm

Title: Image manipulation for cpg1.5.x
Post by: Timos-Welt on December 16, 2009, 02:23:34 pm
This plugin allows the visitor to non-destructively manipulate pictures using new buttons on displayimage.php. Depending on the plugin configuration, the settings for each picture may be saved in a cookie on the visitor's computer (so if a picture is visited again, the old settings will be applied), and the URL may change accordingly (so if the visitor passes on the link, the recepient will see the pic just as the visitor likes it). Check the demo to see what all this means. The plugin will add ~30 kbyte of javascript to the page (slightly less in compatible mode).

Available effects in all browsers including Internet Explorer 5.5-8:

Available effects in all actual browsers but not in Microsoft's IE before version 9:

Browser compatibility:
The effects work fine with

Please note:

Demo (http://cpg15xdev.spaetbier.de/displayimage.php?pid=535&theme=timoswelt&lang=english#top_display_media)

SVN (https://coppermine.svn.sourceforge.net/svnroot/coppermine/branches/cpg1.5.x/plugins/image_manipulation/)

Download latest SVN snapshot (http://coppermine.svn.sourceforge.net/viewvc/coppermine/branches/cpg1.5.x/plugins/image_manipulation.tar.gz?view=tar) (use at own risk)

Download: http://sourceforge.net/projects/coppermine/files/Plugins/1.5.x/cpg1.5.x_plugin_image-manipulation_v2.1.zip/download

This plugin uses the great Pixastic Javascript library (http://www.pixastic.com) by Jacob Seidelin (MIT License).

Workaround for transparent overlay
If you like to have a transparent overlay over your images and don't use the annotate plugin, you may paste this to your theme.php to get it back (leave the setting on config page turned off when using this workaround). Use at your own risk and test carefully, especially with other plugins you use at the same time:
Code: [Select]
/******************************************************************************
** Section <<<theme_html_picture>>> - START
******************************************************************************/
// Displays a picture
function theme_html_picture()
{
    global $CONFIG, $CURRENT_PIC_DATA, $CURRENT_ALBUM_DATA, $USER, $LINEBREAK;
    global $album, $lang_date, $template_display_media;
    global $lang_display_image_php, $lang_picinfo, $lang_common, $lang_errors;

    $superCage = Inspekt::makeSuperCage();

    $pid = $CURRENT_PIC_DATA['pid'];
    $pic_title = '';

    if (!isset($USER['liv']) || !is_array($USER['liv'])) {
        $USER['liv'] = array();
    }
    // Add 1 to hit counter
    if ((!USER_IS_ADMIN && $CONFIG['count_admin_hits'] == 0 || $CONFIG['count_admin_hits'] == 1) && !in_array($pid, $USER['liv']) && $superCage->cookie->keyExists($CONFIG['cookie_name'] . '_data')) {
        add_hit($pid);
        if (count($USER['liv']) > 4) array_shift($USER['liv']);
        array_push($USER['liv'], $pid);
    }

    // The weird comparision is because only picture_width is stored
    if ($CONFIG['thumb_use']=='ht' && $CURRENT_PIC_DATA['pheight'] > $CONFIG['picture_width'] ) {
        $condition = true;
    } elseif ($CONFIG['thumb_use']=='wd' && $CURRENT_PIC_DATA['pwidth'] > $CONFIG['picture_width']) {
        $condition = true;
    } elseif ($CONFIG['thumb_use']=='any' && max($CURRENT_PIC_DATA['pwidth'], $CURRENT_PIC_DATA['pheight']) > $CONFIG['picture_width']) {
        $condition = true;
        //thumb cropping
    } elseif ($CONFIG['thumb_use']=='ex' && max($CURRENT_PIC_DATA['pwidth'], $CURRENT_PIC_DATA['pheight']) > $CONFIG['picture_width']) {
        $condition = true;
    } else {
        $condition = false;
    }

    if ($CURRENT_PIC_DATA['title'] != '') {
        $pic_title .= $CURRENT_PIC_DATA['title'] . $LINEBREAK;
    }
    if ($CURRENT_PIC_DATA['caption'] != '') {
        $pic_title .= $CURRENT_PIC_DATA['caption'] . $LINEBREAK;
    }
    if ($CURRENT_PIC_DATA['keywords'] != '') {
        $pic_title .= $lang_common['keywords'] . ": " . $CURRENT_PIC_DATA['keywords'];
    }

    if (!$CURRENT_PIC_DATA['title'] && !$CURRENT_PIC_DATA['caption']) {
        template_extract_block($template_display_media, 'img_desc');
    } else {
        if (!$CURRENT_PIC_DATA['title']) {
            template_extract_block($template_display_media, 'title');
        }
        if (!$CURRENT_PIC_DATA['caption']) {
            template_extract_block($template_display_media, 'caption');
        }
    }

    $CURRENT_PIC_DATA['menu'] = html_picture_menu(); //((USER_ADMIN_MODE && $CURRENT_ALBUM_DATA['category'] == FIRST_USER_CAT + USER_ID) || ($CONFIG['users_can_edit_pics'] && $CURRENT_PIC_DATA['owner_id'] == USER_ID && USER_ID != 0) || GALLERY_ADMIN_MODE) ? html_picture_menu($pid) : '';

    $image_size = array();

    if ($CONFIG['make_intermediate'] && $condition ) {
        $picture_url = get_pic_url($CURRENT_PIC_DATA, 'normal');
    } else {
        $picture_url = get_pic_url($CURRENT_PIC_DATA, 'fullsize');
    }

    list($image_size['width'], $image_size['height'], , $image_size['geom']) = cpg_getimagesize(urldecode($picture_url));

    $pic_title = '';
    $mime_content = cpg_get_type($CURRENT_PIC_DATA['filename']);

    if ($mime_content['content']=='movie' || $mime_content['content']=='audio') {

        if ($CURRENT_PIC_DATA['pwidth']==0 || $CURRENT_PIC_DATA['pheight']==0) {
            $CURRENT_PIC_DATA['pwidth']  = 320; // Default width

            // Set default height; if file is a movie
            if ($mime_content['content']=='movie') {
                $CURRENT_PIC_DATA['pheight'] = 240; // Default height
            }
        }

        $ctrl_offset['mov']=15;
        $ctrl_offset['wmv']=45;
        $ctrl_offset['swf']=0;
        $ctrl_offset['rm']=0;
        $ctrl_offset_default=45;
        $ctrl_height = (isset($ctrl_offset[$mime_content['extension']]))?($ctrl_offset[$mime_content['extension']]):$ctrl_offset_default;
        $image_size['whole']='width="'.$CURRENT_PIC_DATA['pwidth'].'" height="'.($CURRENT_PIC_DATA['pheight']+$ctrl_height).'"';
    }

    if ($mime_content['content']=='image') {
        if ($CURRENT_PIC_DATA['mode'] != 'fullsize') {
            $winsizeX = $CURRENT_PIC_DATA['pwidth'] + $CONFIG['fullsize_padding_x'];  //the +'s are the mysterious FF and IE paddings
            $winsizeY = $CURRENT_PIC_DATA['pheight'] + $CONFIG['fullsize_padding_y']; //the +'s are the mysterious FF and IE paddings
                $pic_html_href_close = '</a>' . $LINEBREAK;
                $pic_html = "<div style=\"text-align:center;\">";
                $pic_html .= "<div style=\"position:relative;margin:auto auto;width:{$image_size['width']}px;height:{$image_size['height']}px;\">";
                $pic_html .= "<img src=\"" . $picture_url . "\" {$image_size['geom']} class=\"image\" border=\"0\" alt=\"\" />";
                if (!USER_ID && $CONFIG['allow_unlogged_access'] <= 2) {
                    if ($CONFIG['allow_user_registration'] == 0) {
                        $pic_html_href_close = '';
                    } else {
                        $pic_html .= '<a href="javascript:;" onclick="alert(\''.sprintf($lang_errors['login_needed'],'','','','').'\');">';
                    }
                } elseif (USER_ID && USER_ACCESS_LEVEL <= 2) {
                    $pic_html .= '<a href="javascript:;" onclick="alert(\''.sprintf($lang_errors['access_intermediate_only'],'','','','').'\');">';
                } else {
                    $pic_html .= "<a href=\"javascript:;\" onclick=\"MM_openBrWindow('displayimage.php?pid=$pid&amp;fullsize=1','" . uniqid(rand()) . "','scrollbars=yes,toolbar=no,status=no,resizable=yes,width=$winsizeX,height=$winsizeY')\">";
                }
                $pic_title = $lang_display_image_php['view_fs'] . $LINEBREAK . '==============' . $LINEBREAK . $pic_title;
                $pic_html .= "<img src=\"images/image.gif?id=".floor(rand()*1000+rand())."\" width=\"{$image_size['width']}\" height=\"{$image_size['height']}\"  border=\"0\" alt=\"{$lang_display_image_php['view_fs']}\" style=\"position:absolute;left:0px;top:0px;margin:3px;";
                if ($pic_html_href_close) $pic_html .= "cursor:pointer;";
                $pic_html .= "\" />";
                $pic_html .= $pic_html_href_close."</div></div><br />";
                //PLUGIN FILTER
                $pic_html = CPGPluginAPI::filter('html_image_reduced_overlay', $pic_html);

        } else {
                $pic_html = "<div style=\"text-align:center;\">";
                $pic_html .= "<div style=\"position:relative;margin:auto auto;width:{$image_size['width']}px;height:{$image_size['height']}px;\">";
                $pic_html .= "<img src=\"" . $picture_url . "\" {$image_size['geom']} class=\"image\" border=\"0\" alt=\"\" /><br />" . $LINEBREAK;
                $pic_html .= "<img src=\"images/image.gif?id=".floor(rand()*1000+rand())."\" width=\"{$image_size['width']}\" height=\"{$image_size['height']}\"  border=\"0\" alt=\"\" style=\"position:absolute;left:0px;top:0px;margin:3px;\" />";
                $pic_html .= "</div></div><br />";
                //PLUGIN FILTER
                $pic_html = CPGPluginAPI::filter('html_image_overlay', $pic_html);
        }
    } elseif ($mime_content['content']=='document') {
        $pic_thumb_url = get_pic_url($CURRENT_PIC_DATA,'thumb');
        $pic_html = "<a href=\"{$picture_url}\" target=\"_blank\" class=\"document_link\"><img src=\"".$pic_thumb_url."\" border=\"0\" class=\"image\" /></a><br />" . $LINEBREAK;
        //PLUGIN FILTER
        $pic_html = CPGPluginAPI::filter('html_document', $pic_html);
    } else {
        $autostart = ($CONFIG['media_autostart']) ? ('true'):('false');

        if ($mime_content['player'] == 'HTMLA') {
            $pic_html  = '<audio controls="true" src="' . $picture_url . '" autostart="' . $autostart . '"></audio>';
        } elseif ($mime_content['player'] == 'HTMLV') {
            $pic_html  = '<video controls="true" src="' . $picture_url . '" autostart="' . $autostart . '"' . $image_size['whole'] . '></video>';
        } else {

            $players['WMP'] = array('id' => 'MediaPlayer',
                                    'clsid' => 'classid="clsid:22D6F312-B0F6-11D0-94AB-0080C74C7E95" ',
                                    'codebase' => 'codebase="http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701" ',
                                    'mime' => 'type="application/x-mplayer2" ',
                                   );
            $players['DIVX'] = array('id' => 'DivX',
                                    'clsid' => 'classid="clsid:67DABFBF-D0AB-41fa-9C46-CC0F21721616"',
                                    'codebase' => 'codebase="http://go.divx.com/plugin/DivXBrowserPlugin.cab"',
                                    'mime' => 'type="video/divx"'
                                   );
            $players['RMP'] = array('id' => 'RealPlayer',
                                    'clsid' => 'classid="clsid:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA" ',
                                    'codebase' => '',
                                    'mime' => 'type="audio/x-pn-realaudio-plugin" '
                                   );
            $players['QT']  = array('id' => 'QuickTime',
                                    'clsid' => 'classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" ',
                                    'codebase' => 'codebase="http://www.apple.com/qtactivex/qtplugin.cab" ',
                                    'mime' => 'type="video/x-quicktime" '
                                   );
            $players['SWF'] = array('id' => 'SWFlash',
                                    'clsid' => ' classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" ',
                                    'codebase' => 'codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0" ',
                                    'mime' => 'type="application/x-shockwave-flash" '
                                   );
            $players['UNK'] = array('id' => 'DefaultPlayer',
                                    'clsid' => '',
                                    'codebase' => '',
                                    'mime' => ''
                                   );

            $player = $players[$mime_content['player']];

            if (!$player) {
                $player = 'UNK';
            }

            $pic_html  = '<object id="'.$player['id'].'" '.$player['classid'].$player['codebase'].$player['mime'].$image_size['whole'].'>';
            $pic_html .= "<param name=\"autostart\" value=\"$autostart\" /><param name=\"src\" value=\"". $picture_url . "\" />";
            $pic_html .= '</object><br />' . $LINEBREAK;
        }

        //PLUGIN FILTER
        $pic_html = CPGPluginAPI::filter('html_other_media', $pic_html);
    }

    $CURRENT_PIC_DATA['html'] = $pic_html;
    $CURRENT_PIC_DATA['header'] = '';
    $CURRENT_PIC_DATA['footer'] = '';

    $CURRENT_PIC_DATA = CPGPluginAPI::filter('file_data',$CURRENT_PIC_DATA);

    $params = array('{CELL_HEIGHT}' => '100',
        '{IMAGE}' => $CURRENT_PIC_DATA['header'].$CURRENT_PIC_DATA['html'].$CURRENT_PIC_DATA['footer'],
        '{ADMIN_MENU}' => $CURRENT_PIC_DATA['menu'],
        '{TITLE}' => bb_decode($CURRENT_PIC_DATA['title']),
        '{CAPTION}' => bb_decode($CURRENT_PIC_DATA['caption']),
        );

    return template_eval($template_display_media, $params);
}

/******************************************************************************
** Section <<<theme_html_picture>>> - END
******************************************************************************/

/******************************************************************************
** Section <<<theme_display_fullsize_pic>>> - START
******************************************************************************/
// Display the full size image
function theme_display_fullsize_pic()
{
    global $CONFIG, $THEME_DIR, $FORBIDDEN_SET, $LINEBREAK, $pid;
    global $lang_errors, $lang_fullsize_popup, $lang_charset;

    $superCage = Inspekt::makeSuperCage();

    if (!USER_ID && $CONFIG['allow_unlogged_access'] <= 2) {
        printf($lang_errors['login_needed'],'','','','');
        die();
    } elseif (USER_ID && USER_ACCESS_LEVEL <= 2) {
        printf($lang_errors['access_intermediate_only'],'','','','');
        die();
    }
    if ($superCage->get->keyExists('picfile')) {
        if (!GALLERY_ADMIN_MODE) {
            cpg_die(ERROR, $lang_errors['access_denied'], __FILE__, __LINE__);
        }
        //$picfile = $_GET['picfile'];
        //$picfile = $superCage->get->getPath('picfile'); // doesn't work with HTML entities
        $matches = $superCage->get->getMatched('picfile', '/^[0-9A-Za-z\/_.-]+$/');
        $picfile = $matches[0];
        $picname = $CONFIG['fullpath'] . $picfile;
        $imagesize = @getimagesize($picname);
        $imagedata = array('name' => $picfile, 'path' => path2url($picname), 'geometry' => $imagesize[3]);
    } elseif ($pid) {
        $sql = "SELECT filepath, filename, url_prefix, pwidth, pheight FROM {$CONFIG['TABLE_PICTURES']} AS p " . "WHERE pid='$pid' $FORBIDDEN_SET";
        $result = cpg_db_query($sql);
        if (!mysql_num_rows($result)) {
            cpg_die(ERROR, $lang_errors['non_exist_ap'], __FILE__, __LINE__);
        }
        $row = mysql_fetch_assoc($result);
        $pic_url = get_pic_url($row, 'fullsize');
        $geom = 'width="' . $row['pwidth'] . '" height="' . $row['pheight'] . '"';
        $imagedata = array('name' => $row['filename'], 'path' => $pic_url, 'geometry' => $geom);
    }
    if ((!USER_ID && $CONFIG['allow_unlogged_access'] <= 2) || (USER_ID && USER_ACCESS_LEVEL <= 2)) {
        // adjust the size of the window if we don't have to catter for a full-size pop-up, but only a text message
        $row['pwidth'] = 200;
        $row['pheight'] = 100;
    }

    $charset = ($CONFIG['charset'] == 'language file' ? $lang_charset : $CONFIG['charset']);
    $fullsize_html = <<<EOT
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
    <head>
        <meta http-equiv="content-type" content="text/html; charset=$charset" />
        <title>{$CONFIG['gallery_name']}: {$lang_fullsize_popup['click_to_close']}</title>
        <style type="text/css">
            body { margin: 0; padding: 0; background-color: gray; }
            img { margin:0; padding:0; border:0; }
            #content { margin:0 auto; padding:0; border:0; }
            table { border:0; width:{$row['pwidth']}px; height:{$row['pheight']}px; border-collapse:collapse}
            td { vertical-align: middle; text-align:center; }
        </style>

        <script type="text/javascript" src="js/jquery-1.3.2.js"></script>
        <script type="text/javascript" src="js/jquery.dimensions.pack.js"></script>
        <script type="text/javascript" src="js/displayimage.fullsize.js"></script>
    </head>
    <body style="margin:0px; padding:0px; background-color: gray;">

EOT;

        $fullsize_html .= <<<EOT
        <table cellpadding="0" cellspacing="0" align="center" style="padding:0px;">
            <tr>

EOT;
        $fullsize_html .=  '<td align="center" valign="middle" background="' . htmlspecialchars($imagedata['path']) . '" ' . $imagedata['geometry'] . ' class="image">';
        $fullsize_html .=  '<div id="content">';
        $fullsize_html .=  '<a href="javascript: window.close()" style="border:none"><img src="images/image.gif?id='
                . floor(rand()*1000+rand())
                . '&amp;fullsize=yes" '
                . $imagedata['geometry']
                . ' alt="'
                . htmlspecialchars($imagedata['name'])
                . '" title="'
                . htmlspecialchars($imagedata['name'])
                . $LINEBREAK . $lang_fullsize_popup['click_to_close']
                . '" /></a><br />' . $LINEBREAK;
        $fullsize_html .=  <<<EOT
                    </div>
                </td>
            </tr>
        </table>
  </body>
</html>

EOT;

    $fullsize_html = CPGPluginAPI::filter('fullsize_html', $fullsize_html);
    echo $fullsize_html;
}
/******************************************************************************
** Section <<<theme_display_fullsize_pic>>> - END
******************************************************************************/

Title: Re: Image manipulation
Post by: Αndré on December 16, 2009, 03:09:20 pm
Nice plugin.

I suggest to move the 'Reset' button to the right, as people who just 'play' with the buttons will start from the left and nothing will happen ;)
Title: Re: Image manipulation
Post by: Αndré on December 16, 2009, 03:40:13 pm
Turn off 'add transparent overlay to avoid image theft' to make this plugin work.
This should automatically be done at plugin installation imo.
Title: Re: Image manipulation
Post by: Αndré on December 16, 2009, 03:51:41 pm
Is there a reason why you only have built in these effects
  • reset
  • blur
  • b/w
  • invert
  • emboss
  • flip vert (IE only)
  • flip hori (IE only)
  • lighten (not in IE)
  • darken (not in IE)
  • solarize (not in IE)
?

There are more available effects, that should be configurable by the admin:
Quote from: http://www.pixastic.com/lib/download/
Blend
Blur
Blur Fast
Brightness/Contrast
Color Adjust
Color Histogram
Crop
Desaturate
Edge Detection
Edge Detection 2
Emboss
Flip
Flip Horizontally
Flip Vertically
Glow
Histogram
Hue/Saturation/Lightness
Invert
Laplace Edge Detection
Lighten
Mosaic
Noise
Posterize
Pointillize
Remove Noise
Resize
Rotate
Sepia
Sharpen
Solarize
Unsharp Mask
Title: Re: Image manipulation
Post by: Timos-Welt on December 16, 2009, 05:13:18 pm
Just released 0.2 that fixes a lot of display bugs at cost of performance and enables Lighten/Darken buttons for IE, too.

Andre:
Most of the effects are not compatible with all browsers or versions. Flip should work in Firefox, too, but it doesn't ATM (that's why the buttons are only available in IE). I think I'll contact the developer about that issue.

What works everywhere is blur, b/w, invert, emboss, flip, lighten and darken. I think I'll remove solarize as soon as flip works with any browser.
Title: Re: Image manipulation
Post by: Timos-Welt on December 16, 2009, 08:07:12 pm
Found the flip bug - v0.3 works identically in any modern browser.
Title: Re: Image manipulation
Post by: Pascal YAP on December 16, 2009, 09:52:02 pm
WoW I'm speechless :-)))))) Amazing plugin Tim ;D
Title: Re: Image manipulation
Post by: Timos-Welt on December 17, 2009, 02:20:58 pm
v0.4:
- fixed: buttons were visible for non-images
- improvement: toggle buttons show their state
Title: Re: Image manipulation
Post by: Timos-Welt on December 17, 2009, 03:07:04 pm
Feedback from the developer of the Pixastic Javascript library Jacob Seidelin:

"Pixastic is currently licensed under the MPL but I plan to extend that to a MPL/GPL dual license when I get around to updating the necessary files/pages - so, there shouldn't be a problem with you bundling it with your plugin. Just make sure the copyright and license information for Pixastic is included as well (the commented part in the top)."

 :)
Title: Re: Image manipulation
Post by: Timos-Welt on December 18, 2009, 05:09:19 pm
v0.5 adds a slider for pic brightness
Title: Re: Image manipulation
Post by: Αndré on December 18, 2009, 07:44:37 pm
Nice :) But I still miss at least the Sepia effect ;)
Title: Re: Image manipulation
Post by: Timos-Welt on December 21, 2009, 12:47:34 pm
No problem to code, but where's the sense in implementing something that won't work with every mainstream browser? There's a Google project (http://code.google.com/p/explorercanvas/) implementing canvas functions into IE - feel free to add it and test it out.
Title: Re: Image manipulation
Post by: Αndré on December 21, 2009, 02:29:09 pm
We could determine by whitelist or blacklist to add buttons for effects that don't work in the user's browser.
Title: Re: Image manipulation
Post by: Timos-Welt on December 21, 2009, 04:57:43 pm
Potential source for misunderstandings and frustration. User A visits your gallery and writes a comment 'have a look at the image in sepia, it's great'. User B visits your gallery using a different browser and can't find the button for the sepia effect... A perfect way to make support effort appear from nowhere.

The current implementation focuses on compatibility. IE 5.5+, FF 2+, Opera 9.5+, Chrome 3+ will all work the same way, so >90% of the visitors should see the gallery as it is meant to be seen, including some nice new controls to play with. Do you want to have jam on it, too?
Title: Re: Image manipulation
Post by: Αndré on December 21, 2009, 06:13:18 pm
Okay I can see your point. But can't we add a config panel where the admin can choose which buttons he want to display (if the user's browser supports that effect) and add some explanation like "This effect works only on the following browsers: xyz. It's a potential source for misunderstandings and frustration if your users talk about the effects using different browsers."?
Title: Re: Image manipulation
Post by: Timos-Welt on December 22, 2009, 05:32:24 pm
Ok, ok, v0.6 has a compatibility mode, and if you turn it off, it will give new effects in other browsers than IE (contrast, saturation, sharpness, sepia). It is not recommended to turn it off. See demo in IE or FF to see the difference.
Title: Re: Image manipulation
Post by: Αndré on December 22, 2009, 05:38:15 pm
Thank you so much, Timo :-*
Title: Re: Image manipulation
Post by: Timos-Welt on December 27, 2009, 02:06:13 pm
V0.7 adds dynamic URL manipulation, so if you find you preferred settings for a pic and pass the URL to someone else, he/she will see the pic as you liked it.
Title: Re: Image manipulation
Post by: Timos-Welt on December 29, 2009, 03:00:09 pm
v0.8 adds cookie support, so if a visitor visits the same pic later, his settings will be remembered and applied automatically.
Title: Re: Image manipulation for cpg1.5.x
Post by: Timos-Welt on December 31, 2009, 12:04:38 pm
This plugin has finally reached v1.0 and is now a genuine cpg plugin. Have fun with it.

Localisations are welcome!
Title: Re: Image manipulation for cpg1.5.x
Post by: François Keller on December 31, 2009, 01:22:40 pm
french lang file attached
Title: Re: Image manipulation for cpg1.5.x
Post by: Timos-Welt on December 31, 2009, 02:16:39 pm
Thanks François!

v1.1 adds french localization and HTML docs
Title: Re: Image manipulation for cpg1.5.x
Post by: Joachim Müller on January 08, 2010, 06:20:59 pm
Added various improvements to version 1.3 of the plugin in the subversion repository.
Timo, please let me know what you think of my edits.
Cheers

Title: Re: Image manipulation for cpg1.5.x
Post by: Αndré on January 08, 2010, 06:42:16 pm
Version 1.3 doesn't display the status of the toggle buttons (they became red in earlier versions).
Title: Re: Image manipulation for cpg1.5.x
Post by: Timos-Welt on January 08, 2010, 08:11:02 pm
Settings on config page cannot be saved with v1.3.
Toggle button borders don't work anymore (Andre already said this).
The icon thing is really nice.
Title: Re: Image manipulation for cpg1.5.x
Post by: Timos-Welt on January 09, 2010, 11:12:27 am
Settings on config page cannot be saved with v1.3.

False alarm, this works as it should. One has to uninstall 1.2 first before installing 1.3.

V1.4 (see first post) fixes the toggle button issue.
Title: Re: Image manipulation for cpg1.5.x
Post by: Joachim Müller on January 09, 2010, 06:22:36 pm
Thanks for your feedback. I have added some more gimmicks; attached is v1.5, which features some more improvements including to toggle each control individually (this is what I wanted to achieve in the first place for my personal needs). This replaces the compatibility mode setting (which I found confusing in the first place). Anyway, in the end the compatibility mode sort-of survived: the proper JS lib is included depending on the admin's preferences and the visitor's browser.
During development of a plugin it's mandatory to uninstall, then perform the SVN checkout, then re-install.
Thanks for resolving the issues you brought up.
Title: Re: Image manipulation for cpg1.5.x
Post by: Timos-Welt on January 10, 2010, 08:27:27 pm
V1.5 is really nice.

We often assess the importance of keeping things as small as possible very differently (and in the end one reason for compatibility mode was to keep the JS files as small as possible). I am really glad that you kept it 'under the hood' - it saves 5,6 Kbyte of stuff to load.

V1.6 adds the missing icons for the LED sliders. Was a bit 'tricky' to make this work. ;-)
Title: Re: Image manipulation for cpg1.5.x
Post by: Timos-Welt on January 13, 2010, 04:58:46 pm
v1.7 includes the latest changes.
Title: Re: Image manipulation for cpg1.5.x
Post by: Αndré on January 13, 2010, 06:00:59 pm
v1.7 includes a bug ;) Instead of the sharpness image 'undefined' is displayed. See attachment.
Title: Re: Image manipulation for cpg1.5.x
Post by: Timos-Welt on January 13, 2010, 06:53:08 pm
No bug. Clear your browser cache.
Title: Re: Image manipulation for cpg1.5.x
Post by: Timos-Welt on January 13, 2010, 07:00:26 pm
Indeed bug. Will be fixed with 1.8.
Title: Re: Image manipulation for cpg1.5.x
Post by: Timos-Welt on January 13, 2010, 08:50:52 pm
Fixed.
Title: Re: Image manipulation for cpg1.5.x
Post by: Αndré on January 14, 2010, 09:58:04 am
Okay works now (nice sword 8)).

You use <button>s as labels for the sliders. Nothing happens if you click on that buttons (neither in my local testbed nor in your online testbed). Will these buttons get a function in a future release? If not, I suggest not to use buttons, as people like me click madly on that buttons and wonder why nothing happens ;D
Title: Re: Image manipulation for cpg1.5.x
Post by: phill104 on January 14, 2010, 10:58:05 am
Yep, I did the same as Andre
Title: Re: Image manipulation for cpg1.5.x
Post by: Timos-Welt on January 14, 2010, 12:29:50 pm
It must be buttons to make it work.
Title: Re: Image manipulation for cpg1.5.x
Post by: Αndré on January 14, 2010, 12:54:31 pm
That's not true. It works very well if you replace
Code: [Select]
function im_makeled(im_buttonstring,im_idstring,im_valstring,im_iconblub)
{
    var im_tempstr = '';
    if (im_buttonstring)
    {
        im_tempstr += '<button class="admin_menu" style="border:none;background-color:transparent;background-image:none;">'+im_buttonstring+' '+im_iconblub+' &#150; </button><span></span>';
        for(var im_i=-9;im_i<10;im_i++)
        {
            im_tempstr += '<a style="height:10px;border-bottom-width:1px;border-left-width:1px;border-top-width:1px;border-right-width:0px;border-style:solid;text-decoration:none;border-color:#222233;cursor:pointer" id="'+im_idstring+im_i+'" onclick="'+im_valstring+' = parseInt(this.id.substr(4)); im_setit();">&nbsp;</a>';
        }
        im_tempstr += '<a style="height:10px;border-width:1px;border-style:solid;text-decoration:none;border-color:#222233;cursor:pointer" id="'+im_idstring+'10" onclick="'+im_valstring+' = parseInt(this.id.substr(4)); im_setit();">&nbsp;</a>';
        im_tempstr += '<button class="admin_menu" style="border:none;background-color:transparent;background-image:none;"> + '+im_iconblub+' '+im_buttonstring+'</button><br />';
       
    }
    return im_tempstr;
}
with
Code: [Select]
function im_makeled(im_buttonstring,im_idstring,im_valstring,im_iconblub)
{
    var im_tempstr = '';
    if (im_buttonstring)
    {
        im_tempstr += '<span class="admin_menu" style="border:none;background-color:transparent;background-image:none;">'+im_buttonstring+' '+im_iconblub+' &#150; </span><span></span>';
        for(var im_i=-9;im_i<10;im_i++)
        {
            im_tempstr += '<a style="height:10px;border-bottom-width:1px;border-left-width:1px;border-top-width:1px;border-right-width:0px;border-style:solid;text-decoration:none;border-color:#222233;cursor:pointer" id="'+im_idstring+im_i+'" onclick="'+im_valstring+' = parseInt(this.id.substr(4)); im_setit();">&nbsp;</a>';
        }
        im_tempstr += '<a style="height:10px;border-width:1px;border-style:solid;text-decoration:none;border-color:#222233;cursor:pointer" id="'+im_idstring+'10" onclick="'+im_valstring+' = parseInt(this.id.substr(4)); im_setit();">&nbsp;</a>';
        im_tempstr += '<span class="admin_menu" style="border:none;background-color:transparent;background-image:none;"> + '+im_iconblub+' '+im_buttonstring+'</span><br />';
       
    }
    return im_tempstr;
}
Title: Re: Image manipulation for cpg1.5.x
Post by: Timos-Welt on January 14, 2010, 02:20:26 pm
Please test very carefully in all browsers. In some FF and Opera versions the effects havent been applied in one step but one after each other with screen redraws inbetween using span instead of buttons. That's as well the reason for the empty span tag. If your change works everywhere, feel free to commit it!
Title: Re: Image manipulation for cpg1.5.x
Post by: Αndré on January 14, 2010, 02:55:13 pm
In some FF and Opera versions the effects havent been applied in one step but one after each other with screen redraws inbetween
I can confirm that behavior, but cannot replicate it reliably. But it exists in the current version, too. I've tested it on my local testbed and my gallery. It seems that it occurs after a page reload (ctrl+shift+r in Firefox). Your online testbed currently returns a blank page, so I cannot test it there.

I'll try to investigate.


Edit: just tested at your production gallery. Problems also occurs there if I press ctrl+shift+r in Firefox.
Title: Re: Image manipulation for cpg1.5.x
Post by: Αndré on January 14, 2010, 03:38:28 pm
Okay here is what I found out using v1.8.

View an intermediate sized picture. Everything works fine.
Then (using Firefox) press ctrl+shift+r or ctrl+f5 (with that shortcuts you reload the page without loading data from the cache). Now the different effects will be applied after each other.
Now press f5 or call the page again. Everything works fine.

I cannot replicate that behavior in Chrome, as I don't know the correct shortcuts or the bug doesn't exist there.
Title: Re: Image manipulation for cpg1.5.x
Post by: Timos-Welt on January 15, 2010, 03:37:56 pm
@Joachim:
Your changes in install/uninstall functions seems to have introduced a bug for me, see screen shot. I assume it's again a wrong cr/lf thing (see screen shot), but even if I correct it, I get

Code: [Select]
While executing query 'UPDATE cpg15x_config SET value= WHERE name='transparent_overlay'' in plugins/image_manipulation/codebase.php on line 171

mySQL error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'WHERE name='transparent_overlay'' at line 1

everytime trying to uninstall the plugin.
Title: Re: Image manipulation for cpg1.5.x
Post by: Joachim Müller on January 16, 2010, 10:28:31 am
Not sure what went wrong. Please try rev 7066.
Title: Re: Image manipulation for cpg1.5.x
Post by: Timos-Welt on January 16, 2010, 02:07:39 pm
Fixed in SVN
Title: Re: Image manipulation for cpg1.5.x
Post by: Αndré on January 16, 2010, 03:50:59 pm
Okay here is what I found out using v1.8.

View an intermediate sized picture. Everything works fine.
Then (using Firefox) press ctrl+shift+r or ctrl+f5 (with that shortcuts you reload the page without loading data from the cache). Now the different effects will be applied after each other.
Now press f5 or call the page again. Everything works fine.

I cannot replicate that behavior in Chrome, as I don't know the correct shortcuts or the bug doesn't exist there.
Can someone confirm that behavior? I cannot reproduce it without the mentioned page reload, even if I remove the <button> tags.
Title: Re: Image manipulation for cpg1.5.x
Post by: Timos-Welt on January 16, 2010, 07:51:07 pm
That's correct, behaves here the same way, but only after force reload.
Title: Re: Image manipulation for cpg1.5.x
Post by: Αndré on January 17, 2010, 10:42:47 am
I removed the <button> tags from the sliders in r7080. I cannot determine any unexpected behavior. Can everyone please test if the effects are applied simultaneously and not one after each other? Thanks.
Title: Re: Image manipulation for cpg1.5.x
Post by: Timos-Welt on January 17, 2010, 10:50:19 am
Works, but doesn't look nice with my skin (or classic) because you removed the button class and now the font of the LED description is different from the button description.
Title: Re: Image manipulation for cpg1.5.x
Post by: Αndré on January 17, 2010, 11:11:56 am
You're right. I hadn't noticed that. Changed in r7081.
Title: Re: Image manipulation for cpg1.5.x
Post by: Timos-Welt on January 17, 2010, 12:05:16 pm
Released v2.0. I don't think there's much more room for improvement to be honest.
Title: Re: Image manipulation for cpg1.5.x
Post by: dougyang83 on January 25, 2010, 09:27:18 am
nothing happen... something wrong?
Title: Re: Image manipulation for cpg1.5.x
Post by: phill104 on January 25, 2010, 09:29:27 am
nothing happen... something wrong?

Is that supposed to be a test report? You should be aware that there is currently no support for CPG1.5.x. Additionally you should read the board rules - http://forum.coppermine-gallery.net/index.php/topic,55415.msg270616.html#msg270616
Title: Re: Image manipulation for cpg1.5.x
Post by: Joachim Müller on January 25, 2010, 11:26:57 am
That guy is a board spammer. I'm just currently deleting his postings and banning him.
Title: Re: Image manipulation for cpg1.5.x
Post by: Αndré on January 27, 2010, 12:04:09 pm
I noticed an issue.

Set 'Use cookies' to 'Yes' and login as admin or user. Now view some pictures (in my case I try to view a whole album, start at the first image and click 'next', 'next', 'next', ...).

After a few pictures (sometimes 1, sometimes >50) I get logged out. Reason: the session cookie will be updated (or a new one is created and the old one deleted, I'm not sure). The client_id (cookie name) stays the same, but the session_id (cookie value) differs.

I haven't figured out why it happens. Everything works fine if you disable the cookie usage in the plugin configuration.

Can someone confirm that issue? I tested it with Firefox 3.5, Chrome 3, IE6 and IE8 on my online gallery (updated from 1.3.x -> 1.4.x -> 1.5.x) with lots of plugins and on a new local installation without any other plugin installed.


I've attached 3 screen shots of my Firefox cookie console (if you keep it opened while surfing, it doesn't remove 'old' cookies. If I re-open my cookie console, only one cookie (the latest) exists).


Edit: I've traced it back to that function
Code: (plugins/image_manipulation/js/image_manipulation.js) [Select]
function im_createCookie(im_name,im_value) {
    var im_date = new Date();
    im_date.setTime(im_date.getTime()+62208000000);
    var im_expires = "; expires="+im_date.toGMTString();
    document.cookie = im_name+"="+im_value+im_expires+"; path=/";
}
Maybe it's better to save only one cookie that consists an encoded array instead of saving one cookie per image?
Title: Re: Image manipulation for cpg1.5.x
Post by: Timos-Welt on January 28, 2010, 03:58:11 pm
Please check the current SVN version, try it out and give some feedback if it improves things for you and if it works correctly.
It is impossible to save all data to just one cookie (max cookie size is 4096 byte). So the script will now use one cookie per 100 files, meaning
0 <= pid < 100 is saved in cookie im_0
100 <= pid < 200 is saved in cookie im_1
200 <= pid < 300 is saved in cookie im_2
...
So the number of cookies has dropped to a hundredth. Hopefully this won't overstrain Firefox anymore.  ;)
Title: Re: Image manipulation for cpg1.5.x
Post by: Timos-Welt on January 28, 2010, 04:05:49 pm
BTW:
Number of cookies per domain allowed in modern browsers are
IE7/IE8 => 50
Firefox => 50
Opera => 30
Safari => no limit

If you set more cookies, the oldest ones will be deleted. So the new cookie solution will work for galleries with 4500 files without a problem in most browsers, but afterwards we're in trouble again... In the long run, it would be sensible to save the value in the database via PHP / AJAX.
Title: Re: Image manipulation for cpg1.5.x
Post by: phill104 on January 28, 2010, 04:39:49 pm
What do you propose, adding it to the users table? Could lead to some very big databases. Maybe have an admin tool to clear data for any user that has not visited for x days.
Title: Re: Image manipulation for cpg1.5.x
Post by: Αndré on January 28, 2010, 04:48:20 pm
Seems to work better now. I've viewed about 400 pictures and didn't get logged out.

I suggest adding the data to the cookie only if the user has manipulated the image (value != 0). Currently I have cookie contents like
Code: (Cookie 'im_877') [Select]
_87753_0_87754_0_87755_0_87756_0_87757_0_87758_0_87759_0_87760_0_87761_0_87762_0_87763_0_87764_0_87765_0_87766_0_87767_0_87768_0_87769_0_87770_0_87771_0_87772_0_87773_0_87774_0_87775_0_87776_0_87777_0_87778_0_87779_0_87780_0_87781_0_87782_0_87783_0_87784_0_87785_0_87786_0_87787_0_87788_0_87789_0_87790_0_87792_0_87793_0_87794_0_87795_0_87796_0_87797_0_87798_0_87799_0_87701_0_87703_0_87705_0_87707_0_87709_0_87711_0_87713_0_87715_0_87717_0_87719_0_87721_0_87723_0_87725_0_87727_0_87729_0_87730_0_87731_0_87732_0_87733_0_87734_0_87735_0_87736_0_87737_0_87738_0_87739_0_87740_0_87741_0_87742_0_87744_0_87745_0_87746_0_87747_0_87748_0_87749_0_87750_0_87751_0_87752_0
Furthermore you could store only the pid%100 instead of the whole pid (i.e. if the pid is 87753 and the cookie name is im_877 you store only '53') and then drop one underscore to save some space.

Example.
Now:
Code: (Cookie 'im_877') [Select]
_87753_0_87754_0_87755_0_87756_0_87757_0
With my suggestion:
Code: (Cookie 'im_877') [Select]
530_540_550_560_570

What do you propose, adding it to the users table? Could lead to some very big databases.
Yes. That should be configurable in the plugin config. First we need to change the code in a way, that it don't stores unmanipulated images (value = 0).
If you think of exif data and hit/voting stats tables, we already have some space consumer. But that's the decision of the webmaster.
Title: Re: Image manipulation for cpg1.5.x
Post by: Timos-Welt on January 28, 2010, 04:54:37 pm
Just did that and encoded the values with toString / parseInt so we have now 400 pids per cookie. Meaning it will work in galleries with up to 18000 pid's. Values of 0 are not saved anymore. I think that's enough for most purposes.
Title: Re: Image manipulation for cpg1.5.x
Post by: Joachim Müller on January 28, 2010, 05:01:31 pm
I second Phill's suggestion to store stuff inside the database and not inside the cookie. Pruning old records in the database is of course mandatory. This should take care of registered users, which is our target audience imo. The feature to store something is not that important for guests imo - we could store some stuff inside a cookie for the guests, but ideally only a unique visitor ID that correlates to the database table that actually stores the per pic preferences.
If you decide to implement storage inside the database I suggest to ask the admin on the plugin's config screen what amount of records should be kept before the pruning of older records (the database garbage collection) kicks in. You could provide an estimate there as well about the space consumption of those records inside the database.
However, I suggest coming up with a database table of it's own instead of using the user table - to keep our table clean. Additional benefit would be that the unique ID for the guest and subsequently storage of the guest records inside the database could be implemented that way as well.
Using more than one cookie is bad design imo and should be discarded.
Title: Re: Image manipulation for cpg1.5.x
Post by: Timos-Welt on January 28, 2010, 05:13:39 pm
Might be a good way to handle it, but this would produce one AJAX request everytime a button or LED slider is touched.  :o
I think that's just plain overkill for many servers, and it certainly would drop the performance of the plugin in a negative way.
Title: Re: Image manipulation for cpg1.5.x
Post by: Joachim Müller on January 28, 2010, 05:21:53 pm
Then use the cookie as a temporary storage: write the data you need to write to the cookie. On the next pageload, read the data from the cookie and write that to the database. You end up with "delayed" storage, but the result would be the same imo.
Title: Re: Image manipulation for cpg1.5.x
Post by: Timos-Welt on January 28, 2010, 05:45:16 pm
I probably won't, sorry. I am absolutely sure that my gallery will not come beyond 18,000 files in the next ten years, so I have time untill cpg 2.7.x I think (and I love JS, but I hate php/sql).  ;)

I'll add a remark to the docs that use of cookies should be turned off if there are PIDs in the gallery > 10,000 to make sure everything works fine. If anyone is interested => feel free, this is GPL!  ;D
Title: Re: Image manipulation for cpg1.5.x
Post by: Αndré on January 28, 2010, 05:52:59 pm
Then use the cookie as a temporary storage: write the data you need to write to the cookie. On the next pageload, read the data from the cookie and write that to the database. You end up with "delayed" storage, but the result would be the same imo.
The result is a different one, if the user closes the page after image manipulation.
Title: Re: Image manipulation for cpg1.5.x
Post by: Timos-Welt on January 28, 2010, 10:10:42 pm
Released v2.2.
Title: Re: Image manipulation for cpg1.5.x
Post by: Joachim Müller on January 29, 2010, 07:33:40 am
I'll add a remark to the docs that use of cookies should be turned off if there are PIDs in the gallery > 10,000 to make sure everything works fine.
You could even add a check to the install function in codebase.php for that number of images.
Title: Re: Image manipulation for cpg1.5.x
Post by: Timos-Welt on January 29, 2010, 08:16:13 am
I slept on it. I think it's better to make the number of cookies to be used configurable, merge all data to one array and save them in packets of 300 to the cookies. This way, the limit wouldn't be PIDs < 18000, but the visitor would have to actively change the settings of 6,000 images in the gallery before a problem might occur (if number of cookies is set to 20 which is very save). Further we'd have only the number of cookies we really need (in 99% of all cases 1) instead of 1 per 100 PIDs. And we could implement a FIFO mechanism, so if the visitor clicks on the buttons of the 6,001st pic, the oldest data would get deleted. Shouldn't be too much work, and I think it's very unlikely that a visitor really modifies the settings of more than 6000 images of a gallery.
Title: Re: Image manipulation for cpg1.5.x
Post by: Αndré on February 17, 2010, 02:04:53 pm
Version 2.2 attached in initial post.

Changelog:
Title: Re: Image manipulation for cpg1.5.x
Post by: Chylly Kayza on April 22, 2011, 01:49:19 am
Hello,

first of all, very nice plugin!

I tried to add a break between the buttons for flip vert. and flip horiz. because it breaks the table on the page where the filmstrip sits.

Can anybody help?

Thanx in advance

Title: Re: Image manipulation for cpg1.5.x
Post by: Αndré on April 26, 2011, 02:04:58 pm
Open js/image_manipulation.js, find
Code: [Select]
im_btn.innerHTML += ' <button value="'+js_vars.im_strflipv+'" id="but_flipv" onclick="im_isflipv = (im_isflipv) ? 0 : 1; '+'im_setit();" class="button" style="cursor:pointer;margin-top:4px;" type="button">'+js_vars.im_icon_flipv+js_vars.im_strflipv+'</button>';and replace with
Code: [Select]
im_btn.innerHTML += ' <br /><button value="'+js_vars.im_strflipv+'" id="but_flipv" onclick="im_isflipv = (im_isflipv) ? 0 : 1; '+'im_setit();" class="button" style="cursor:pointer;margin-top:4px;" type="button">'+js_vars.im_icon_flipv+js_vars.im_strflipv+'</button>';
Title: Re: Image manipulation for cpg1.5.x
Post by: Chylly Kayza on April 26, 2011, 02:20:18 pm
Thank you...it works!
Title: Re: Image manipulation for cpg1.5.x
Post by: Timos-Welt on July 11, 2011, 11:19:19 am
I have attached a new version (2.3) to the first posting of this thread.

New:
Support for IE 9 in standards mode  - no more limitations in the newest Internet Explorer, because it finally supports the canvas browser element that is needed to make all features (contrast, saturation, sharpness, sepia) work. Please give me a feedback if it works like expected. For older IE versions there should be no difference.