Jump to content
horst

Page Image Manipulator 1

Recommended Posts

---------------------------------------------------------------------------------------------------------------------------------

  when working with PW version 2.6+, please use Pim2, not Pim!

  read more here  on how to change from the older to the newer version in existing sites

---------------------------------------------------------------------------------------------------------------------------------

PageImage Manipulator

The Page Image Manipulator is a module that let you in a first place do ImageManipulations with your PageImages. - And in a second place there is the possibility to let it work on any imagefile that exists in your servers filesystem, regardless if it is a 'known PW-image'.

The Page Image Manipulator is a Toolbox for Users and Moduledevelopers. It is written to be as close to the Core ImageSizer as possible. Besides the GD-filterfunctions it contains resize, crop, canvas, rotate, flip, sharpen, unsharpMask and 3 watermark methods.



How does it work?
pw_pim_codeexample01.jpg
You can enter the ImageManipulator by calling the method pim2Load(). After that you can chain together how many actions in what ever order you like. If your manipulation is finished, you call pimSave() to write the memory Image into a diskfile. pimSave() returns the PageImage-Object of the new written file so we are able to further use any known PW-image property or method. This way it integrates best into the ProcessWire flow.

The three examples above put out the same visual result: a grayscale image with a width of 240px. Only the filenames will slightly differ.

You have to define a name-prefix that you pass with the pimLoad() method. If the file with that prefix already exists, all operations are skipped and only the desired PageImage-Object gets returned by pimSave(). If you want to force recreation of the file, you can pass as second param a boolean true: pim2Load('myPrefix', true).

You may also want to get rid of all variations at once? Than you can call $pageimage->pim2Load('myPrefix')->removePimVariations()!

A complete list of all methods and actions are at the end of this post.
 
You may also visit the post with tips & examples for users and module developers.


How to Install

  • Download the module
  • Place the module files in /site/modules/PageImageManipulator/
  • In your admin, click Modules > Check for new modules
  • Click "install" for PageImageManipulator
  • Done! There are no configuration settings needed, just install and use it.

Download    (version 0.2.0)

History of origins

http://processwire.com/talk/topic/3278-core-imagemanipulation/


----------------------------------------------------------------------------------------------------------


Page Image Manipulator - Methods

* pimLoad  or  pim2Load, depends on the version you use!

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

  • param 1: $prefix - (string) = mandatory!
  • param 2: mixed, $forceRecreation or $options
  • param 3: mixed, $forceRecreation or $options
  • return: pim - (class handle)
  • $options - (array) default is empty, see the next method for a list of valid options!
  • $forceRecreation - (bool) default is false

It check if the desired image variation exists, if not or if forceRecreation is set to true, it prepares all settings to get ready for image manipulation
-------------------------------------------------------------------

* setOptions

setOptions(array $options)

  • param: $options - (array) default is empty
  • return: pim - (class handle)

Takes an array with any number valid options / properties and set them by replacing the class-defaults and / or the global config defaults optionally set in the site/config.php under imageSizerOptions or imageManipulatorOptions.

valid options are:

  • quality = 1 - 100 (integer)
  • upscaling = true | false (boolean)
  • cropping = true | false (boolean)
  • autoRotation =true | false (boolean)
  • sharpening = 'none' | 'soft' | 'medium' | 'strong' (string)
  • bgcolor = (array) css rgb or css rgba, first three values are integer 0-255 and optional 4 value is float 0-1, - default is array(255,255,255,0)
  • thumbnailColorizeCustom = (array) rgb with values for colorize, integer -255 - 255 (this can be used to set a custom color when working together with Thumbnails-Module)
     
  • outputFormat = 'gif' | 'jpg' | 'png' (Attention: outputFormat cannot be specified as global option in $config->imageManipulatorOptions!)

set {singleOption} ($value)
For every valid option there is also a single method that you can call, like setQuality(90), setUpscaling(false), etc.
-------------------------------------------------------------------

* pimSave

pimSave()

  • return: PageImage-Object

If a new image is hold in memory, it saves the current content into a diskfile, according to the settings of filename, imagetype, targetFilename and outputFormat. Returns a PageImage-Object!
-------------------------------------------------------------------

* release

release()

  • return: void (nothing)

if you, for what ever reason, first load image into memory but than do not save it, you should call release() to do the dishes! ;-) If you use pimSave() to leave the ImageManipulator, release() is called automatically.
-------------------------------------------------------------------

* getOptions

getOptions()

  • return: associative array with all final option values

example:

["autoRotation"] bool(true)
["upscaling"] bool(false)
["cropping"] bool(true)
["quality"] int(90)
["sharpening"] string(6) "medium"
["targetFilename"] string(96) "/htdocs/site/assets/files/1124/pim_prefix_filename.jpg"
["outputFormat"] string(3) "jpg"

get {singleOption} ()
For every valid option there is also a single method that you can call, like getQuality(), getUpscaling(), etc. See method setOptions for a list of valid options!
-------------------------------------------------------------------

* getImageInfo

getImageInfo()

  • return: associative array with useful informations of source imagefile

example:

["type"] string(3) "jpg"
["imageType"] int(2)
["mimetype"] string(10) "image/jpeg"
["width"] int(500)
["height"] int(331)
["landscape"] bool(true)
["ratio"] float(1.5105740181269)
["bits"] int(8)
["channels"] int(3)
["colspace"] string(9) "DeviceRGB"

-------------------------------------------------------------------

* getPimVariations

getPimVariations()

  • return: array of Pageimages

Collect all pimVariations of this Pageimage as a Pageimages array of Pageimage objects. All variations created by the core ImageSizer are not included in the collection.

