Draw annotation with multiply blend mode

71 views
Skip to first unread message

Matt Parizeau

unread,
Nov 29, 2018, 8:24:18 PM11/29/18
to pdfnet-w...@googlegroups.com
Q:

Is it possible to create a custom annotation with multiply blend mode?

A:

Yes, here is an example of overriding the draw function of the Rectangle annotation so that all Rectangles will be multiply blended with the page content. This code also uses the context_blender library to use multiply blend mode on browsers that don't support it natively like IE11.

$(document).on('viewerLoaded', function() {
  var docViewer = readerControl.docViewer;
  var annotManager = docViewer.getAnnotationManager();

  docViewer.on('pageComplete', function(e, pageIndex) {
    annotManager.drawAnnotations(pageIndex + 1);
  });
});


var isMultiplySupported = function(ctx) {
  ctx.globalCompositeOperation = 'multiply';
  return ctx.globalCompositeOperation === 'multiply';
};

var setupOverCanvas = function(annotation, drawParams) {
  var ctx = drawParams[0];
  // save existing annotations drawn so far
  saveCanvas.width = ctx.canvas.width;
  saveCanvas.height = ctx.canvas.height;
  saveCanvasCtx.drawImage(ctx.canvas, 0, 0);

  ctx.save();
  ctx.setTransform(1, 0, 0, 1, 0, 0);
  ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  ctx.restore();

  // draw the annotation
  ctx.save();
  rectangleDraw.apply(annotation, drawParams);
  ctx.restore();

  // save the drawn annotation to the "over" canvas
  overCanvas.width = ctx.canvas.width;
  overCanvas.height = ctx.canvas.height;
  overCtx.drawImage(ctx.canvas, 0, 0);

  // reset the canvas
  ctx.save();
  ctx.setTransform(1, 0, 0, 1, 0, 0);
  ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  ctx.restore();
};


var tempCanvas = document.createElement('canvas');
var tempCtx = tempCanvas.getContext('2d');

var saveCanvas = document.createElement('canvas');
var saveCanvasCtx = saveCanvas.getContext('2d');

var overCanvas = document.createElement('canvas');
var overCtx = overCanvas.getContext('2d');

var rectangleDraw = Annotations.RectangleAnnotation.prototype.draw;
Annotations.RectangleAnnotation.prototype.draw = function(ctx) {
  var isHrThumb = false;

  var pageIndex = this.PageNumber - 1;
  var pageCanvas = document.querySelector('.canvas' + pageIndex);
  if (!pageCanvas) {
    isHrThumb = true;
    pageCanvas = document.getElementById('hrthumb' + pageIndex);
  }

  var canvasMultiplier = window.utils.getCanvasMultiplier();
  ctx.save();
  if (pageCanvas) {
    if (!isMultiplySupported(ctx)) {
      setupOverCanvas(this, arguments);
    }

    var docViewer = readerControl.docViewer;
    var rotation = docViewer.getCompleteRotation(this.PageNumber);

    var xPoint = this.X;
    var yPoint = this.Y;
    // some browsers have trouble with a zero width or height in drawImage calls
    var width = this.Width || 1;
    var height = this.Height || 1;

    var zoom = docViewer.getZoom();
    var scalingFactor = (pageCanvas.width / parseFloat(pageCanvas.style.width)) * zoom;
    var topOffset = parseFloat(pageCanvas.style.top) || 0;
    var leftOffset = parseFloat(pageCanvas.style.left) || 0;
    var pageInfo = docViewer.getDocument().getPageInfo(pageIndex);
    var docPageRotation = rotation - docViewer.getRotation();
    if (docPageRotation % 2 !== 0) {
      var tempWidth = pageInfo.width;
      pageInfo.width = pageInfo.height;
      pageInfo.height = tempWidth;
    }

    var unrotatedWidth = (rotation % 2 === 0) ? pageCanvas.width : pageCanvas.height;
    var unrotatedHeight = (rotation % 2 === 0) ? pageCanvas.height : pageCanvas.width;

    if (!isHrThumb) {
      tempCanvas.width = unrotatedWidth;
      tempCanvas.height = unrotatedHeight;

      if (rotation === CoreControls.PageRotation.e_90) {
        tempCtx.rotate(-Math.PI / 2);
        tempCtx.translate(-tempCanvas.height, 0);

        var tempLeftOffset = topOffset;
        topOffset = pageInfo.height * scalingFactor - tempCanvas.height - leftOffset;
        leftOffset = tempLeftOffset;
      } else if (rotation === CoreControls.PageRotation.e_180) {
        tempCtx.rotate(Math.PI);
        tempCtx.translate(-tempCanvas.width, -tempCanvas.height);

        leftOffset = pageInfo.width * scalingFactor - tempCanvas.width - leftOffset;
        topOffset = pageInfo.height * scalingFactor - tempCanvas.height - topOffset;
      } else if (rotation === CoreControls.PageRotation.e_270) {
        tempCtx.rotate(Math.PI / 2);
        tempCtx.translate(0, -tempCanvas.width);

        var tempTopOffset = leftOffset;
        leftOffset = pageInfo.width * scalingFactor - tempCanvas.width - topOffset;
        topOffset = tempTopOffset;
      }

      if (rotation !== CoreControls.PageRotation.e_0) {
        tempCtx.drawImage(pageCanvas, 0, 0);
        pageCanvas = tempCanvas;
      }
    }

    var x = xPoint * scalingFactor - leftOffset;
    var y = yPoint * scalingFactor - topOffset;

    ctx.drawImage(pageCanvas, x, y, width * scalingFactor, height * scalingFactor, this.X, this.Y, width, height);

    if (!isMultiplySupported(ctx)) {
      // draw original canvas over top before blending so that annotations are blended
      ctx.save();
      ctx.setTransform(1, 0, 0, 1, 0, 0);
      ctx.drawImage(saveCanvas, 0, 0);
      ctx.restore();

      // use context_blender function
      overCtx.bO(ctx, 'multiply');
    }
  } else {
    rectangleDraw.apply(this, arguments);
  }
  ctx.restore();

  if (isMultiplySupported(ctx)) {
    ctx.globalCompositeOperation = 'multiply';

    rectangleDraw.apply(this, arguments);
  }
};

Reply all
Reply to author
Forward
0 new messages