Image Watermarking/ Copyright with GD

2

Comments

  • Okay, after further thought, here goes a fix that will work for my themes (and maybe others that use the getCustomImageURL()). The only thing is that you'll have to edit more than just i.php.

    copy and paste the following code into i.php around line 213 (just as stated in the above post):

    `////////////////////////////////////////////////////////////////////////////////

    // Watermark Hack

    ////////////////////////////////////////////////////////////////////////////////

    $perform_watermark = zp_conf('perform_watermark');

    $watermark_image = zp_conf('watermark_image');

    if ($perform_watermark == true && $thumb == false && $_GET['wm'] == true) {

    $watermark = imagecreatefrompng($watermark_image);

    imagealphablending($watermark, false);

    imagesavealpha($watermark, true);

    $watermark_width = imagesx($watermark);

    $watermark_height = imagesy($watermark);

    // Position Overlay in Bottom Right

    $dest_x = imagesx($newim) - $watermark_width;

    $dest_y = imagesy($newim) - $watermark_height;

    imagecopy($newim, $watermark, $dest_x, $dest_y, 0, 0, $watermark_width, $watermark_height);

    imagedestroy($watermark);

    }

    ////////////////////////////////////////////////////////////////////////////////`

    now from lines 257-263 of classes.php change the function from:

    `function getCustomImage($size, $width, $height, $cropw, $croph, $cropx, $cropy) {

    return WEBPATH . "/zen/i.php?a=" . urlencode($this->album->name) . "&i=" . urlencode($this->filename)

    . ($size ? "&s=$size" : "" ) . ($width ? "&w=$width" : "") . ($height ? "&h=$height" : "")

    . ($cropw ? "&cw=$cropw" : "") . ($croph ? "&ch=$croph" : "")

    . ($cropx ? "&cx=$cropx" : "") . ($cropy ? "&cy=$cropy" : "") ;

    }`

    to the following:

    `function getCustomImage($size, $width, $height, $cropw, $croph, $cropx, $cropy, $wm=true) {

    return WEBPATH . "/zen/i.php?a=" . urlencode($this->album->name) . "&i=" . urlencode($this->filename)

    . ($size ? "&s=$size" : "" ) . ($width ? "&w=$width" : "") . ($height ? "&h=$height" : "")

    . ($cropw ? "&cw=$cropw" : "") . ($croph ? "&ch=$croph" : "")

    . ($cropx ? "&cx=$cropx" : "") . ($cropy ? "&cy=$cropy" : "")

    . ($wm ? "&wm=$wm" : "") ;

    }`

    Then in template-functions.php change lines 554-558 from:

    `function getCustomAlbumThumb($size, $width=NULL, $height=NULL, $cropw=NULL, $croph=NULL, $cropx=NULL, $cropy=null) {

    global $_zp_current_album;

    $thumb = $_zp_current_album->getAlbumThumbImage();

    return $thumb->getCustomImage($size, $width, $height, $cropw, $croph, $cropx, $cropy);

    }`

    to the following:

    `function getCustomAlbumThumb($size, $width=NULL, $height=NULL, $cropw=NULL, $croph=NULL, $cropx=NULL, $cropy=null, $wm=false) {

    global $_zp_current_album;

    $thumb = $_zp_current_album->getAlbumThumbImage();

    return $thumb->getCustomImage($size, $width, $height, $cropw, $croph, $cropx, $cropy, $wm);

    }`

    Also in template-functions.php change lines 892-903 from:

    `function getCustomImageURL($size, $width=NULL, $height=NULL, $cropw=NULL, $croph=NULL, $cropx=NULL, $cropy=NULL) {

    global $_zp_current_image;

    return $_zp_current_image->getCustomImage($size, $width, $height, $cropw, $croph, $cropx, $cropy);

    }`

    `function printCustomSizedImage($alt, $size, $width=NULL, $height=NULL, $cropw=NULL, $croph=NULL, $cropx=NULL, $cropy=NULL, $class=NULL, $id=NULL) {

    $sizearr = getSizeCustomImage($size, $width, $height, $cropw, $croph, $cropx, $cropy);

    echo "$alt
    " width="" . $sizearr[0] . "" height="" . $sizearr[1] . """ .

    (($class) ? " class="$class"" : "") .

    (($id) ? " id="$id"" : "") . " />";

    }`

    to the following:

    `function getCustomImageURL($size, $width=NULL, $height=NULL, $cropw=NULL, $croph=NULL, $cropx=NULL, $cropy=NULL, $wm=true) {

    global $_zp_current_image;

    return $_zp_current_image->getCustomImage($size, $width, $height, $cropw, $croph, $cropx, $cropy, $wm);

    }`

    `function printCustomSizedImage($alt, $size, $width=NULL, $height=NULL, $cropw=NULL, $croph=NULL, $cropx=NULL, $cropy=NULL, $class=NULL, $id=NULL, $wm=true) {

    $sizearr = getSizeCustomImage($size, $width, $height, $cropw, $croph, $cropx, $cropy);

    echo "$alt
    " width="" . $sizearr[0] . "" height="" . $sizearr[1] . """ .

    (($class) ? " class="$class"" : "") .

    (($id) ? " id="$id"" : "") . " />";

    }`

    What this code does is that by default, when you use getCustomImageURL() it will automatically watermark your image (this way your images are ALWAYS protected. If you want to turn it off (to maybe make a custom-sized thumbnail), just set the 8th parameter of the function to false. However, it's the opposite for getCustomAlbumThumb(). Because we have it explicitly get a thumb, we have $wm be false by default.

    That should do it.

  • nathan Member
    This is a fairly lengthy hack. I'll take a look at seeing if there is a different way to do this. I tired my best to make the code small, and this is really a bit too much for what I was after.

    I like this bit though:
    `////////////////////////////////////////////////////////////////////////////////

    // Watermark Hack

    ////////////////////////////////////////////////////////////////////////////////

    $perform_watermark = zp_conf('perform_watermark');

    $watermark_image = zp_conf('watermark_image');

    if ($perform_watermark == true && $thumb == false && $_GET['wm'] == true) {

    $watermark = imagecreatefrompng($watermark_image);

    imagealphablending($watermark, false);

    imagesavealpha($watermark, true);

    $watermark_width = imagesx($watermark);

    $watermark_height = imagesy($watermark);

    // Position Overlay in Bottom Right

    $dest_x = imagesx($newim) - $watermark_width;

    $dest_y = imagesy($newim) - $watermark_height;

    imagecopy($newim, $watermark, $dest_x, $dest_y, 0, 0, $watermark_width, $watermark_height);

    imagedestroy($watermark);

    }

    ////////////////////////////////////////////////////////////////////`

    Thanks for that.

  • nathan Member
    Sorry for a double post, but we might be able to get this included in the zenphoto project. That way, people won't have to edit ALL the files themselves. They won't have to do anything really.

    I'll open a feature request in the bug tracker.
  • Well, if this will be worked in "officially" it would be great if not only would we be able to specify the default watermark image in the config, but if we were also able to specify a different watermark image during runtime.

    This would be useful, for example, if I wanted a default watermark on my bigger images (say it was a logo and my domain name), but then later on decide to watermark my thumbnails with just the logo. When I call the function to specify a thumbnail, I could just easily give it the name of the new watermark.
  • Daxeno Member
    This is still not in the Wiki. :(
  • trisweb Administrator
    Good point Daxeno. ;-)
  • Daxeno Member
    and it seems not working as well.
  • Dax-

    I was able to get the antialiasing working on my site OK. What seems to not be working?

    Thinkdreams.
  • In case you haven't seen it, http://www.thinkdreams.com/devzp is where my test site is at.

    I used Nathan's original code, without the GameDudeX modifications (just haven't had time to integrate them yet).

    Thinkdreams
  • Daxeno Member
    i have tried Nathans Code but it seems not working coz after i followed his instructions, my photos won't show at all. :(
  • Mind if I take a look at your code?

    Thinkdreams
  • nathan Member
    --
    i have tried Nathans Code but it seems not working coz after i followed his instructions, my photos won't show at all. :(
    --
    I'm sorry to hear that.
    I think I know what the probmlem could be. As it is low/zero loss image manipulation, it uses heaps of memory.

    Can you add this line to the top of the .htaccess file, clear the cache folder and give it another go?

    `# PHP is hungry. Give it more resources.

    php_value memory_limit 16M`

    16MB should be fine for everything zenphoto is doing.

    And yes. I am sorry it is not in the wiki. I'll do that now (with the php memory override).
  • nathan Member
    The wiki is not functioning properly. I PROMISE I will add it as soon as I can, but the wiki is not loading properly and there are timeouts I try and sign in and add content.
  • Daxeno Member
    Ive made it work but it only showed the watermarking on the Random Images. lol

    Here's my i.php code :

    <?php

    /*******************************************************************************
    * i.php: Zenphoto image processor. All image requests go through this file. *
    *******************************************************************************
    * URI Parameters:
    * s - size (logical): Based on config, makes an image of "size s."
    * h - height (explicit): Image is always h pixels high, w is calculated.
    * w - width (explicit): Image is always w pixels wide, h is calculated.
    * cw - crop width: crops the image to cw pixels wide.
    * ch - crop height: crops the image to ch pixels high.
    * cx - crop x position: the x (horizontal) position of the crop area.
    * cy - crop y position: the y (vertical) position of the crop area.
    * q - JPEG quality (1-100): sets the quality of the resulting image.
    *
    * - cx and cy are measured from the top-left corner of the _scaled_ image.
    * - One of s, h, or w _must_ be specified; the others are optional.
    * - If more than one of s, h, or w are specified, s takes priority, then w+h:
    * - If both w and h are given, the image is resized to shortest side, then
    * cropped on the remaining dimension. Image output will always be WxH.
    * - If none of s, h, or w are specified, the original image is returned.
    *******************************************************************************
    */

    define('OFFSET_PATH', true);
    // i.php - image generation.
    require_once("functions.php");

    // Set the config variables for convenience.

    $perform_watermark = zp_conf('perform_watermark');
    $watermark_image = zp_conf('watermark_image');
    $thumb_crop = zp_conf('thumb_crop');
    $thumb_size = zp_conf('thumb_size');
    $thumb_crop_width = zp_conf('thumb_crop_width');
    $thumb_crop_height = zp_conf('thumb_crop_height');
    $image_use_longest_side = zp_conf('image_use_longest_side');
    $image_default_size = zp_conf('image_size');
    $quality = zp_conf('image_quality');
    $thumb_quality = zp_conf('thumb_quality');
    $upscale = zp_conf('image_allow_upscale');

    // Don't let anything get above this, to save the server from burning up...
    define('MAX_SIZE', 3000);

    // Generate an image from the given file ($_GET['f']) at the given size ($_GET['s'])
    if (!isset($_GET['a']) || !isset($_GET['i'])) {
    die("<b>Zenphoto error:</b> Please specify both an album and an image.");
    // TODO: Return a default image (possibly with an error message) instead of just dying.
    }

    // Fix special characters in the album and image names if mod_rewrite is on:
    if (zp_conf('mod_rewrite')) {
    $zppath = substr($_SERVER['REQUEST_URI'], strlen(WEBPATH)+1);
    $qspos = strpos($zppath, '?');
    if ($qspos !== false) $zppath = substr($zppath, 0, $qspos);
    $zpitems = explode("/", $zppath);
    if (isset($zpitems[1]) && $zpitems[1] == 'image') {
    $req_album = $zpitems[0];
    // This next line assumes the image filename is always last. Take note.
    $req_image = $zpitems[count($zpitems)-1];
    if (!empty($req_album)) $_GET['a'] = urldecode($req_album);
    if (!empty($req_image)) $_GET['i'] = urldecode($req_image);
    }
    }

    $album = sanitize($_GET['a']);
    $image = sanitize($_GET['i']);

    // Disallow abusive size requests.
    if ((isset($_GET['s']) && $_GET['s'] < MAX_SIZE)
    || (isset($_GET['w']) && $_GET['w'] < MAX_SIZE)
    || (isset($_GET['h']) && $_GET['h'] < MAX_SIZE)) {

    // Set default variable values.
    $thumb = $size = $width = $height = $crop = $cw = $ch = $cx = $cy = false;

    // If s=thumb, Set up for the default thumbnail settings.
    $size = $_GET['s'];
    if ($size == "thumb") {
    $thumb = true;
    if ($thumb_crop) {
    if ($thumb_crop_width > $thumb_size) $thumb_crop_width = $thumb_size;
    if ($thumb_crop_height > $thumb_size) $thumb_crop_height = $thumb_size;
    $cw = $thumb_crop_width;
    $ch = $thumb_crop_height;
    $crop = true;
    } else {
    $crop = $cw = $ch = false;
    }
    $size = round($thumb_size);
    $quality = round($thumb_quality);

    // Otherwise, populate the parameters from the URI
    } else {
    if ($size == "default") {
    $size = $image_default_size;
    } else if (empty($size) || !is_numeric($size)) {
    $size = false; // 0 isn't a valid size anyway, so this is OK.
    } else {
    $size = round($size);
    }

    if (isset($_GET['w'])) { $width = round($_GET['w']); }
    if (isset($_GET['h'])) { $height = round($_GET['h']); }
    if (isset($_GET['cw'])) { $cw = round($_GET['cw']); $crop = true; }
    if (isset($_GET['ch'])) { $ch = round($_GET['ch']); $crop = true; }
    if (isset($_GET['cx'])) { $cx = round($_GET['cx']); }
    if (isset($_GET['cy'])) { $cy = round($_GET['cy']); }
    if (isset($_GET['q'])) { $quality = round($_GET['q']); }
    }

    $postfix_string = ($size ? "_$size" : "") . ($width ? "_w$width" : "")
    . ($height ? "_h$height" : "") . ($cw ? "_cw$cw" : "") . ($ch ? "_ch$ch" : "")
    . (is_numeric($cx) ? "_cx$cx" : "") . (is_numeric($cy) ? "_cy$cy" : "");

    } else {
    // No image parameters specified; return the original image.
    header("Location: " . PROTOCOL . "://" . $_SERVER['HTTP_HOST'] . WEBPATH
    . "/albums/" . rawurlencode($album) . "/" . rawurlencode($image));
    return;
    }

    $newfilename = "{$album}_{$image}{$postfix_string}.jpg";
    $newfile = SERVERCACHE . "/" . $newfilename;
    $imgfile = SERVERPATH . "/albums/$album/$image";

    // Check for the source image.
    if (!file_exists($imgfile)) {
    die("<b>Zenphoto error:</b> Image not found.");
    }

    // If the file hasn't been cached yet, create it.
    if (!file_exists($newfile)) {
    if ($im = get_image($imgfile)) {
    $w = imagesx($im);
    $h = imagesy($im);

    // Give the sizing dimension to $dim
    if (!empty($size)) {
    $dim = $size;
    $width = $height = false;
    } else if (!empty($width) && !empty($height)) {
    $ratio_in = $h / $w;
    $ratio_out = $height / $width;
    $crop = true;
    if ($ratio_in > $ratio_out) {
    $thumb = true;
    $dim = $width;
    $ch = $height;
    } else {
    $dim = $height;
    $cw = $width;
    $height = true;
    }

    } else if (!empty($width)) {
    $dim = $width;
    $size = $height = false;
    } else if (!empty($height)) {
    $dim = $height;
    $size = $width = false;
    } else {
    // There's a problem up there somewhere...
    die("<b>Zenphoto error:</b> Image processing error. Please report to the developers.");
    }

    // Calculate proportional height and width.
    $hprop = round(($h / $w) * $dim);
    $wprop = round(($w / $h) * $dim);

    if ($thumb) {
    // Use the shortest side.
    if ($h > $w) {
    $neww = $dim;
    $newh = $hprop;
    } else {
    $neww = $wprop;
    $newh = $dim;
    }
    } else {
    if (($size && $image_use_longest_side && $h > $w) || $height) {
    $newh = $dim;
    $neww = $wprop;
    } else {
    $newh = $hprop;
    $neww = $dim;
    }

    // If the requested image is the same size or smaller than the original, redirect to it.
    if (!$upscale && $newh >= $h && $neww >= $w && !$crop) {
    header("Location: " . PROTOCOL . "://" . $_SERVER['HTTP_HOST'] . WEBPATH
    . "/albums/" . rawurlencode($album) . "/" . rawurlencode($image));
    return;
    }
    }

    $newim = imagecreatetruecolor($neww, $newh);
    imagecopyresampled($newim, $im, 0, 0, 0, 0, $neww, $newh, $w, $h);

    // Crop the image if requested.
    if ($crop) {
    if ($cw === false || $cw > $neww) $cw = $neww;
    if ($ch === false || $ch > $newh) $ch = $newh;
    if ($cx === false) $cx = round(($neww - $cw) / 2);
    if ($cy === false) $cy = round(($newh - $ch) / 2);
    if ($cw + $cx > $neww) $cx = $neww - $cw;
    if ($ch + $cy > $newh) $cy = $newh - $ch;
    $newim_crop = imagecreatetruecolor($cw, $ch);
    imagecopy($newim_crop, $newim, 0, 0, $cx, $cy, $cw, $ch);
    imagedestroy($newim);
    $newim = $newim_crop;
    }

    //-- watermarking
    if ($perform_watermark == true) {

    $watermark = imagecreatefrompng($watermark_image);
    imagealphablending($watermark, false);
    imagesavealpha($watermark, true);
    $watermark_width = imagesx($watermark);
    $watermark_height = imagesy($watermark);

    // Position Overlay in Bottom Right
    $dest_x = imagesx($newim) - $watermark_width;
    $dest_y = imagesy($newim) - $watermark_height;

    imagecopy($newim, $watermark, $dest_x, $dest_y, 0, 0, $watermark_width, $watermark_height);
    imagedestroy($watermark);
    }
    //-- /watermarking

    // Create the cached file (with lots of compatibility)...
    touch($newfile);
    imagejpeg($newim, $newfile, $quality);
    chmod($newfile,0644);
    imagedestroy($newim);
    imagedestroy($im);
    }
    }

    // ... and redirect the browser to it.
    header("Location: " . PROTOCOL . "://" . $_SERVER['HTTP_HOST'] . WEBPATH . "/cache/" . rawurlencode($newfilename));
    exit();
    ?>
  • This is not answered yet :(.
  • Solutions to this watermarking issue,,,, anyone??
  • Daxeno, the reason is because if your image is smaller than the size defined by the theme, then zenphoto will load the original image instead of generating a new one, thus bypassing i.php.

    It's also why the watermark does not appear on the image if you open it up in full-size.

    I think template-functions.php needs to be modified in order to force zenphoto to process the original picture too, but I suck at reading other people's code and I can't figure out what exactly needs to be changed.

    Hopefully someone can...
  • hm i would like to know how skwids copyrighting method works.
    i mean adding a text watermark to the image instead of a image.
    some folks got it running here. but there is nowhere a howto.
    unfortunately i'm not very good in php so i would be very thankful for a step by step tutorial.

    thanks a lot
  • Here is the watermarking how-to on the wiki: http://www.zenphoto.org/trac/wiki/ZenphotoHacks#WatermarkingHack
  • yes i found this one. but i would like to do the watermarking with text not with another image. there are some people in this thread who described that they build such a watermarking system, but they lost no word on how they did it.
  • udzguru-

    skwid had originally come up with the text based version of watermarking, the problem comes in that it doesn't do alpha blending very well using the GD functions. That's why there was a shift more toward using the images instead. The images make it easier to add custom texts, special characters, etc some of which may not be as easy with just text.

    That's probably why there wasn't any more mention of it.

    Is there a reason specifically that you didn't want to use the image functionality vs text? It doesn't alter the actual image at all in the albums directory, just the cached zenphoto images.
  • Their text was done using a png. You can use photoshop to format your text on a 24bit png file.
  • i tried to build in the image-watermarking hack, did it just like described in the hacks section in the trac, but that hack doesn't work.
    :(

    here's the image i used :
    http://udzguru.ath.cx/gallery/zenphoto/zen/images/watermark.png

    the code was pasted, just as described in this thread/the hacks section of the wiki.

    i'm using the ladest svn-version of zenphoto because of the subalbums functionality.
  • udzguru, I am having the same problem...if someone has gotten this to work on SNV 441 please let us know how!!
  • I'll grab my code and try it. I don't have it in the latest SVN myself, so I'll give it a shot and see how it works.

    Hopefully tomorrow I can create a test site to try it out. Keep you guys posted.
  • OK. There was some missing instructions on the wiki page here: http://www.zenphoto.org/trac/wiki/ZenphotoHacks#WatermarkingHack

    It does work, however, I had to remove the `&& $thumb == false` to get it to display. I remember having to fiddle with the detection of thumbs before, as the issue is to not have the thumbnails display the watermark as well (unless that is your intent).

    It definitely needs to be looked at, tweaked, and possibly integrated into the core code at some point, as it is a useful feature, but not a high priority at any means.

    But the practical upshot is that it does work with SVN 441, and the wiki docs have been updated with the missing instructions.
  • wonderful thinkdreams.

    now it works for me like a charm. thanks a lot
  • Has anyone figured out how to use the watermark hack to apply a watermark only to video thumbnails? If so, can you explain how? I have the video and watermark hack applied but so far I haven't been able to figure out how to apply a watermark only to video thumbnails.
  • I don't like the way I did it, but if you're desperate, it works. What it does is add the video watermark on the thumb before saving it to the cache. When calling the image processor (i.php) it gives an extra parameter with the watermark image file to use (in my case, "videoWatermark.png").

    class-image.php
    ===============
    in the getThumb() function replace:

    `return WEBPATH . "/zen/i.php?a=".urlencode($this->album->name)."&i=".urlencode($this->videoThumb)."&s=thumb";`

    to

    `return WEBPATH . "/zen/i.php?a=".urlencode($this->album->name)."&i=".urlencode($this->videoThumb)."&s=thumb&wm=videoWatermark.png";`

    i.php
    =====
    right before the
    `// Create the cached file (with lots of compatibility)...

    @touch($newfile);`

    add:

    `$perform_watermark = zp_conf('perform_watermark');

    if (isset($_GET['wm']) && $perform_watermark == true && $thumb == true)

    {

    $watermark = imagecreatefrompng("images/".$_GET['wm']);

    imagealphablending($watermark, false);

    imagesavealpha($watermark, true);

    $watermark_width = imagesx($watermark);

    $watermark_height = imagesy($watermark);

    // Position Overlay in Bottom Right

    $dest_x = imagesx($newim) - $watermark_width;

    $dest_y = imagesy($newim) - $watermark_height;

    imagecopymerge($newim, $watermark, $dest_x, $dest_y, 0, 0, $watermark_width, $watermark_height,100);

    imagedestroy($watermark);

    }`

    This was done without the watermark hack applied, so I'm not sure how will it work with it.
  • Do you have an example of what this looks like jordi?
Sign In or Register to comment.