-------------------------------------------------------------------

* removePimVariations

removePimVariations()

  • return: pim - (class handle)

Removes all image variations that was created using the PIM, all variations that are created by the core ImageSizer are left untouched!

-------------------------------------------------------------------

* width

width($dst_width, $sharpen_mode=null)

  • param: $dst_width - (integer)
  • param: $auto_sharpen - (boolean) default is true was deleted with version 0.0.8, - sorry for breaking compatibility
  • param: $sharpen_mode - (string) possible: 'none' | 'soft' | 'medium' | 'strong', default is 'soft'
  • return: pim - (class handle)

Is a call to resize where you prioritize the width, like with pageimage. Additionally, after resizing, an automatic sharpening can be done with one of the three modes.
-------------------------------------------------------------------

* height

height($dst_height, $sharpen_mode=null)

  • param: $dst_height - (integer)
  • param: $auto_sharpen - (boolean) default is true was deleted with version 0.0.8, - sorry for breaking compatibility
  • param: $sharpen_mode - (string) possible: 'none' | 'soft' | 'medium' | 'strong', default is 'soft'
  • return: pim - (class handle)

Is a call to resize where you prioritize the height, like with pageimage. Additionally, after resizing, an automatic sharpening can be done with one of the three modes.
-------------------------------------------------------------------

* resize

resize($dst_width=0, $dst_height=0, $sharpen_mode=null)

  • param: $dst_width - (integer) default is 0
  • param: $dst_height - (integer) default is 0
  • param: $auto_sharpen - (boolean) default is true was deleted with version 0.0.8, - sorry for breaking compatibility
  • param: $sharpen_mode - (string) possible: 'none' | 'soft' | 'medium' | 'strong', default is 'soft'
  • return: pim - (class handle)

Is a call to resize where you have to set width and / or height, like with pageimage size(). Additionally, after resizing, an automatic sharpening can be done with one of the three modes.
-------------------------------------------------------------------

* stepResize

stepResize($dst_width=0, $dst_height=0)

  • param: $dst_width - (integer) default is 0
  • param: $dst_height - (integer) default is 0
  • return: pim - (class handle)

this performs a resizing but with multiple little steps, each step followed by a soft sharpening. That way you can get better result of sharpened images.
-------------------------------------------------------------------

* sharpen

sharpen($mode='soft')

  • param: $mode - (string) possible values 'none' | 'soft'| 'medium'| 'strong'
  • return: pim - (class handle)

Applys sharpening to the current memory image. You can call it with one of the three predefined pattern, or you can pass an array with your own pattern.

-------------------------------------------------------------------

* unsharpMask

unsharpMask($amount, $radius, $threshold)

  • param: $amount - (integer) 0 - 500, default is 100
  • param: $radius - (float) 0.1 - 50, default is 0.5
  • param: $threshold - (integer) 0 - 255, default is 3
  • return: pim - (class handle)

Applys sharpening to the current memory image like the equal named filter in photoshop.

Credit for the used unsharp mask algorithm goes to Torstein Hønsi who has created the function back in 2003.

-------------------------------------------------------------------

* smooth

smooth($level=127)

  • param: $level - (integer) 1 - 255, default is 127
  • return: pim - (class handle)

Smooth is the opposite of sharpen. You can define how strong it should be applied, 1 is low and 255 is strong.
-------------------------------------------------------------------

* blur

blur()

  • return: pim - (class handle)

Blur is like smooth, but cannot called with a value. It seems to be similar like a result of smooth with a value greater than 200.
-------------------------------------------------------------------

* crop

crop($pos_x, $pos_y, $width, $height)

  • param: $pos_x - (integer) start position left
  • param: $pos_y - (integer) start position top
  • param: $width - (integer) horizontal length of desired image part
  • param: $height - (integer) vertical length of desired image part
  • return: pim - (class handle)

This method cut out a part of the memory image.
-------------------------------------------------------------------

* canvas

canvas($width, $height, $bgcolor, $position, $padding)

  • param: $width = mixed, associative array with options or integer, - mandatory!
  • param: $height = integer, - mandatory if $width is integer!
  • param: $bgcolor = array with rgb or rgba, - default is array(255, 255, 255, 0)
  • param: $position = one out of north, northwest, center, etc, - default is center
  • param: $padding = integer as percent of canvas length, - default is 0
  • return: pim - (class handle)

This method creates a canvas according to the given width and height and position the memory image onto it.

You can pass an associative options array as the first and only param. With it you have to set width and height and optionally any other valid param. Or you have to set at least width and height as integers.

Hint: If you want use transparency with rgba and your sourceImage isn't of type PNG, you have to define 'png' as outputFormat with your initially options array or, for example, like this: $image->pimLoad('prefix')->setOutputFormat('png')->canvas(300, 300, array(210,233,238,0.5), 'c', 5)->pimSave()

-------------------------------------------------------------------

* flip

flip($vertical=false)

  • param: $vertical - (boolean) default is false
  • return: pim - (class handle)

This flips the image horizontal by default. (mirroring)
If the boolean param is set to true, it flips the image vertical instead.
-------------------------------------------------------------------

* rotate

rotate($degree, $backgroundColor=127)

  • param: $degree - (integer) valid is -360 0 360
  • param: $backgroundColor - (integer) valid is 0 - 255, default is 127
  • return: pim - (class handle)

This rotates the image. Positive values for degree rotates clockwise, negative values counter clockwise. If you use other values than 90, 180, 270, the additional space gets filled with the defined background color.
-------------------------------------------------------------------

* brightness

