horst

Page Image Manipulator 1

Recommended Posts

horst    3,958

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

  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
horst    3,958

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 20

Share this post


Link to post
Share on other sites
owzim    595

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
Wanze    1,366

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
horst    3,958

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
kongondo    5,003

@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    3,958

@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
ryan    13,367

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
Raymond Geerts    482

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
Raymond Geerts    482

@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    3,958

@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
Raymond Geerts    482

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
horst    3,958

@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    3,958

@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
horst    3,958

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
horst    3,958

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
Soma    6,126

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
horst    3,958

 ...

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
Martijn Geerts    3,178

$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

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


  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By bernhard
      hi everybody,
      this is a preview of a module that i'm working on for quite a long time. I needed it for an intranet office management application that i'm still working on. It makes it very easy to create very customized Datatables using the awesome jquery datatables plugin (www.datatables.net)
       
      EARLY ALPHA release!
      It's very likely that there will lots of changes to this module that may cause breaking your implementations.
       
      Module source
      sorry, removed as it changes too frequently; closed alpha - contact me if you think you can contribute
       
       
      Remarks:
      The module is intended to be used on the backend. Loading styles is at the moment only done via adding files to the $config->styles/scripts arrays. Also the communicaton to javascript is done via the $config->js() method that is built into the admin and would have to be implemented manually on frontend use. But it would not be difficult of course
      Installation:
      Nothing special here, just download + install
       
      edit: removed some parts, because i made a complete rewrite of the module! (see last posting in the thread)
       
      Customization example:
      in the screencast you see an example that i'm using in a process module. i put the table inside an InputfieldMarkup just to have the same look&feel all around the admin. you see that you could also use this module to create tables quickly and easily using @kongondo s runtime markup module.
      complete PHP code:
      $this->headline('Kundenliste'); $form = $modules->get('InputfieldForm'); // init datatables module $dt2 = $modules->get('RockDataTables2'); // setup columns // name $col = new dtCol(); $col->name = 'name'; $col->title = 'Name'; $col->data = function($page) { return $page->title; }; $dt2->cols->add($col); // type $col = new dtCol(); $col->name = 'type'; $col->data = function($page) { return $page->rockcontact_type->title; }; $dt2->cols->add($col); // modified $col = new dtCol(); $col->name = 'modified'; $col->data = function($page) { $obj = new stdClass(); $obj->timestamp = $page->modified; $obj->display = date('d.m.Y', $page->modified); return $obj; }; $dt2->cols->add($col); // setup table $dt2->id = 'dt_kundenliste'; $dt2->js('/site/modules/ProcessRockProjects/dt_kundenliste.js'); $f = $modules->get('InputfieldMarkup'); $f->value = $dt2->render(); $form->add($f); // ################################## // ajax request -> return data // non-ajax -> render form + table // ################################## if($config->ajax) { echo $dt2->getJSON($pages->find('template=rockcontact, sort=random, limit=10000')); die(); } else $out .= $form->render(); return $out; what is interesting here is this part:
      // modified $col = new dtCol(); $col->name = 'modified'; $col->data = function($page) { $obj = new stdClass(); $obj->timestamp = $page->modified; $obj->display = date('d.m.Y', $page->modified); return $obj; }; $dt2->cols->add($col); datatables support orthogonal data (https://datatables.net/extensions/buttons/examples/html5/outputFormat-orthogonal.html). a date column is a good example, because you need to DISPLAY a formatted date (like 10.02.2017) but you need to be able to SORT this column by a different value (timestamp). its very easy to accomplish this by providing both values in your json. Btw: You could also just transfer the timestamp and do the formatting on the client-side via javascript. Next Example will show ho this would work. Both cases can be necessary, it's just an example here.
      [...] removed
      Why i created this module:
      of course i know @Soma s module but i needed a lot more features and the newer datatables version. also i like to define all the columns as objects and have everything on one place. lister & markupadmindatatable: nice for basic tables but lacks of features to modify the appearance of the cell values (like rendering icons, background colors and so on) datatables provides a great frontend API for filtering, showing/hiding columns, getting data, modifying it... it also plays well together with frontend charts like google chart api in this case:
       
      todo / roadmap:
      all kinds of column filters (like seen in the example above that shows an older and bloated version of this module) support for ajax filters and pagination (currently all filtering and sorting is done on the client side. i tried it with up to 50.000 rows and got reasonable results. initial loading took around 10sec. but of course this heavily depends on the complexity of your table and your data.  
       
       
    • By Robin S
      PageListTrash
      Allows non-superusers to trash pages directly from Page List (if they have page-delete permission for that page).
      Not much to say really - the module adds a "Trash" option to the extra actions for pages in Page List. It looks and works just like the Trash action available to superusers.

      https://github.com/Toutouwai/PageListTrash/
       
      Up to you whether you think non-superusers should be trusted with simpler trashing. For most cases I like the default behaviour where editors have to jump through some more hoops - I want them to think carefully about what they are doing. But if an editor needs to trash several pages then this module might reduce frustration.
      @tpr, by now you can probably predict what I'm going to say...
      ...something to merge into AdminOnSteroids?
    • By horst
      Wire Mail SMTP

      An extension to the new WireMail base class that uses SMTP-transport

      This module integrates EmailMessage, SMTP and SASL php-libraries from Manuel Lemos into ProcessWire. I use this continously evolved libraries for about 10 years now and there was never a reason or occasion not to do so. I use it nearly every day in my office for automated composing and sending personalized messages with attachments, requests for Disposition Notifications, etc. Also I have used it for sending personalized Bulkmails many times.

      The WireMailSmtp module extends the new email-related WireMail base class introduced in ProcessWire 2.4.1 (while this writing, the dev-branch only).
       
      Here are Ryans announcement.



      Current Version 0.2.5
      get it from the Modules Directory Install and Configure

      Download the module into your site/modules/ directory and install it.

      In the config page you fill in settings for the SMTP server and optionaly the (default) sender, like email address, name and signature.
      You can test the smtp settings directly there. If it says "SUCCESS! SMTP settings appear to work correctly." you are ready to start using it in templates, modules or bootstrap scripts.


      Usage Examples
      The simplest way to use it:
      $numSent = wireMail($to, $from, $subject, $textBody); $numSent = wireMail($to, '', $subject, $textBody); // or with a default sender emailaddress on config page This will send a plain text message to each recipient.
       
      You may also use the object oriented style:
      $mail = wireMail(); // calling an empty wireMail() returns a wireMail object $mail->to($toEmail, $toName); $mail->from = $yourEmailaddress; // if you don't have set a default sender in config // or if you want to override that $mail->subject($subject); $mail->body($textBody); $numSent = $mail->send(); Or chained, like everywhere in ProcessWire:
      $mail = wireMail(); $numSent = $mail->to($toEmail)->subject($subject)->body($textBody)->send(); Additionaly to the basics there are more options available with WireMailSmtp. The main difference compared to the WireMail BaseClass is the sendSingle option. With it you can set only one To-Recipient but additional CC-Recipients.
      $mail = wireMail(); $mail->sendSingle(true)->to($toEmail, $toName)->cc(array('person1@example.com', 'person2@example.com', 'person3@example.com')); $numSent = $mail->subject($subject)->body($textBody)->send(); The same as function call with options array:
      $options = array( 'sendSingle' => true, 'cc' => array('person1@example.com', 'person2@example.com', 'person3@example.com') ); $numSent = wireMail($to, '', $subject, $textBody, $options); There are methods to your disposal to check if you have the right WireMail-Class and if the SMTP-settings are working:
      $mail = wireMail(); if($mail->className != 'WireMailSmtp') { // Uups, wrong WireMail-Class: do something to inform the user and quit echo "<p>Couldn't get the right WireMail-Module (WireMailSmtp). found: {$mail->className}</p>"; return; } if(!$mail->testConnection()) { // Connection not working: echo "<p>Couldn't connect to the SMTP server. Please check the {$mail->className} modules config settings!</p>"; return; } Following are a ...


      List of all options and features


      testConnection () - returns true on success, false on failures


      sendSingle ( true | false ) - default is false

      sendBulk ( true | false ) - default is false, Set this to true if you have lots of recipients (50+)


      to ($recipients) - one emailaddress or array with multiple emailaddresses

      cc ($recipients) - only available with mode sendSingle, one emailaddress or array with multiple emailaddresses

      bcc ($recipients) - one emailaddress or array with multiple emailaddresses

       
      from = 'person@example.com' - emailaddress, can be set in module config (called Sender Emailaddress) but it can be overwritten here

      fromName = 'Name Surname' - optional, can be set in module config (called Sender Name) but it can be overwritten here


      priority (3) - 1 = Highest | 2 = High | 3 = Normal | 4 = Low | 5 = Lowest

      dispositionNotification () or notification () - request a Disposition Notification


      subject ($subject) - subject of the message

      body ($textBody) - use this one alone to create and send plainText emailmessages

      bodyHTML ($htmlBody) - use this to create a Multipart Alternative Emailmessage (containing a HTML-Part and a Plaintext-Part as fallback)

      addSignature ( true | false ) - the default-behave is selectable in config screen, this can be overridden here
      (only available if a signature is defined in the config screen)

      attachment ($filename, $alternativeBasename = "") - add attachment file, optionally alternative basename


      send () - send the message(s) and return number of successful sent messages


      getResult () - returns a dump (array) with all recipients (to, cc, bcc) and settings you have selected with the message, the message subject and body, and lists of successfull addresses and failed addresses,


      logActivity ($logmessage) - you may log success if you want

      logError ($logmessage) - you may log warnings, too. - Errors are logged automaticaly
       
       
      useSentLog (true | false) - intended for usage with e.g. third party newsletter modules - tells the send() method to make usage of the sentLog-methods - the following three sentLog methods are hookable, e.g. if you don't want log into files you may provide your own storage, or add additional functionality here

      sentLogReset ()  - starts a new LogSession - Best usage would be interactively once when setting up a new Newsletter

      sentLogGet ()  - is called automaticly within the send() method - returns an array containing all previously used emailaddresses

      sentLogAdd ($emailaddress)  - is called automaticly within the send() method
       
      Changelog: https://github.com/horst-n/WireMailSmtp/blob/master/CHANGELOG.md
       
    • By celfred
      Hello,
      I'm desperately trying to update my website to PW 3.0.62 and I'm facing issues to to module compatibility. I was stuck with Pages2Pdf which I managed to solve bu updating the module from Github, but now it's the Pages Web Service module... and this time, I don't know wht to do
      The Module is found there. But it is quite old and I can't find it in the modules catalogue... and my site is making quite a use of it (I can't think of a way to do otherwise, sorry...)
      After adding the FileCompiler=0 to the module pages, the error I'm stuck with is :
      Fatal error: Class 'WireData' not found in /home/celfred/PlanetAlert/site/modules/ServicePages/ServicePages.module on line 22
      and I have no idea on what to do... I must admit I'm not a programmer but a middle-school teacher... (for your information, here's the site I'm talking about : http://planetalert.tuxfamily.org ) but I'm struggling hard to solve the different issues I have to face and I'm wlling to understand things. I have just spent many hours trying to make 2.8 work on my localhost (and it seems ok ) but I'd like to switch to 3.x to prepare the future
      If anyone had the will to spend a few minutes to try and help me, I would greatly appreciate.
      Thanks in advance !
      If you need more information to understand my problem, feel free to ask.
    • By dimitrios
      Hello,
      I have created a module that, given a Facebook app ID and secret, posts on Facebook on behalf of a user profile or page after a PW page is saved.
      This module is configurable as follows:
      Templates: posts can take place only for pages with the defined templates On/Off switch: specify a checkbox field that will not allow the post if checked Specify a message and/or an image for the post
      Usage
      edit the desired PW page and save; it will post right after the initial Facebook log in and permission granting. After that, a token is kept.
       
      Download
      PW module directory: http://modules.processwire.com/modules/auto-fb-post/ Github: https://github.com/kastrind/AutoFbPost   Note: Facebook SDK for PHP is used.