7

I really like the WP_Image_Editor class. I wanted to use it for some custom functionality I'm making, but I was wondering - Watermarking images - is there a way that I could use the objects created by WP_Image_Editor to merge an image with a watermark? I cannot figure out any obvious way.

3

If you really want to use these classes the only way would be to extend both existing implementations Wp_Image_Editor_Imagick and Wp_Image_Editor_GD.

Here's an approach for the Wp_Image_Editor_GD:

namespace WPSE98156;

use
    Wp_Image_Editor_Gd,
    Wp_Error;

class WatermarkImageEditor extends Wp_Image_Editor_Gd {

    /*
     * @param resource $stamp (A GD image resource)
     *
     * @return bool|WP_Error
     */
    public function stamp_watermark( $stamp ) {

        /**
         * The resource of the image to edit is stored in
         * $this->image, after $this->load() was called
         */
        $loaded = $this->load();
        if ( is_wp_error( $loaded ) )
            return $loaded;

        // Set the margins for the stamp and get the height/width of the stamp image
        $marge_right = 10;
        $marge_bottom = 10;
        $sx = imagesx( $stamp );
        $sy = imagesy( $stamp );

        // Copy the stamp image onto our photo using the margin offsets and the photo
        // width to calculate positioning of the stamp.
        imagecopy(
            $this->image,
            $stamp,
            imagesx( $this->image ) - $sx - $marge_right,
            imagesy( $this->image ) - $sy - $marge_bottom,
            0,
            0,
            imagesx( $stamp ),
            imagesy( $stamp )
        );
    }

    /**
     * @param array $args
     *
     * @return bool
     */
    public static function test( $args = [] ) {

        /**
         * Maybe implement your own test here, whether the environment
         * is able to deal with your implementation of the
         * stamp_watermark() method
         */
        return parent::test( $args );
    }

    /**
     * @param string $mime_type
     *
     * @return bool
     */
    public static function supports_mime_type( $mime_type ) {

        /**
         * Todo: Check here if the implementation of the method stamp_watermark()
         * can deal with the mime-types image/png, image/jpeg and image/gif
         */
        return parent::supports_mime_type( $mime_type );
    }
}

The implementation follows this example on php.net.

Now that you have your implementation you must add the new class to the stack of possible image editors using the filter wp_image_editors:

namespace WPSE98156;

add_filter( 'wp_image_editors', function( $editors ) {

    if ( ! is_array( $editors ) )
        return $editors; //someone broke the filtered value

    array_unshift( $editors, WatermarkImageEditor::class );

    return $editors;
} );

Now it's likely possible to get an instance of your custom editor when calling wp_get_image_editor():

$editor = wp_get_image_editor( '/path/to/image.jpeg' );
if ( ! is_wp_error( $editor ) && is_callable( [ $editor, 'stamp_watermark' ] ) && ! is_wp_error( $loaded ) ) {

    $stamp = imagecreatefrompng( '/path/to/watermark.png' );
    $success = $editor->stamp_watermark( $stamp );
    if ( ! is_wp_error( $success ) )
        $editor->save();
}

You could also simply create the instance explicitly. Every other client, using wp_get_image_editor() won't be aware of the method stamp_watermark() anyway.

Some important notes:

  • The code is not tested. It's meant to provide a first approach on how to extend the Wp_Image_Editor_Gd class.
  • The examples show syntax that requires at least PHP 5.5
  • All tasks about loading required files are not shown. Use proper auto loading.
  • I'm not into the details of the GD API. So I'm not sure about supported mime-types, you should test this and implement the methods test() and supportet_mime_types() according to this.
2

I have had a lot of problems implementing David code. I had errors like “WP_IMAGE_EDITOR_GD” not found, “WatermarkImageEditor” not found… And when I got it to work, it didn’t work with alpha channel png, so I lost a lot of hours making it work with them. So I will explain how I have it.

Put all this code in a php file, mine is called watermark.php.

<?php
class WatermarkImageEditor extends WP_Image_Editor_GD {
    public function stamp_watermark( $stampPath, $marginH=0, $marginV=0 ) {
        $loaded = $this->load();
        if ( is_wp_error( $loaded ) ) return $loaded;

        $stamp=imagecreatefrompng( $stampPath );
        if(is_wp_error($stamp)){ return $stamp; }
        imagealphablending($stamp, true);

        $sx = imagesx( $stamp );
        $sy = imagesy( $stamp );
        imagealphablending($this->image, true);
        imagecopy(
            $this->image, $stamp,$marginH,$this->size['height']-$sy-$marginV,0,0,$sx, $sy
        );  
    }

    public static function test( $args = [] ) { return parent::test( $args ); }

    public static function supports_mime_type( $mime_type ) { return parent::supports_mime_type( $mime_type ); }
}

Now, we need to register the filter. I am using it in my own plugin, so I have this code on my main plugin file, but you can also put it on other place like functions.php. Note that I am using require_once to load watermark.php, so watermark.php has to be in the same folder.

add_filter( 'wp_image_editors', function( $editors ) {
    require_once __DIR__. '/watermark.php';
    if ( ! is_array( $editors ) )
        return $editors; //someone broke the filtered value
    array_unshift( $editors, "WatermarkImageEditor");
    return $editors;
} );

And the last step, call to stamp_watermark(). On this example, I am loading an image from disk, resizing it, putting the watermark, and saving it. Note that stamp_watermark() receives on the first parameter, the path or url of the watermark, the other 2 parameters are the optional margin.

$editor= wp_get_image_editor($imagePath);
$editor->resize(1920, 1080, TRUE);
if(is_callable([$editor,'stamp_watermark'])){
  $success = $editor->stamp_watermark( ABSPATH.'wp-content/uploads/watermark-full.png', 20, 20 );       
  if(!is_wp_error($success)){ $editor->save($imagePath); }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.