Please upgrade here. These earlier versions are no longer being updated and have security issues.
HackerOne users: Testing against this community violates our program's Terms of Service and will result in your bounty being denied.

adding a watermark to uploaded images

I'm using the advanced text editor (same as here).

I'd really like to add a watermark of a png to the bottom right of images uploaded. Limited PHP skills but it sounds pretty easy, but hacking the scripts isn;t working,

Should it be a simple adjustment?

(sorry would of posted it development but looks like I dont have permission?)

Comments

  • noncenonce Necro-on Forensics
    edited March 2016

    you said: I'm using the advanced text editor (same as here).

    I looked at the core code and the plugin, and some other plugins.

    Yes you would need to write your own plugin as above or modify the editor plugin or ask that a change to core be made to allow for watermark option (there are already options for crop, and image quality), so a watermark option might not be to difficult to add if desired and could be a good addition to "protect images on your site".
    Presumably you would prefer to use the editor drag and drop so you would need to ....

    using something similar to this.

    http://php.net/manual/en/image.examples-watermark.php
    or you could use something like this http://php.net/manual/en/image.examples.merged-watermark.php as another option.

    A code walkabout as follows....

    the editor plugin calls this method

    $filePathParsed = Gdn_UploadImage::saveImageAs($tmpFilePath, $absoluteFileDestination);

    which looks in class.uploadimage.php for the method saveImageAs.

    there is no hook and you cannot override function via a conf/bootstrap.... So you would need to add the option to the saveimageas method or clone method and add and rename it in plugin.

    since there is no option for a watermark in the class.uploadimage.php.
    it would need to be added (after the image rotation tests) to the saveimageas method before the line that says // No need to check these, if we get here then whichever function we need will be available

    //add the watermark if it is an editor image upload path.
    if(preg_match("/editor/",$TargetPath)) {
    // below could also be a config statement to path of watermark instead of a hard-code.
    $watermark = imagecreatefrompng("http://url_to_your_watermark.png");
    // the offsets on x and y axis.
    $xoff = 10;
    $yoff = 10;

    imagecopy($TargetImage, $watermark, imagesx($TargetImage) - imagesx($watermark) - $xoff, imagesy($TargetImage) - imagesy($TargetImage) - $yoff, 0, 0, imagesx($watermark), imagesy($watermark));
    }
    // end of watermark

            // No need to check these, if we get here then whichever function we need will be available
            if ($OutputType == 'gif') {
    

    ideally you should not change the core, so you could clone the function and give it a new name and add it to your cloned editor plugin.
    if you so desire.

    the above would allow you to use the editor plugin as normal and not affect other uploads such as file upload or add picture or any of the other plugins.

  • R_JR_J Ex-Fanboy Munich Admin

    If there is no event in the upload class available, I would use discussion-/commentModels afterSave event

  • x00x00 MVP
    edited March 2016

    hook gdn_upload_saveAs_handler

    Useful variables.

    $path = $args['Path'];
    $name = $args['Parsed']['Name'];
    

    grep is your friend.

  • noncenonce Necro-on Forensics
    edited March 2016

    yes true, but not too efficient to create and save again as far as hook and memory. watermark option parameter would be nicer than you would need to create save destroy again.

    quick and dirty.....

    // add a watermark to png, gif and jpeg images that is uploaded via editor plugin.
    public function gdn_upload_saveAs_handler($sender,$args) {

    $Path = $args['Path'];
    $width = $args['Parsed']['Width'];

    if ($width && (preg_match("/editor/",$Path))) {
    //below could also be a config statement to path of watermark instead of a hard-code.
    $watermark = imagecreatefrompng("https://vanillaforums.org/plugins/EmojiExtender/emoji/little/surprised.png");
    $xoff = 10;
    $yoff = 5;

    if (preg_match("/png/",$Path)){
    $TargetImage = imagecreatefrompng($Path);
    imagecopy($TargetImage, $watermark, imagesx($TargetImage) - imagesx($watermark) - $xoff, imagesy($TargetImage) - imagesy($watermark) - $yoff, 0, 0, imagesx($watermark), imagesy($watermark));
    imagepng($TargetImage, $Path);
    imagedestroy($TargetImage);
    }

    if (preg_match("/jpg|jpeg/",$Path)){
    $TargetImage = imagecreatefromjpeg($Path);
    imagecopy($TargetImage, $watermark, imagesx($TargetImage) - imagesx($watermark) - $xoff, imagesy($TargetImage) - imagesy($watermark) - $yoff, 0, 0, imagesx($watermark), imagesy($watermark));
    imagejpeg($TargetImage, $Path);
    imagedestroy($TargetImage);
    }

    if (preg_match("/gif/",$Path)){
    $TargetImage = imagecreatefromgif($Path);
    imagecopy($TargetImage, $watermark, imagesx($TargetImage) - imagesx($watermark) - $xoff, imagesy($TargetImage) - imagesy($watermark) - $yoff, 0, 0, imagesx($watermark), imagesy($watermark));
    imagegif($TargetImage, $Path);
    imagedestroy($TargetImage);
    }

    imagedestroy($watermark);

    }
    }

  • vrijvlindervrijvlinder Papillon-Sauvage MVP

    It would be a great improvement to be able to watermark all or any images uploaded regardless of what editor or upload plugin is being used. And to have a settings config which one could have the option in the dashboard to save whatever image one wants to use.

    I would be interested to be able to add this to the Galleries plugin as well as the UseBanner plugin, which use the normal upload form and not editor.

    I have tried to implement this but only succeeded in breaking my uploader… :(

  • @nonce said:
    yes true, but not too efficient to create and save again as far as hook and memory. watermark option parameter would be nicer than you would need to create save destroy again.

    quick and dirty.....

    // add a watermark to png, gif and jpeg images that is uploaded via editor plugin.
    public function gdn_upload_saveAs_handler($sender,$args) {

    $Path = $args['Path'];
    $width = $args['Parsed']['Width'];

    if ($width && (preg_match("/editor/",$Path))) {
    //below could also be a config statement to path of watermark instead of a hard-code.
    $watermark = imagecreatefrompng("https://vanillaforums.org/plugins/EmojiExtender/emoji/little/surprised.png");
    $xoff = 10;
    $yoff = 5;

    if (preg_match("/png/",$Path)){
    $TargetImage = imagecreatefrompng($Path);
    imagecopy($TargetImage, $watermark, imagesx($TargetImage) - imagesx($watermark) - $xoff, imagesy($TargetImage) - imagesy($watermark) - $yoff, 0, 0, imagesx($watermark), imagesy($watermark));
    imagepng($TargetImage, $Path);
    imagedestroy($TargetImage);
    }

    if (preg_match("/jpg|jpeg/",$Path)){
    $TargetImage = imagecreatefromjpeg($Path);
    imagecopy($TargetImage, $watermark, imagesx($TargetImage) - imagesx($watermark) - $xoff, imagesy($TargetImage) - imagesy($watermark) - $yoff, 0, 0, imagesx($watermark), imagesy($watermark));
    imagejpeg($TargetImage, $Path);
    imagedestroy($TargetImage);
    }

    if (preg_match("/gif/",$Path)){
    $TargetImage = imagecreatefromgif($Path);
    imagecopy($TargetImage, $watermark, imagesx($TargetImage) - imagesx($watermark) - $xoff, imagesy($TargetImage) - imagesy($watermark) - $yoff, 0, 0, imagesx($watermark), imagesy($watermark));
    imagegif($TargetImage, $Path);
    imagedestroy($TargetImage);
    }

    imagedestroy($watermark);

    }
    }

    Thanks for that, sorry I'm new to PHP. So is this a new function - Where should it go and what should be changed to call it?

  • noncenonce Necro-on Forensics
    edited March 2016

    you said: Thanks for that, sorry I'm new to PHP. So is this a new function - Where should it go and what should be changed to call it?

    Good question.
    yes, this is a new function, it doesn't replace anything. you just add it to a plugin.
    put the function/method in your "watermark plugin" or any other custom plugin you want to add it to.
    this is pretty much all the code you need. just wrap it in a plugin.

    Certainly there must be instructions on this forum how to create a shell or plugin wrapper for a function.
    Tutorials, documentation, or a discussion relating to making a plugin would have an explanation. no need to get into that here.
    this is the only function necessary to add a watermark.
    As I said, it is quick and dirty. you can enhance or change the code as you want.
    You can walk through the code and look at php.net to see what each of the image manipulation functions does.
    essentially it looks a the absolute path of an image. and modifies the image in that location after it is saved.

    you said: I would be interested to be able to add this to the Galleries plugin as well as the UseBanner plugin,

    further explanation: assumption paths are standard and uploaded files in the upload folder within subfolders...

    this is a crude way of seeing if the uploaded file is an image and checking the absolute path of the image being saved
    if ($width && (preg_match("/editor/",$Path))) {

    so if a plugin adds a file to the uploads directory with a subfolder "editor" the watermark will be added.

    if you changed it to this if ($width && (!preg_match("/userpics/",$Path))) {
    it would add a watermark to every image that is in the uploads folder that is NOT in the userpics folder provided the calling plugin called Gdn_UploadImage::saveImageAs

    regarding galleries or userbanner... a brief look at the plugins Userbanner would theoretically add a watermark with the above method since it calls saveimageas and the above method hooks into that function. you would just need to allow it to look in the folder where userbanner images are stored. Galleries was too complex for me to walk through, it would do well with a major refactor and if saveImageas were included in the new code you could also use the watermark plugin.

  • vrijvlindervrijvlinder Papillon-Sauvage MVP

    @nonce said: Certainly there must be instructions on this forum how to create a shell or plugin wrapper for a function.

    Sure, Here I made it into a plugin, however I can't make it work . I tried various combos but no dice…
    I also tried to create a jquery watermark but that is only cosmetic and does not change the file itself…
    Have a look at the one I made with your code… I added the config to add url to watermark image in dashboard, all enables ok and saves to config the url… but the images uploaded do not get watermarked when uploaded via discussion as attachment..or anything else that I can see...

  • noncenonce Necro-on Forensics
    edited March 2016

    My advice.
    You might consider testing the code I posted in a plugin wrapper with NO CHANGES to the function code I posted.
    "Test with the editor plugin use the drag and drop."
    the above code should add a
    to the lower right hand corner of an image that you add. it will not affect images already uploaded.
    if it works. fine.
    if it doesn't work. then you need to double check the code and make sure you haven't changed it.
    if it works without any changes. try adding a config statement
    if after you add a config statement and it doesn't work with editor drag and drop, you know the problem is with your change.
    then change one thing at a time and test logically using editor drag and drop. if the one thing you change doesn't work, you will know where your problem is.
    after you have made all your changes and it is working with editor drag and drop test with 3rd party plugins.
    if you are testing with other 3rd party plugins or the fileupload plugin that don't save the regular image via Gdn_UploadImage::saveImageAs - obviously the watermark plugin won't work since it fires at the end of the saveimageas method
    debug as necessary and test logically.

  • noncenonce Necro-on Forensics
    edited March 2016

    beyond the obvious logical testing using baby steps and troubleshooting with logging and breakpoints.

    addendum to above code information and advice.

    DISCLAIMER
    Individual results may vary. The statements above have not been evaluated by a certified in all testing environments. Code mentioned is not intended to diagnose, treat, cure or prevent any disease and do not replace medical advice.
    Advice on treatment or care of an individual patient should be obtained through consultation with a physician or trained health care practitioner who has examined that patient or is familiar with that patient's medical history. Discontinue use, if persistent pain occurs.

    also the original questioner wanted to add a png watermark. if your watermark is not a png you will need to add code.

  • vrijvlindervrijvlinder Papillon-Sauvage MVP

    well that may be the case however the thumbnails do use in the Uploader plugin so at least the thumbs should have been processed …. I will test more… thanks

    $TargetPath =     "thumbnails/{$Parsed['Name']}";
              $ThumbParsed = Gdn_UploadImage::SaveImageAs($Path, $TargetPath, $Height, $Width, $Options);
    
  • noncenonce Necro-on Forensics
    edited March 2016

    I don't think you understand the logic regarding thumbnails. Watermark should be added to the full sized image.
    if a thumbnail is required it would be a reduced image of the already watermarked "full-sized image".
    study the code and know what the value of every variable is and what you expect it to be and what actually gets executed. troubleshoot with logging and breakpoints.

  • Thanks both of you, I just tested it and it works great.

    I'm using an image that is locally on my server. should I put the full http:// path or change it to be relative / just logo.pgn and put this logo in the plugin folder?

  • vrijvlindervrijvlinder Papillon-Sauvage MVP

    Can you elaborate ? What works ? The plugin I made works? If that is the case then just add the image URL in the dashboard settings page for the plugin .

  • noncenonce Necro-on Forensics
    edited March 2016

    you said: I'm using an image that is locally on my server. should I put the full http:// path or change it to be relative / just logo.pgn and put this logo in the plugin folder?

    assumption your watermark file is in plugins/Watermark folder and is named watermark.png and is a png file.
    the following may work.

    "plugins/Watermark/watermark.png"

    if not try
    $watermark = $this->getWebResource('watermark.png',"/");
    $watermark = imagecreatefrompng($watermark);

    getResource is another option.

    looking at the code....
    buttonbar and imageupload should watermark work with your watermark plugin.
    user banner plugin should work with watermark plugin
    editor plugin should work with watermark plugin.

    you said: well that may be the case however the thumbnails do use in the Uploader plugin so at least the thumbs should have been processed …. I will test more… thanks
    $ThumbParsed = Gdn_UploadImage::SaveImageAs($Path, $TargetPath, $Height, $Width, $Options);

    assumption is you are capable of using the code and it works properly with editor drag and drop Editor plugin. you (plural you) as well have not stated "What works?", you just digressed.

    fileupload plugin should work with a processing kludge - double process it.
    Gdn_UploadImage::SaveImageAs($Path,$Path); // save again to invoke method on full image.
    $TargetPath = "thumbnails/{$Parsed['Name']}";
    $ThumbParsed = Gdn_UploadImage::SaveImageAs($Path, $TargetPath, $Height, $Width, $Options);

    gallery.php plugin may work with kludge as well

    look for $blah = getimagesize($filePath);

    add

    Gdn_UploadImage::SaveImageAs($Path,$Path); // save again to invoke method on full image.
    $blah = getimagesize($filePath);

    regarding watermark plugin itself.

    a default watermark might be an idea.
    assumption: default-watermark.png located here: plugins/Watermark/default-watermark.png
    $defaultwatermark = $this->getWebResource('default-watermark.png',"/");

    or

    $defaultwatermark = "plugins/Watermark/default-watermark.png;

    watermark can also be retrieved locally the same way.

    incorporate with config statement to choose default if no watermark is given.

    configuration options for x and y offsets.

    you might include an option as well for a jpeg watermark.

    you probably don't want to add the watermark to the thumbnail directly. let the Fullsize image get watermarked and shrunk.

    you might add a return for thumbnail related folders to handle avoidance of thumbnails (editor is already hadled) but file upload and others are not.

    galleries looks like it has a th folder for thumbnails, others use thumb or thumbnail or some others thumb*
    // return if thumb, thumb, or /th/ folders.
    if (preg_match("/\/th\/|thumb/",$Path)) return;

    nothing tested. just looked at the code.

    the whole thing is a kludge. better to add a parameter and a better hook in the core.

  • noncenonce Necro-on Forensics
    edited March 2016

    re: galleries typo above try:

    not
    Gdn_UploadImage::SaveImageAs($Path,$Path); // save again to invoke method on full image.__

    edit galleries
    Gdn_UploadImage::SaveImageAs($filePath,$filePath); // save again to invoke method on full image.
    $blah = getimagesize($filePath);

  • @nonce said:

    you probably don't want to add the watermark to the thumbnail directly. let the Fullsize image get watermarked and shrunk.

    >

    What will this code shrink the image into? Something specified by dimensions?

  • noncenonce Necro-on Forensics

    if you adjust it. yes. I suggest you go here and you will begin to understand quality and scaling.

    http://php.net/manual/en/function.imagejpeg.php
    and all the other ones.

    particularly....
    http://php.net/manual/en/function.imagecopyresampled.php

    you can add whatever you want in the plugin code.

  • noncenonce Necro-on Forensics

    misread your comment, my mistake.

    you said: What will this code shrink the image into? Something specified by dimensions?

    this code doesn't shrink anything, but you can. The shrinking that I was talking about is in regards to the thumbnail which is part of the editor plugin.

Sign In or Register to comment.