Jump to content

Tutorial how to add a site wide optional watermarking method to all pageimages


horst
 Share

Recommended Posts

Hi there, I'm starting a small series of tutorials here.
The first one(s) deal with the topic "How can I add a watermark to all pageimages of a site?"

  1. first episode "Tutorial how to add a site wide optional watermarking method to all pageimages"
  2. second episode "Second Episode: "How can I add a watermark to all pageimages of a site?""

This is targeted to all, - beginners, intermediate, pros, - but mainly to interested PW lovers.

The fictitious starting situation could be that a website owner has been creating beautiful photos for many years and would like to show them on his site in higher output sizes. A reference to real people or events does not exist, or would be "purely coincidental". Could someone please tell @Rob(AU) about this. ?

This first episode shows a really straight and forward solution that could be an answer to the question "How can I get things be done?". We will create a PHP function that will give back a watermarked variation of every pageimage we put into it. We don't want bother our self to much with coding or image manipulation stuff. So for this first example we will setup our site with a single centralized image field that can contain one PNG image that should be used as our alpha transparency overlay for all watermarked image variations. Additionally to that, we install a PW third party module that does the image manipulation stuff. I will use the Page Image Manipulation module for this, because I know it very well. There are also *other good solutions in the PW ecosystem and if you would like you can add and use every existing PHP library that can assist you, or write your own individual low level code for that. But that's not our topic here. We want to get things done. Lets start!

 

1) Create a single centralized image field somewhere on a settings page if you have one. If your site doesn't has one, because you haven't had a need for that til now, the homepage may be a good place too. If you go with the homepage, but for other situations too, it may be a good idea to separate the overlay image input field from other content you have on that page.

1.1) Create an image field that should contain one file, and only of type PNG
gtd01.thumb.jpg.a9b7ea124b17324ee30b25f71572a1fb.jpg

1.2) Create a fieldset tab
gtd02.jpg.7be951803acf60125dcc4a2d19a2f22a.jpg

1.3) Add both to the template of your choice
gtd03.thumb.jpg.995b9760a9148ae172ecae5690e9f60b.jpg

 

2) Add the Page Image Manipulator module to your site ...

2.1) ... by going to your modules section in the admin, select the tab "New" and add the Modules Classname under "Add Module From Directory": PageImageManipulator
gtd04.jpg.46ed592eca2192190f106a9a8de1de5d.jpg

2.2) Download and install it.

2.3) Go to the modules site tab and scroll down to the position where you find the entries for a Pageimage Manipulator 1 and a Pageimage Manipulator 2. There you can savely uninstall the legacy version 1 that is only needed for PW version prior to 2.6.
gtd05.jpg.8ae63ab73fc8a4ea82f4e620c64437fc.jpg

 

3) Provide a PNG overlay image. For this example we want use a 2000 x 2000 px transparent PNG image with our watermark sign or watermark text. If you don't have one ready but have an image manipulation program on your local machine at hand that excepts photoshop actions, you can download one here for fast creation:
photoshop_action_PW-png-creations.zip

3.1) Create a new image 2000px x 2000px with a transparent background
gtd06.jpg.b3eee9e28d89d22f3acb5c8601f28add.jpg

3.2)  Add some meaningful text at a position you like. If you want to use the PS action, don't forget to rasterize all vector text before starting it.
gtd07.jpg.b34be5eb41448d850d883b16d3ef3075.jpg

3.3) Regardless if you used the PS action or created some nice overlay in another way, you should set the opacity of the final image to something between 20 and 40 percent. You may have to test this out for a production version. But now we want to get things done. Save the final version and ...
gtd08.jpg.cf295e018914cba921c3f7d0163f7bc2.jpg

3.4) Upload it into the centralized image field in your site!
 

4) Create a PHP function that encapsulates the watermark overlay process and outputs a finished pageimage as a variation.

To get a go here without messing up our site, we can create a test.php file as sibling of PWs index.php. We will *boostrap PW there and get full access to the API site this way:

<?php namespace ProcessWire;
include __DIR__ . '/index.php';

function ourWatermarkTestfunction(Pageimage $image) {

    return $watermarkedImage;
}

Let the file operating in the PW namespace, boostrap the PW API and our barebone function. We want to pass in a pageimage and we want to get out a pageimage that is a watermarked variation of the source pageimage.

