PDF image diff

142 views
Skip to first unread message

Matt Parizeau

unread,
Sep 13, 2018, 6:19:19 PM9/13/18
to PDFTron WebViewer
Q:

Is it possible to display the differences between two PDF documents? For simplicity assume that they are both one page.

A:

Yes, you could load the first document in the viewer and then load a second document in memory and render the first page onto a canvas. Then you could append the canvas over top of the viewer and update the color of the pixels to indicate where the files overlap.

Here is code that you could put into a config file. Note the places where you should enter your license key and the path to the second document.

$(document).on('documentLoaded', function() {
 
var newDoc = new CoreControls.Document('file.pdf', 'pdf');
 
var docLocation = '/PATH/TO/OTHER/DOCUMENT.pdf';
 
var pageIndex = 0;
 
var currentLoadCanvas;
 
var lastRenderRect;

 
function update() {
    currentLoadCanvas
= updatePage(newDoc, pageIndex, currentLoadCanvas, lastRenderRect);
 
}

  loadDocument
(newDoc, docLocation, function() {
   
if ($('.canvas' + pageIndex).length > 0) {
      update
();
   
}

    readerControl
.docViewer.on('pageComplete', function(e, completedPageIndex) {
     
if (completedPageIndex === pageIndex) {
        update
();
     
}
   
});
 
});

  readerControl
.docViewer.on('beginRendering', function() {
    lastRenderRect
= readerControl.docViewer.getViewportRegionRect(readerControl.docViewer.getCurrentPage() - 1);
   
if (currentLoadCanvas) {
      newDoc
.cancelLoadCanvas(currentLoadCanvas);
   
}
 
});
});

var updatePage = function(doc, pageIndex, currentLoadCanvas, lastRenderRect) {
 
if (currentLoadCanvas) {
    doc
.cancelLoadCanvas(currentLoadCanvas);
 
}

 
var firstDocCanvas = $('.canvas' + pageIndex)[0];
 
// make first doc blue
 
var firstDocCtx = firstDocCanvas.getContext('2d');
 
var firstDocImageData = firstDocCtx.getImageData(0, 0, firstDocCanvas.width, firstDocCanvas.height);
 
var firstDocData = firstDocImageData.data;

 
for (var i = 0; i < firstDocData.length; i += 4) {
   
// make all non-white pixels blue
   
var isWhite = firstDocData[i] === 255 && firstDocData[i + 1] === 255 && firstDocData[i + 2] === 255;
   
if (!isWhite) {
      firstDocData
[i] = 0;
      firstDocData
[i + 1] = 0;
      firstDocData
[i + 2] = 255;
   
}
 
}
  firstDocCtx
.putImageData(firstDocImageData, 0, 0);

 
var isViewportRender = firstDocCanvas.style.left !== '';

 
return doc.loadCanvasAsync({
    pageIndex
: pageIndex,
    canvasNum
: 1,
    getZoom
: function() {
     
return readerControl.docViewer.getZoom();
   
},
    drawComplete
: function(pageCanvas) {
      $
('.canvasOverlay').remove();

     
var $pageCanvas = $(pageCanvas);
      $pageCanvas
.css({
        position
: 'absolute',
       
'z-index': 25,
        left
: firstDocCanvas.style.left,
        top
: firstDocCanvas.style.top,
       
'background-color': ''
     
});
      $pageCanvas
.addClass('canvasOverlay');
      $
('#pageContainer' + pageIndex).append(pageCanvas);

     
var ctx = pageCanvas.getContext('2d');
     
var imageData = ctx.getImageData(0, 0, pageCanvas.width, pageCanvas.height);
     
var data = imageData.data;

     
for (var i = 0; i < data.length; i += 4) {
       
// make all white pixels transparent
       
if (data[i] === 255 && data[i + 1] === 255 && data[i + 2] === 255) {
          data
[i + 3] = 0;
       
} else {
         
var coords = getCoords(i, pageCanvas.width);
         
var index = getIndex(coords, firstDocCanvas.width);
         
if (coords.y <= firstDocCanvas.height && coords.x <= firstDocCanvas.width &&
           
(firstDocData[index] !== 255 || firstDocData[index + 1] !== 255 || firstDocData[index + 2] !== 255)) {
           
// make overlapping pixels gray
            data
[i] = 128;
            data
[i + 1] = 128;
            data
[i + 2] = 128;
         
} else {
           
// make all other pixels red
            data
[i] = 255;
            data
[i + 1] = 0;
            data
[i + 2] = 0;
         
}
       
}
     
}
      ctx
.putImageData(imageData, 0, 0);
   
},
    renderRect
: isViewportRender ? lastRenderRect : undefined
 
});
};

function getCoords(i, width) {
 
var pixels = Math.floor(i / 4);

 
return {
    x
: pixels % width,
    y
: Math.floor(pixels / width)
 
};
}

function getIndex(coords, width) {
 
return ((coords.y * width) + coords.x) * 4;
}

function loadDocument(doc, docLocation, callback) {
 
CoreControls.getDefaultBackendType().then(function(backendType) {
     
var options = {
        workerTransportPromise
: CoreControls.initPDFWorkerTransports(backendType, {}, 'LICENSE_KEY_HERE')
     
};
     
var partRetriever = new CoreControls.PartRetrievers.ExternalPdfPartRetriever(docLocation);
      doc
.loadAsync(partRetriever, callback, options);
 
});
}


Reply all
Reply to author
Forward
0 new messages