brightness($level)

  • param: $level - (integer) -255 0 255
  • return: pim - (class handle)

You can adjust brightness by defining a value between -255 and +255. Zero lets it unchanged, negative values results in darker images and positive values in lighter images.
-------------------------------------------------------------------

* contrast

contrast($level)

  • param: $level - (integer) -255 0 255
  • return: pim - (class handle)

You can adjust contrast by defining a value between -255 and +255. Zero lets it unchanged, negative values results in lesser contrast and positive values in higher contrast.
-------------------------------------------------------------------

* grayscale

grayscale()

  • return: pim - (class handle)

Turns an image into grayscale. Remove all colors.
-------------------------------------------------------------------

* sepia

sepia()

  • return: pim - (class handle)

Turns the memory image into a colorized grayscale image with a predefined rgb-color that is known as "sepia".
-------------------------------------------------------------------

* colorize

colorize($anyColor)

  • param: $anyColor - (array) like css rgb or css rgba - but with values for rgb -255 - +255,  - value for alpha is float 0 - 1, 0 = transparent  1 = opaque
  • return: pim - (class handle)

Here you can adjust each of the RGB colors and optionally the alpha channel. Zero lets the channel unchanged whereas negative values results in lesser / darker parts of that channel and higher values in stronger saturisation of that channel.
-------------------------------------------------------------------

* negate

negate()

  • return: pim - (class handle)

Turns an image into a "negative".
-------------------------------------------------------------------

* pixelate

pixelate($blockSize=3)

  • param: $blockSize - (integer) 1 - ??, default is 3
  • return: pim - (class handle)

This apply the well known PixelLook to the memory image. It is stronger with higher values for blockSize.
-------------------------------------------------------------------

* emboss

emboss()

  • return: pim - (class handle)

This apply the emboss effect to the memory image.
-------------------------------------------------------------------

* edgedetect

edgedetect()

  • return: pim - (class handle)

This apply the edge-detect effect to the memory image.
-------------------------------------------------------------------

* getMemoryImage

getMemoryImage()

  • return: memoryimage - (GD-Resource)

If you want apply something that isn't available with that class, you simply can check out the current memory image and apply your image - voodoo - stuff
-------------------------------------------------------------------

* setMemoryImage

setMemoryImage($memoryImage)

  • param: $memoryImage - (GD-Resource)
  • return: pim - (class handle)

If you are ready with your own image stuff, you can check in the memory image for further use with the class.
-------------------------------------------------------------------

* watermarkLogo

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

  • param: $pngAlphaImage - mixed [systemfilepath or PageImageObject] to/from a PNG with transparency
  • param: $position - (string) is one out of: N, E, S, W, C, NE, SE, SW, NW,
    - or: north, east, south, west, center, northeast, southeast, southwest, northwest
    default is 'center'
  • param: $padding - (integer) 0 - 25, default is 5, padding to the borders in percent of the images length!
  • return: pim - (class handle)

You can pass a transparent image with its filename or as a PageImage to the method. If the watermark is bigger than the destination-image, it gets shrinked to fit into the targetimage. If it is a small watermark image you can define the position of it:

     NW - N - NE
     |    |    |
     W  - C -  E
     |    |    |
     SW - S - SE

 
The easiest and best way I have discovered to apply a big transparency watermark to an image is as follows:
create a square transparent png image of e.g. 2000 x 2000 px, place your mark into the center with enough (percent) of space to the borders. You can see an example here! The $pngAlphaImage get centered and shrinked to fit into the memory image. No hassle with what width and / or height should I use?, how many space for the borders?, etc.
-------------------------------------------------------------------

* watermarkLogoTiled

watermarkLogoTiled($pngAlphaImage)

  • param: $pngAlphaImage - mixed [systemfilepath or PageImageObject] to/from a PNG with transparency
  • return: pim - (class handle)

Here you have to pass a tile png with transparency (e.g. something between 150-300 px?) to your bigger images. It got repeated all over the memory image starting at the top left corner.
-------------------------------------------------------------------

* watermarkText

watermarkText($text, $size=10, $position='center', $padding=2, $opacity=50, $trueTypeFont=null)

  • param: $text - (string) the text that you want to display on the image
  • param: $size - (integer) 1 - 100, unit = points, good value seems to be around 10 to 15
  • param: $position - (string) is one out of: N, E, S, W, C, NE, SE, SW, NW,
    - or: north, east, south, west, center, northeast, southeast, southwest, northwest
    default is 'center'
  • param: $padding - (integer) 0 - 25, default is 2, padding to the borders in percent of the images length!
  • param: $opacity- (integer) 1 - 100, default is 50
  • param: $trueTypeFont - (string) systemfilepath to a TrueTypeFont, default is freesansbold.ttf (is GPL & comes with the module)
  • return: pim - (class handle)

Here you can display (dynamic) text with transparency over the memory image. You have to define your text, and optionally size, position, padding, opacity for it. And if you don't like the default font, freesansbold, you have to point to a TrueTypeFont-File of your choice.
Please have a look to example output: http://processwire.com/talk/topic/4264-release-page-image-manipulator/page-2#entry41989
-------------------------------------------------------------------





PageImage Manipulator - Example Output

pw_screenshot_pim_exampleThumbs.jpg

  • Like 33

Share this post


Link to post
Share on other sites

PageImage Manipulator - Tips & Examples


* how to create a PNG with transparency for the watermarkLogo method

If you can use adobe photoshop, you simply may download and install this action: photoshop_action_PW-png-creations.zip

  • create an empty image (transparent, not white or black) of 2000 x 2000 pixel
  • write / paste your text and / or logo in a single color, (e.g. black)
  • when finished with your text you should have one single layer with text on transparent background
  • then click the action PW-png-creations -> 2000px-square-to-smooth and you are done.

