Executing `createimagefrompng()` from save_post hook (or equivalent hook)

I’m having trouble executing createimagefrompng() from a hook. I’ve used the fairly straightforward PHP way to add a watermark to an image. If I hardcode the image URLs in this function and for example execute it from a page or whatever it seems to work flawlessly, but whenever I execute the exact function from a hook (to add watermarks to images just uploaded to a post), WordPress seems to ‘crash’ (as in, the loading spinner keeps spinning and nothing actually happens).

The PHP code I use for the watermark – which works perfectly when called from a template or whatever:

// Load the stamp and the photo to apply the watermark to
$stamp = imagecreatefrompng('stamp.png');
$im = imagecreatefromjpeg('photo.jpeg');

// 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($im, $stamp, imagesx($im) - $sx - $marge_right, imagesy($im) - $sy - $marge_bottom, 0, 0, imagesx($stamp), imagesy($stamp));

// Output and free memory
header('Content-type: image/png');
imagepng($im);
imagedestroy($im);

Whenever I put this in a function, and comment out code part by part it seems to already crash on the first $stamp = ... line. Can’t really figure out why this happens.

tl;dr scenario sketch
I want to add a watermark to every image uploaded in an ACF field in a specific posttype but the watermark PHP code provided in the PHP.net docs crashes on the first line of code.

Thanks guys!

1 Answer
1

The use of header() function produce output in the middle of the request and crash it.

To modify uploaded image you should use wp_handle_upload filter instead of save_post action. Also, ideally, you should use WP_Image_Editor class, which will use the best image manipulation library available in the server (GD, Imagemagick) and triggers several filters and actions that can be used by another plugins:

add_filter( 'wp_handle_upload', 'cyb_handle_upload_callback' );
function cyb_handle_upload_callback( $data ) {

    // get instance of WP_Image_Editor class
    $image = wp_get_image_editor( $data['file'] );

    if( ! is_wp_error( $image ) ) {

        // Manipulate your image here
        $stamp = imagecreatefrompng( 'path/to/stamp.png' );
        $margin_right = 10;
        $margeing_bottom = 10;
        $sx = imagesx( $stamp );
        $sy = imagesy( $stamp );

        imagecopy(
            $data['file'],
            $stamp,
            imagesx( $data['file'] ) - $sx - $margin_right,
            imagesy( $data['file'] ) - $sy - $margin_bottom,
            0,
            0,
            imagesx( $stamp ),
            imagesy( $stamp )
        );

        // Save the modified image
        $image->save();

    }

    return $data;
}

If we follow this implementation extending WP_Editor_Image class:

add_filter( 'wp_handle_upload', 'cyb_handle_upload_callback' );
function cyb_handle_upload_callback( $data ) {

    $image = wp_get_image_editor( $data['file'] );

    if ( ! is_wp_error( $image ) && is_callable( [ $image, 'stamp_watermark' ] ) ) {

        $stamp = imagecreatefrompng( '/path/to/stamp.png' );
        $success = $editor->stamp_watermark( $stamp );

        if ( ! is_wp_error( $success ) ) {
            $image->save();
        }

    }

    return $data;
}

Leave a Comment