If we want to test what we have so far, we would fetch us an image from a page we know it has one and pass it into the function:

<?php namespace ProcessWire;
include __DIR__ . '/index.php';

function ourWatermarkTestfunction(Pageimage $originalImage) {
    $watermarkedImage = $originalImage;
    return $watermarkedImage;
}

$image = $pages->get('[your selector here to a well known page that has an images field called images]')->images->first();
$variation = ourWatermarkTestfunction($image);
$variation = $variation->width(800);
echo "<img src='{$variation->url}' alt='{$variation->description}' />";

We tweaked our function to pass us the input image as output. And we echo out it as a HTML image. If this is working as expected, we can start to do code the main part of our function.

We will use the module Pageimage Manipulator for that and referring to its description page, when we scroll down to the method called watermarkLogo, it tells us how we can use it. 

watermarkLogo($pngAlphaImage, $position='center', $padding=2)

It want to have one mandatory param, the transparent PNG overlay image. Optionally it can take params for positioning the overlay. For our test we will use the defaults and as they are optional arguments, we don't need to call them.

Referring to the PIM2 API, we have to start the process by calling

pim2Load($prefix, $param2=optional, $param3=optional)

And at the end we have to call

pimSave()

Putting this together we will get this:

function ourWatermarkTestfunction(Pageimage $originalImage) {
    $watermarkedImage = $originalImage->pim2Load('wm')->watermarkLogo($pngAlphaImage)->pimSave();
    return $watermarkedImage;
}

So, this will produce an error as we have not specified what $pngAlphaImage is. It should be our site wide overlay image that we have stored at a well known place, for example on our homepage. Also we want to apply a check if we really get a Pageimage from there, to avoid unhandled errors if for whatever reason the image gets deleted by accident at some time in the future.

function ourWatermarkTestfunction(Pageimage $originalImage) {

    // get the field of the transparent watermark overlay image in a robust way,
    // regardless if it is set to 1 image or multiple images, and if it gets changed or not in the future
    $watermarkImages = wire()->pages->get('id=1')->getUnformatted('setting_watermark');
    if(!$watermarkImages) {
        // return the unmodified original image to do not break our front end site
        return $originalImage;
    }
    // check if it at least contain one image, than fetch it
    if(0 == count($watermarkImages)) {
        // return the unmodified original image to do not break our front end site
        return $originalImage;
    }
    $pngAlphaImage = $watermarkImages->first(); // is the same as wire()->pages->get('id=1')->getUnformatted('setting_watermark')->first()

    // now let the module process our watermarking and save it into a variation
    $watermarkedImage = $originalImage->pim2Load('wm')->watermarkLogo($pngAlphaImage)->pimSave();

    // return the watermarked variation
    return $watermarkedImage;
}

Lets have a visually check if all went well:

$image = $pages->get('[your selector here to a well known page that has an images field called images]')->images->first();
$variation = ourWatermarkTestfunction($image);
$variation = $variation->width(800);
?>
<img src='<?=$variation->url?>' alt='<?=$variation->description?>' />

Now we should see our watermarked variation in the same dimensions as the original is. That's fine and it's time to leave the test and implement that into our custom site API. We will add a hook to the Pageimage object that we want call 'wm' and that does exactly what we have created here.

 

5) Open your site/ready.php and add the following hook into it:

<?php namespace ProcessWire;

$this->addHook('Pageimage::wm', function(HookEvent $event) {

});

Now we can call on every Pageimage the new method wm: $image->wm->width(500) to get a watermarked and 500px width resized variation out.

Ok, first we have to add our functions body into it. And we slightly have to change it a bit, because now it became a anonymous function of a HookEvent. Therefore it has not a own name anymore, and the input is not a Pageimage in the first time, but a HookEvent. (But in the end, it is a Pageimage, because it is a hooked event of a Pageimage. ?)