Hhm, maybe before saving you want to tweak the global transparency of the image a bit. That one used in the ProcessWire example was set to 75% instead of 100%. Just try out what looks best for you.


-------------------------------------------------------------------

* did you know that you can save to different file formats, regardless of source format?
 
You only have to specify your desired format (gif, jpg, png) with the optionally options array with a key named outputFormat and pass it with your call to pimLoad() or use setOptions() before any other action-method:

// assuming the first image is a jpeg
$img = $page->images->first();

// define outputFormat
$options = array('outputFormat'=>'png');

// apply it together with other actions
$myPng = $img->pimLoad('myPrefix')->setOptions($options)->width(240)->pimSave();

//------------------------------------------------------------------------------------------
// you may also do it as a OneLiner only with the image format conversion 
$myPng = $page->images->eq(0)->pimLoad('myPrefix', array('outputFormat'=>'png'))->pimSave();

// or you can use the setOutputFormat method
$myPng = $page->images->first()->pimLoad('myPrefix')->setOutputFormat('png')->pimSave();

-------------------------------------------------------------------

* (how) can I use the ImageManipulator with other imagefiles than PW-Pageimages?

You can load any imagefile from your servers filesystem into the ImageManipulator with:

$pim = wire('modules')->get('PageImageManipulator')->imLoad($imageFilename);
// or
$pim = $wire->modules->get('PageImageManipulator')->imLoad($imageFilename, $options);

You can directly with the imLoad-method pass specific $options or you can do a separate call to setOptions(). Then you do your desired actions and last but not least you call save()! Most time I think the original passed file gets overwritten with the manipulation result, but you are also able to save to a different name and  / or fileformat. If so, it is useful to get the final (sanitized) filename back after saveing.

$optionalNewFilename = $pim->setOptions($options)->height(360)->flip()->blur()->save();

Also you may call this in one line if you prefer:

if(false!==$wire->modules->get('PageImageManipulator')->imLoad($imageFilename,$options)->height(360)->flip()->blur()->save()) {
    // success !!
}

-------------------------------------------------------------------

* how can I use the PageImageManipulator with my own module/s?

If you build a module that do some image manipulation you can define the PIM as needed dependency in your ModulesInfo method with the key 'requires'. You may also force to install the PIM if it isn't already with the key 'installs':

public static function getModuleInfo() {
    return array(
        // ...
        'requires' => array('PageImageManipulator'),
        'installs' => 'PageImageManipulator',
        // ...
    );
}

detailed infos are here: http://processwire.com/talk/topic/778-module-dependencies/

additionally, if you need to check if a module dependency has a minimum version number, you can do it in your install method like this:

public function ___install() {
    // check that at least the minimum version number is installed
    $needed = '0.0.3';
    $a = wire('modules')->get('PageImageManipulator')->getModuleInfo();
    $actual = preg_replace('/(\d)(?=\d)/', '$1.', str_pad("{$a['version']}", 3, "0", STR_PAD_LEFT));
    if(version_compare($actual, $needed, '<')) {
        throw new WireException(sprintf($this->_(__CLASS__ . " requires PageImageManipulator %s or newer. Please update."), $needed));
        return;
    }
    // ... more code
}


-------------------------------------------------------------------

* global options in site/config.php

You can create a config-array in your site/config.php. If you look into it you will find a config array for the ImageSizer that comes with the PW core

$config->imageSizerOptions = array(
	'autoRotation' => true,
	'sharpening' => 'soft',
	'upscaling' => true,
	'cropping' => true,
	'quality' => 90
);

You can define another array with these keys:

$config->imageManipulatorOptions = array(
	'autoRotation' => true,
	'sharpening' => 'soft',
	'upscaling' => false,
	'cropping' => true,
	'quality' => 90,
	'bgcolor' => array(255,255,255,0),
);

You don't have to specify all of the options. PiM reads the imageSizerOptions and merge them with the imageManipulatorOptions. So if you want to have different values you can specify them in imageManipulatorOptions to override those from imageSizerOptions. Only one option isn't present with the imageSizer: bgcolor. This is only used by the imageManipulator.


-------------------------------------------------------------------

* using PiM together with the awesome Thumbnails Module  (http://mods.pw/1b)


If you use the Thumbnails Module together with PiM, you can set two options in the site/config.php under imageManipulatorOptions:

$config->imageManipulatorOptions = array(
   // ...
	'thumbnailColorizeCustom' => array(40,-35,0),
	'thumbnailCoordsPermanent' => true
);

For the colorize dropdown select you can define the custom color here and with the second param you enable/disable permanent storage of RectangleCoords and params. The coords and params are stored with Thumbnails Module per session, but are lost after the session is closed. If you enable permanent storage these data is written into a custom IPTC field of the original imagefile.


-------------------------------------------------------------------

* some more examples will folow here

 . . .

-------------------------------------------------------------------
 

Edited by horst
  • Like 21

Share this post


Link to post
Share on other sites

Horst, finally =)

I've yet to dive into all of that but it looks great at first glance. Thanks for the awesome contribution.

  • Like 1

Share this post


Link to post
Share on other sites

Do you plan to integrate some of Photoshops filters too? :P

Nice module btw, great work!!! ^-^

  • Like 1

Share this post


Link to post
Share on other sites

Nice module btw, great work!!! ^-^

thanks Wanze!

Do you plan to integrate some of Photoshops filters too? :P

