horst Posted June 13, 2021 Share Posted June 13, 2021 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?" first episode "Tutorial how to add a site wide optional watermarking method to all pageimages" 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 1.2) Create a fieldset tab 1.3) Add both to the template of your choice 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 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. 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 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. 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 ... 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 10 4 Link to comment Share on other sites More sharing options...
wbmnfktr Posted June 14, 2021 Share Posted June 14, 2021 @Rob(AU) will find this on his own... some day... probably. ? 1 Link to comment Share on other sites More sharing options...
Rob(AU) Posted July 1, 2021 Share Posted July 1, 2021 @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? 1 Link to comment Share on other sites More sharing options...
horst Posted July 1, 2021 Author Share Posted July 1, 2021 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 More sharing options...
kongondo Posted July 1, 2021 Share Posted July 1, 2021 13 hours ago, Rob(AU) said: $photo->media @horst This is a Pageimage object. $photo->mediaField; This is a Pageimages object. https://mediamanager.kongondo.com/documentation/frontend-output-of-media-manager-fields/media-manager-objects/ 1 Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now