<?php
/*
Plugin Name: Watermark
Description: Applies a watermark image to all uploaded images
Version: 1.01
Requires at least: 2.03
*/

// You can add multiple watermarking rules to apply different images to different upload fields. Only the first rule which matches a field will be applied.

watermark_addRule(array(
  'tables'  => '',              # Comma-separated list of table names to be watermarked. To apply this rule to all tables, leave blank or comment out this line.
  'fields'  => '',              # Comma-separated list of upload field names to be watermarked. To apply this rule to all upload fields, leave blank or comment out this line.
  'thumb'   => '',              # Comma-separated list of thumbnail indexes (e.g. '1,3,5') or '' for original image.
  'image'   => 'http://localhost/test/logo.png', # url or filepath to watermarking image
  'alpha'   => 1,               # Translucency: 1 = opaque, 0.5 = half-transparent
  'hAlign'  => 'right',         # Horizontal Alignment: left, center, right
  'vAlign'  => 'bottom',        # Vertical Alignment: top, middle, bottom
  'hMargin' => 5,               # Horizontal Margin: pixels left between left/right edge of image and watermark (n/a when hAlign=center)
  'vMargin' => 5,               # Vertical Margin: pixels left between top/bottom edge of image and watermark (n/a when vAlign=middle)
));


// DON'T UPDATE ANYTHING BELOW THIS LINE

addAction('upload_save',           'watermark_onUploadSave');
addAction('upload_thumbnail_save', 'watermark_onThumbnailSave');

function watermark_addRule( $ruleInfo ) {
  if (!@$GLOBALS['WATERMARK_RULES']) { $GLOBALS['WATERMARK_RULES'] = array(); }
  $GLOBALS['WATERMARK_RULES'][] = $ruleInfo;
}

function watermark_onThumbnailSave( $args ) {
  list($tablename, $fieldname, $suffix, $thumbSavePath) = $args;
  $thumbIndex = $suffix;
  if ($suffix == '') { $thumbIndex = '1'; }
  _watermark_onSave( $tablename, $fieldname, $thumbSavePath, $thumbIndex );
}

function watermark_onUploadSave( $args ) {
  list($tablename, $fieldname, $sourceFilepath) = $args;
  _watermark_onSave( $tablename, $fieldname, $sourceFilepath, '' );
}

function _watermark_onSave( $tablename, $fieldname, $sourceFilepath, $thumbIndex ) {

  // find the first rule which matches tablename and fieldname
  $matchingRule = null;
  if (@$GLOBALS['WATERMARK_RULES']) {
    foreach ($GLOBALS['WATERMARK_RULES'] as $rule) {

      if (@$rule['tables']) {
        $validTables = preg_split('/\s*,\s*/', $rule['tables']);
        if (!in_array( $tablename, $validTables )) { continue; }
      }

      if (@$rule['fields']) {
        $validFields = preg_split('/\s*,\s*/', $rule['fields']);
        if (!in_array( $fieldname, $validFields )) { continue; }
      }

      if (@$rule['thumb']) {
        if (!$thumbIndex) { continue; }
        $validThumbIndexes = preg_split('/\s*,\s*/', $rule['thumb']);
        if (!in_array( $thumbIndex, $validThumbIndexes )) { continue; }
      }
      else {
        if ($thumbIndex) { continue; }
      }

      // we found a matching rule, stop looking at more rules
      $matchingRule = $rule;
      break;
    }
  }

  // if we didn't find a rule, return without doing anything
  if (!$matchingRule) { return; }

  // render a watermarked image using our matching rule
  list($targetImage, $sourceType) = _watermark_watermarkImage(array(
    'source'    => $sourceFilepath,
    'watermark' => $matchingRule['image'],
    'alpha'     => $matchingRule['alpha'],
    'hAlign'    => $matchingRule['hAlign'],
    'vAlign'    => $matchingRule['vAlign'],
    'hMargin'   => $matchingRule['hMargin'],
    'vMargin'   => $matchingRule['vMargin'],
  ));

  // if watermarking failed, return without doing anything
  if (!$targetImage) { return; }

  // overwrite source image
  switch($sourceType) {
    case IMAGETYPE_JPEG: imagejpeg( $targetImage, $sourceFilepath ); break;
    case IMAGETYPE_GIF:  imagegif(  $targetImage, $sourceFilepath ); break;
    case IMAGETYPE_PNG:  imagepng(  $targetImage, $sourceFilepath ); break;
    default: die(__FUNCTION__ . ": Unknown image type!"); break;
  }
}