Hhm, I think: no!   :P :P

I prefer to use photoshop directly with a wrapper class that uses the COM-technique on Windows ;)

  • Like 2

Share this post


Link to post
Share on other sites

@Horst: Oh, so now we can talk? I understood your last post before the above to mean you needed space (content overflowing across various posts) to finish writing IManipulator's tutorial b4 we could start posting :D

Congrats on this great achievement! :)

  • Like 1

Share this post


Link to post
Share on other sites

@Horst: Oh, so now we can talk? I understood your last post before the above to mean you needed space (content overflowing across various posts) to finish writing IManipulator's tutorial b4 we could start posting :D

Congrats on this great achievement! :)

Thanks Kongondo,

- and yes, you (partly) understood right!

At least I want to have a different post for further added examples, you know, the IP.board editor sometimes lost the text structure when there is a lot of text in it.

Share this post


Link to post
Share on other sites

Very impressive module Horst! I look forward to using it. Please post to the modules directory too if possible. Thanks for your great work here. 

  • Like 2

Share this post


Link to post
Share on other sites

I'm probably doing something wrong, because i'm getting an error with trying the watermarkLogo and watermarkLogoTiled

I was thinking the $pngAlphaImage has to be an image object or url so i tried both ways, with out any luck.

$img = $page->images->first();

$wmi = $page->watermark;

$imgsrc = $img->pimLoad('tw',true)->width(240)->watermarkLogoTiled($wmi->url)->pimSave();

echo "<img src='{$imgsrc->url}' /><br />";
 

Can you point out what i'm doing wrong? The error is below:

Error: Exception: Cannot read the pngAlphaImageFile! (in
/Users/user/Sites/www_domains/processwire/htdocs/site/modules/PageImageManipulator/ImageManipulator.class.php
line 1271)
 

Share this post


Link to post
Share on other sites

@Martijn a path works fine, i needed to use $wmi->filename instead.

$img = $page->images->first();

$wmi = $page->watermark;

$imgsrc = $img->pimLoad('tw',true)->width(240)->watermarkLogoTiled($wmi->filename)->pimSave();

echo "<img src='{$imgsrc->url}' /><br />";
 

@horst it would be nice to be able to position the watermark image. I have used a small 50×50 px. In phpThumb it is possible to position the watermark image with the following values:

LT - T - RT
L  - C -  R

LB - B - RB

or to have it the ProcessWire way: northwest, north, northeast, west, center, east, southwest, south, southeast
 

  • Like 2

Share this post


Link to post
Share on other sites

@horst it would be nice to be able to position the watermark image. I have used a small 50×50 px. In phpThumb it is possible to position the watermark image with the following values:

LT - T - RT

L  - C -  R

LB - B - RB

or to have it the ProcessWire way: northwest, north, northeast, west, center, east, southwest, south, southeast

Hey Raymond, thanks for trying this.

I will add this like the ProcessWire way with 'n' 'north' 'center' 'c' etc, because of consistency with the ImageSizer. It was already on the todo list because I need it for the watermarkText method too, but currently I'm running a bit out of time.

Also I will make the watermark methods accept pageimage and filename for the $pngAlphaImage!

  • Like 2

Share this post


Link to post
Share on other sites

Thats great news, looking forward to give it a try when its finished.

Using a pageImage object makes sence when its needed to rescale or in any other way pim modify the watermark in way go.

  • Like 1

Share this post


Link to post
Share on other sites

@Raymond: I have uploaded a new version with the positioning added! Let me know how it works.

@all: there was a little bug (a 0 instaed of a 1) in the module file at Line 81 that has ignored the forceRecreation param.

Please update both files to version 0.0.2 (link is in the first post)

Edit:

@Raymond: Yes you are right, it is really nice to have the watermark image as pageImage too.

I have tried this:

$img = $page->images->first();

$wmi = $page->watermark->pimLoad('wmi')->colorize('red')->pimSave();

$imgsrc = $img->pimLoad('tw',true)->width(180)->grayscale()->watermarkLogo($wmi, 'southeast', 0)->pimSave();

echo "<img src='{$imgsrc->url}' /><br />";

and a grayscale watermark becomes red. Nice! Have not thought about this possibilities before. :)

post-1041-0-31086100-1376592788.png   post-1041-0-48913000-1376592726_thumb.jp

Edited by horst
  • Like 2

Share this post


Link to post
Share on other sites

Greetings,

Very excellent work Horst! I have tried this in a sandbox site and cannot wait to integrate it into a live project.

Now, how about preventing clients from uploading photos that ruin our beautiful designs? Maybe a hand that reaches out and stops them from clicking "submit" in certain cases? Or maybe an automatic watermark that stamps "developer not responsible for this image."

But seriously, your work is amazing.

Thanks,

Matthew

  • Like 2

Share this post


Link to post
Share on other sites

@horst thanks for these extra features in the watermarkLogo process. One question what does the 0 stand for?

$padding (in percent of the image length), default is 2

(I also have updated the method doc in first post with this) ;)

Share this post


Link to post
Share on other sites

Hhm, I have finalized the third WatermarkMethod: watermarkText()