/**
* Example Pageimage Hook for watermarking functionality,
* adds a new method to Pageimage objetcs named wm.
* Used in a small tutorial series in the ProcessWire forums
* https://processwire.com/talk/topic/25752-tutorial-how-to-add-a-site-wide-optional-watermarking-method-to-all-pageimages/
*
* @version 0.0.1
*
* @var HookEvent 
*/
$this->addHook('Pageimage::wm', function(HookEvent $event) {

    // get the image out of the event object
    $originalImage = $event->object;

    // access the field of the transparent watermark overlay image in a robust way,
    // regardless if it is set to 1 image or multiple images, and if it has changed
    // in this regard since we wrote this hook function
    $watermarkImages = wire()->pages->get('id=1')->getUnformatted('setting_watermark');

    // check if the imagefield exists and it at least contain one image, than fetch it
    if(!$watermarkImages || 0 == count($watermarkImages)) {

        // return the unmodified original image to do not break our front end site
        $event->return = $originalImage;

        // inform the admin about the missing watermark overlay, (or do something other useful)
        wireMail('admin@example.com', 'noreply@example.com', 'MISSING SITEWIDE WATERMARK OVERLAY IMAGE');
        wireLog('errors', 'MISSING SITEWIDE WATERMARK OVERLAY IMAGE');

        // stop further execution
        return;
    }

    $pngAlphaImage = $watermarkImages->first(); // is the same as wire()->pages->get('id=1')->getUnformatted('setting_watermark')->first()

    // now let the module process our watermarking and save it into a variation
    $watermarkedImage = $originalImage->pim2Load('wm')->watermarkLogo($pngAlphaImage)->pimSave();

    // to return the watermarked variation,
    // we have to replace the event object with our watermark variation
    $event->return = $watermarkedImage;

});

 

Now we can call our watermarked images like this:

    $image = $page->images->first();
    $variation = $image->wm()->width(800);
?>
    <img src='<?=$variation->url?>' alt='<?=$variation->description?>' />

 

Now all looks fine in the first line. But there is some room for improvements also in this basic "get the things done" solution. I keep this for one of the next episodes, where we can dive a little bit into image debugging and / or create a more advanced version of the image watermarking function, maybe as a PW module. 

Thanks for reading! ?

 

TL;DR

*pageimage  https://processwire.com/api/ref/pageimage/
*boostrap  https://processwire.com/docs/front-end/include/
*image modules  https://processwire.com/modules/category/photo-video/
*hooks  https://processwire.com/docs/modules/hooks/
*hook event__https://processwire.com/api/ref/hook-event/

 

Spoiler

551818671_20210609_204240.-pim2-wm.800x03.jpg.de10f785980b6f9bad7c139906014198.jpg

watermark-overlay.thumb.png.217251478de54199967c10254d6d7478.png

 

 

  • Like 10
  • Thanks 4
Link to comment
Share on other sites

  • 2 weeks later...

@horst when you said you would write a tutorial I did not expect a short reference manual! Thank you heaps. @wbmnfktr, yes, I eventually found my way here - life delayed my return.

This looks awesome and I'm looking forward to using it. At the moment it reveals that I am a better photographer than coder...
I have encountered an error at the beginning of step 4. I have tried to tweak the code to reflect my fields and setup, but keep getting an error. I'm testing on my NAS and my setup uses MediaManager and has photo as the photo/image field. Thus I have the following:

Quote

<?php namespace ProcessWire;
include __DIR__ . '/index.php';

function ourWatermarkTestfunction(Pageimage $originalImage) {
    $watermarkedImage = $originalImage;
    return $watermarkedImage;
}

$image = $pages->get('/photos/cloudscapes/yalata/')->photo->media;
$variation = ourWatermarkTestfunction($image);
$variation = $variation->width(800);
echo "<img src='{$variation->url}' alt='{$variation->description}' />";

The following error is thrown:

Quote

TypeError

Argument 1 passed to ProcessWire\ourWatermarkTestfunction() must be an instance of ProcessWire\Pageimage, null given, called in /volume4/web/landscapes/test.php on line 10

In my current template, using MediaManager, the following produces the expected output:

Quote


foreach($page->photo as $photo) {
  $image = $photo->media->url;
}
$out = "";
        $out .=  "<img src=$image class='mainimageH' alt='$headline'>";
        echo $out;

What am I'm missing or doing wrong?

  • Like 1
Link to comment
Share on other sites

Hey, you are using mediamanager and your tweaks have changed that the item passed into the function isn't a pageimage. Maybe a mediamanager object or a url string. I'm on mobile ATM, I'll come back to you. ?

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...