function _watermark_watermarkImage($options) {
  list($sourceImage, $sourceWidth, $sourceHeight, $sourceType) = _watermark_getImage($options['source']);
  list($watermarkImage, $watermarkWidth, $watermarkHeight)     = _watermark_getImage($options['watermark']);

  // if either image is not actually an image, return without doing anything
  if (!$sourceImage || !$watermarkImage) { return; }

  $targetImage = imagecreatetruecolor($sourceWidth, $sourceHeight);

  // determine watermark offset based on options: hAlign, vAlign, hMargin, vMargin
  if      ( strtolower($options['hAlign']) == 'left'   ) { $watermarkOffsetX = $options['hMargin']; }
  else if ( strtolower($options['hAlign']) == 'center' ) { $watermarkOffsetX = $sourceWidth / 2 - $watermarkWidth / 2; }
  else if ( strtolower($options['hAlign']) == 'right'  ) { $watermarkOffsetX = $sourceWidth - $watermarkWidth - $options['hMargin']; }
  else                                                   { die(__FUNCTION__ . ": Illegal hMargin value!"); }
  if      ( strtolower($options['vAlign']) == 'top'    ) { $watermarkOffsetY = $options['vMargin']; }
  else if ( strtolower($options['vAlign']) == 'middle' ) { $watermarkOffsetY = $sourceHeight / 2 - $watermarkHeight / 2; }
  else if ( strtolower($options['vAlign']) == 'bottom' ) { $watermarkOffsetY = $sourceHeight - $watermarkHeight - $options['vMargin']; }
  else                                                   { die(__FUNCTION__ . ": Illegal vMargin value!"); }

  // first, copy the source image to the target image
  imagecopyresized($targetImage, $sourceImage, 0, 0, 0, 0, $sourceWidth, $sourceHeight, $sourceWidth, $sourceHeight);

  // render the watermark onto it, pixel-by-pixel
  for( $y = 0; $y < $watermarkHeight; $y++ ) {
    for( $x = 0; $x < $watermarkWidth; $x++ ) {

      // determine which pixel on the target image we're rendering to
      $targetX = $x + $watermarkOffsetX;
      $targetY = $y + $watermarkOffsetY;

      // if this pixel would fall outside our image, skip it (this should only happen if the watermark (plus margins) is bigger than our source image)
      if ( $targetX < 0 || $targetY < 0 || $targetX >= $sourceWidth || $targetY >= $sourceHeight ) { continue; }

      // get colours of both pixels
      $sourcePixelColor    = imagecolorsforindex( $sourceImage, imagecolorat( $sourceImage, $targetX, $targetY ) );
      $watermarkPixelColor = imagecolorsforindex( $watermarkImage, imagecolorat( $watermarkImage, $x, $y ) );

      // determine alpha of watermark pixel based on pixel's alpha and global $options['alpha']
      $watermarkFinalPixelAlpha = round( ( ( 127 - $watermarkPixelColor['alpha'] ) / 127 ), 2 ) * $options['alpha'];

      // mix colours to get target pixel colour
      $avg_red   = _watermark_mixColours( $sourcePixelColor['red'],   $watermarkPixelColor['red'],   $watermarkFinalPixelAlpha );
      $avg_green = _watermark_mixColours( $sourcePixelColor['green'], $watermarkPixelColor['green'], $watermarkFinalPixelAlpha );
      $avg_blue  = _watermark_mixColours( $sourcePixelColor['blue'],  $watermarkPixelColor['blue'],  $watermarkFinalPixelAlpha );

      // set target pixel colour
      imagesetpixel( $targetImage, $targetX, $targetY, _watermark_pickColourIndex( $targetImage, $avg_red, $avg_green, $avg_blue ) );
    }
  }

  imagedestroy($sourceImage);
  imagedestroy($watermarkImage);

  return array($targetImage, $sourceType);
}

/*function _watermark_displayImage( $image, $imageType ) {
  switch($imageType) {
    case IMAGETYPE_JPEG: header('Content-Type: image/jpeg'); header('Content-Disposition: inline; filename=test.jpg'); imagejpeg( $image, '' ); break;
    case IMAGETYPE_GIF:  header('Content-Type: image/gif');  header('Content-Disposition: inline; filename=test.gif'); imagegif(  $image, '' ); break;
    case IMAGETYPE_PNG:  header('Content-Type: image/png');  header('Content-Disposition: inline; filename=test.png'); imagepng(  $image, '' ); break;
    default:     die(__FUNCTION__ . ": Unknown image type!"); break;
  }
}*/

function _watermark_getImage( $sourcePath ) {
  list($width, $height, $imageType) = getimagesize($sourcePath);
  switch($imageType) {
    case IMAGETYPE_JPEG:  $image = @imagecreatefromjpeg($sourcePath); break; // Use @ and ini_set('gd.jpeg_ignore_warning') in init.php to suppress gd invalid jpeg errors. See: http://bugs.php.net/bug.php?id=39918
    case IMAGETYPE_GIF:   $image = imagecreatefromgif($sourcePath); break;
    case IMAGETYPE_PNG:   $image = imagecreatefrompng($sourcePath); break;
    default:              return; break;
  }
  return array( $image, $width, $height, $imageType );
}

function _watermark_mixColours( $color1, $color2, $ratio ) {
  return round((( $color1 * ( 1 - $ratio )) + ( $color2  * $ratio )));
}

function _watermark_pickColourIndex( $image, $r, $g, $b ) {
  $colourIndex = imagecolorexact( $image, $r, $g, $b );
  if ($colourIndex != -1) { return $colourIndex; }

  $colourIndex = imagecolorallocate( $image, $r, $g, $b );
  if ($colourIndex != -1) { return $colourIndex; }

  return imagecolorclosest( $image, $r, $g, $b );
}

?>