(and have uploaded the third and (hopefully) last version of the module: http://processwire.com/talk/topic/4264-release-page-image-manipulator/)

But it isn't really what I wanted it to be. It is because GD2 with PHP (at least with version < 5.5.0) doesn't support anti aliasing for transparency! :(

My initially plan was to analyse the source image histogram-data and automaticly set the fontcolor to more lighten or darker. Also I want to have it a bit blurred and transparent. But everytime one define the transparent color for the overlayed textmask, it gets cutted the hard way! (0 = nothing or 1=100%, and nothing in between) :(

I have tried to get a bit around that behave and now it depends on the source images. Sometimes it seems to be possible to use the method, and sometimes it's to ugly!
 

pw_watermarkText_example.jpg

  • Like 1

Share this post


Link to post
Share on other sites

The module is updated to version 0.0.4 and is available in the modules section now: http://mods.pw/5E

There are no other additions planned!

(So there should be some improvements done for a final stable version 1.0: all logging and errorhandling should be made ready for translation, but this isn't scheduled yet)

Share this post


Link to post
Share on other sites

Thanks for the hard work here Horst! Looks like a very useful and good implementation.

I'm in need of such a tool right now and I can't get it to work. When calling this in a template I get this error.

site/assets/files/1111/source_gartenidylle_031007_151328.jpg
Fatal error: Exception: Method Pageimage::imLoad does not exist or is not callable in this context (in /xxx/dev.urlich/wire/core/Wire.php line 320) #0 /xxx/html/dev.urlich/site/templates/home.php(32): Wire->__call('imLoad', Array) #1 /xxx/html/dev.urlich/site/templates/home.php(32): Pageimage->imLoad('bright_', Object(Pageimage)) #2 

Code is this:

$p = wire("pages")->get(1111);echo $p->image->url;
$img = $p->image;
$pim = $img->imLoad("bright_")->contrast(100)->brightness(100)->pimSave();

The module is loaded and the hook should be added (according to debug admin info) but the error suggests not? I tried with loading the module but then I get another error.

/site/assets/files/1111/source_gartenidylle_031007_151328.jpg
Fatal error: Exception: Cannot load the MemoryImage! (in /xxx/dev.urlich/site/modules/PageImageManipulator/ImageManipulator.class.php line 1216) #0 /xxx/dev.urlich/site/templates/home.php(32): ImageManipulator->contrast(100) #1 

I have no idea what could cause the problem, maybe it's just me and the server.

Some minor things:

- Your modules code has tabs and space indents mixed. Something I'm aware of because I use SublimeText2 and It does what it automatic. :)

- I found the name "PageImage" inconsistent to the core which uses "Pageimage".

- I get a Warning: Invalid argument supplied for foreach() in /xxx/dev.urlich/wire/modules/Process/ProcessModule/ProcessModule.module on line 671 on module screen of PageImageManipulator

  • Like 1

Share this post


Link to post
Share on other sites

 ...

Code is this:
$p = wire("pages")->get(1111);echo $p->image->url;
$img = $p->image;
$pim = $img->imLoad("bright_")->contrast(100)->brightness(100)->pimSave();

it must be $img->pimLoad("bright_")

EDIT:

to the 'minor things' I will have a look later and report back here, promised :)

Edited by horst

Share this post


Link to post
Share on other sites

$img->imLoad("bright_") should be $img->pimLoad("bright") I think.

Don't know why the underscore. and you've a typo in the "pim"

<blink>Horst wins !</blink>

Edited by Martijn Geerts
  • Like 1

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By BitPoet
      Here's a little text formatter module that redirects all external links found in a textarea (e.g. for hit counting) to a given URL.
      TextformatterExternalRedirect
      GitHub repo
      As TextFormatters do, this module modifies the contents of the textarea (HTML) at rendering time. It prepends the given URL to the link address for external links (http and https), optionally makes sure that the link is opened in a new window and allows you to add css classes to such links.
      All options can be configured in the module's configuration settings.
      Usage:
      Download the zip archive and extract it to site/modules, the rename the top folder to TextformatterExternalRedirect Go to the backend and select "Modules" -> "Refresh", then click "Install" for "External Link Redirect" Click "Settings" and configure the module
      Go into the field configuration for the field(s) you want this formatter to apply to and add it from the dropdown
      Done, now any external links in the configured fields will have the configured settings applied Feel free to leave feedback and post and questions you have here.
       
    • By teppo
      Hey folks!
      Took a couple of late nights, but managed to turn this old gist of mine into a proper module. The name is SearchEngine, and currently it provides support for indexing page contents (into a hidden textarea field created automatically), and also includes a helper feature ("Finder") for querying said contents. No fancy features like stemming here yet, but something along those lines might be added later if it seems useful (and if I find a decent implementation to integrate).
      Though the API and selector engine make it really easy to create site search pages, I pretty much always end up duplicating the same features from site to site. Also – since it takes a bit of extra time – it's tempting to skip over some accessibility related things, and leave features like text highlighting out. Overall I think it makes sense to bundle all that into a module, which can then be reused over and over again 🙂
      Note: markup generation is not yet built into the module, which is why the examples below use PageArray::render() method to produce a simple list of results. This will be added later on, as a part of the same module or a separate Markup module. There's also no fancy JS API or anything like that (yet).
      This is an early release, so be kind – I got the find feature working last night (or perhaps this morning), and some final tweaks and updates were made just an hour ago 😅
      GitHub repository: https://github.com/teppokoivula/SearchEngine Modules directory: https://modules.processwire.com/modules/search-engine/ Demo: https://wireframe-framework.com/search/ Usage
      Install SearchEngine module. Note: the module will automatically create an index field install time, so be sure to define a custom field (via site config) before installation if you don't want it to be called "search_index". You can change the field name later as well, but you'll have to update the "index_field" option in site config or module settings (in Admin) after renaming it.
      Add the site search index field to templates you want to make searchable. Use selectors to query values in site search index. Note: you can use any operator for your selectors, you will likely find the '=' and '%=' operators most useful here. You can read more about selector operators from ProcessWire's documentation.
      Options
      By default the module will create a search index field called 'search_index' and store values from Page fields title, headline, summary, and body to said index field when a page is saved. You can modify this behaviour (field name and/or indexed page fields) either via the Module config screen in the PocessWire Admin, or by defining $config->SearchEngine array in your site config file or other applicable location:
      $config->SearchEngine = [ 'index_field' => 'search_index', 'indexed_fields' => [ 'title', 'headline', 'summary', 'body', ], 'prefixes' => [ 'link' => 'link:', ], 'find_args' => [ 'limit' => 25, 'sort' => 'sort', 'operator' => '%=', 'query_param' => null, 'selector_extra' => '', ], ]; You can access the search index field just like any other ProcessWire field with selectors:
      if ($q = $sanitizer->selectorValue($input->get->q)) { $results = $pages->find('search_index%=' . $query_string . ', limit=25'); echo $results->render(); echo $results->renderPager(); } Alternatively you can delegate the find operation to the SearchEngine module as well:
      $query = $modules->get('SearchEngine')->find($input->get->q); echo $query->resultsString; // alias for $query->results->render() echo $query->pager; // alias for $query->results->renderPager() Requirements
      ProcessWire >= 3.0.112 PHP >= 7.1.0 Note: later versions of the module may require Composer, or alternatively some additional features may require installing via Composer. This is still under consideration – so far there's nothing here that would really depend on it, but advanced features like stemming most likely would.
      Installing
      It's the usual thing: download or clone the SearchEngine directory into your /site/modules/ directory and install via Admin. Alternatively you can install SearchEngine with Composer by executing composer require teppokoivula/search-engine in your site directory.
    • By teppo
      MarkupMenu is a markup module for generating menu trees. When provided a root page as a starting point, it generates a navigation tree (by default as a HTML "<ul>" element wrapped by a "<nav>" element) from that point onwards. If you've also provided it with current (active) page, the menu will be rendered accordingly, with current item highlighted and items rendered up to that item and its children (unless you disable the "collapsed" option, in which case the full page tree will be rendered instead).
      Modules directory: https://modules.processwire.com/modules/markup-menu/ GitHub repository: https://github.com/teppokoivula/MarkupMenu Usage
      As a markup module, MarkupMenu is intended for front-end use, but you can of course use it in a module as well. Typically you'll only need the render() method, which takes an array of options as its only argument:
      echo $modules->get('MarkupMenu')->render([ 'root_page' => $pages->get(1), 'current_page' => $page, ]); Note: if you omit root_page, site root page is used by default. If you omit current_page, the menu will be rendered, but current (active) page won't be highlighted etc.
      A slightly more complex example, based on what I'm using on one of my own sites to render a (single-level) top menu:
      echo $modules->get('MarkupMenu')->render([ 'current_page' => $page, 'templates' => [ 'nav' => '<nav class="{classes} menu--{menu_class_modifier}" aria-label="{aria_label}">%s</nav>', 'item_current' => '<a class="menu__item menu__item--current" href="{item.url}" tabindex="0" aria-label="Current page: {item.title}">{item.title}</a>', ], 'placeholders' => [ 'menu_class_modifier' => 'top', 'aria_label' => 'Main navigation', ], 'include' => [ 'root_page' => true, ], 'exclude' => [ 'level_greater_than' => 1, ], ]); Note: some things you see above may not be entirely sensible, such as the use of {menu_class_modifier} and {aria_label} placeholders. On the actual site the "nav" template is defined in site config, so I can define just these parts on a case-by-case basis while actual nav markup is maintained in one place.
      Please check out the README file for available render options. I'd very much prefer not to keep this list up to date in multiple places. Basically there are settings for defining "templates" for different parts of the menu (list, item, etc.), include array for defining rules for including in the menu and exclude array for the opposite effect, classes and placeholders arrays for overriding default classes and injecting custom placeholders, etc. 🙂
      MarkupMenu vs. MarkupSimpleNavigation
      TL;DR: this is another take on the same concept. There are many similarities, but also some differences – especially when it comes to the supported options and syntax. If you're currently using MarkupSimpleNavigation then there's probably no reason to switch over.
      I'd be surprised if someone didn't draw lines between this module and Soma's awesome MarkupSimpleNavigation. Simply put I've been using MSN (...) for years, and it's been great – but there are some issues with it, particularly in the markup generation area, and it also does some things in a way that doesn't quite work for me – the xtemplates thing being one of these. In some ways less about features, and more about style, I guess 🙂
      Anyhow, in MarkupMenu I've tried to correct those little hiccups, modernise the default markup, and allow for more flexibility with placeholder variables and additional / different options. MarkupMenu was built for ProcessWire 3.0.112+ and with PHP 7.1+ in mind, it's installable with Composer, and I have a few additional ideas (such as conditional placeholders) still on my todo list.
      One more small(ish) difference is that MarkupMenu supports overriding default options via $config->MarkupMenu. I find myself redefining the default markup for every site, which until now meant that each site had a wrapper function for MarkupSimpleNavigation (to avoid code / config repetition), and this way I've been able to leave that out 🙂
      Requirements
      ProcessWire >= 3.0.112 PHP >= 7.1.0 If you're working on an earlier version of ProcessWire or PHP, use MarkupSimpleNavigation instead.
    • By teppo
      Hey folks!
      I'm happy to finally introduce a project I've been working on for quite a while now: it's called Wireframe, and it is an output framework for ProcessWire.
      Note that I'm posting this in the module development area, maily because this project is still in rather early stage. I've built a couple of sites with it myself, and parts of the codebase have been powering some pretty big and complex sites for many years now, but this should still be considered a soft launch 🙂
      --
      Long story short, Wireframe is a module that provides the "backbone" for building sites (and apps) with ProcessWire using an MVC (or perhaps MVVM – one of those three or four letter abbreviations anyway) inspired methodology. You could say that it's an output strategy, but I prefer the term "output framework" since in my mind the word "strategy" means something less tangible. A way of doing things, rather than a tool that actually does things.
      Wireframe (the module) provides a basic implementation for some familiar MVC concepts, such as Controllers and a View layer – the latter of which consists of layouts, partials, and template-specific views. There's no "model" layer, since in this context ProcessWire is the model. As a module Wireframe is actually quite simple – not even nearly the biggest one I've built – but there's still quite a bit of stuff to "get", so I've put together a demo & documentation site for it at https://wireframe-framework.com/.
      In addition to the core module, I'm also working on a couple of site profiles based on it. My current idea is actually to keep the module very light-weight, and implement most of the "opinionated" stuff in site profiles and/or companion modules. For an example MarkupMenu (which I released a while ago) was developed as one of those "companion modules" when I needed a menu module to use on the site profiles.
      Currently there are two public site profiles based on Wireframe:
      site-wireframe-docs is the demo&docs site mentioned above, just with placeholder content replaced with placeholder content. It's not a particularly complex site, but I believe it's still a pretty nice way to dig into the Wireframe module. site-wireframe-boilerplate is a boilerplate (or starter) site profile based on the docs site. This is still very much a work in progress, but essentially I'm trying to build a flexible yet full-featured starter profile you can just grab and start building upon. There will be a proper build process for resources, it will include most of the basic features one tends to need from site to site, etc. --
      Requirements and getting started:
      Wireframe can be installed just like any ProcessWire module. Just clone or download it to your site/modules/ directory and install. It doesn't, though, do a whole lot of stuff on itself – please check out the documentation site for a step-by-step guide on setting up the directory structure, adding the "bootstrap file", etc. You may find it easier to install one of the site profiles mentioned above, but note that this process involves the use of Composer. In the case of the site profiles you can install ProcessWire as usual and download or clone the site profile directory into your setup, but after that you should run "composer install" to get all the dependencies – including the Wireframe module – in place. Hard requirements for Wireframe are ProcessWire 3.0.112 and PHP 7.1+. The codebase is authored with current PHP versions in mind, and while running it on 7.0 may be possible, anything below that definitely won't work. A feature I added just today to the Wireframe module is that in case ProcessWire has write access to your site/templates/ directory, you can use the module settings screen to create the expected directories automatically. Currently that's all, and the module won't – for an example – create Controllers or layouts for you, so you should check out the site profiles for examples on these. (I'm probably going to include some additional helper features in the near future.)
      --
      This project is loosely based on an earlier project called pw-mvc, i.e. the main concepts (such as Controllers and the View layer) are very similar. That being said, Wireframe is a major upgrade in terms of both functionality and architecture: namespaces and autoloader support are now baked in, the codebase requires PHP 7, Controllers are classes extending \Wireframe\Controller (instead of regular "flat" PHP files), implementation based on a module instead of a collection of drop-in files, etc.
      While Wireframe is indeed still in a relatively early stage (0.3.0 was launched today, in case version numbers matter) for the most part I'm happy with the way it works, and likely won't change it too drastically anytime soon – so feel free to give it a try, and if you do, please let me know how it went. I will continue building upon this project, and I am also constantly working on various side projects, such as the site profiles and a few unannounced helper modules.
      I should probably add that while Wireframe is not hard to use, it is more geared towards those interested in "software development" type methodology. With future updates to the module, the site profiles, and the docs I hope to lower the learning curve, but certain level of "developer focus" will remain. Although of course the optimal outcome would be if I could use this project to lure more folks towards that end of the spectrum... 🙂
      --
      Please let me know what you think – and thanks in advance!
    • By Robin S
      After forgetting the class name of the wonderful AdminPageFieldEditLinks module for what feels like the 100th time I decided I needed to give my failing memory a helping hand...
      Autocomplete Module Class Name
      Provides class name autocomplete suggestions for the "Add Module From Directory" and "Add Module From URL" fields at Modules > New.
      Requires ProcessWire >= v3.0.16.
      Screencast

      Installation
      Install the Autocomplete Module Class Name module.
      Configuration
      Add Module From Directory
      Choose the type of autocomplete suggestions list: "Module class names from directory" or "Custom list of module class names". The latter could be useful if you regularly install some modules and would prefer a shorter list of autocomplete suggestions. The list of class names in the modules directory is generated when the Autocomplete Module Class Name module is installed. It doesn't update automatically (because the retrieval of the class names is quite slow), but you can use the button underneath when you want to retrieve an updated list of class names from the directory. Add Module From URL
      If you want to see autocomplete suggestions for the "Add Module From URL" field then enter them in the following format:
      [autocomplete suggestion] > [module ZIP url]
      Example: RepeaterImages > https://github.com/Toutouwai/RepeaterImages/archive/master.zip Awesomplete options
      The "fuzzy search" option uses custom filter and item functions for Awesomplete so that the characters you type just have to exist in the autocomplete suggestion item and occur after preceding matches but do not need to be contiguous. Uncheck this option if you prefer the standard Awesomplete matching. Custom settings for Awesomplete can be entered in the "Awesomplete options" field if needed. See the Awesomplete documentation for more information.  
      https://github.com/Toutouwai/AutocompleteModuleClassName
      https://modules.processwire.com/modules/autocomplete-module-class-name/
×
×
  • Create New...