How to rerender PDF.js page with different scale? - pdf.js

I'm trying just to run the same procedure, but with different scale. But it gives me broken pictures. So what is the correct way to update scale?
function draw(num, scale) {
pdfDoc.getPage(num).then(function(page) {
var viewport = page.getViewport(scale);
var canvas = document.getElementById('the-canvas');
var context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
var renderContext = {
canvasContext: context,
viewport: viewport
};
page.render(renderContext);
}
}
draw(1, 1);
draw(1, 2);

Related

How i can extract svg element with text pdf js

I need extarct svg element with text from pdf. But if i did like this:
PDF:
Pdf link https://dropfiles.org/2dTlpxTN
const PDF_PATH = "https://dropfiles.org/2dTlpxTN";
const PAGE_NUMBER = 1;
const PAGE_SCALE = 1.5;
const SVG_NS = "http://www.w3.org/2000/svg";
pdfjsLib.GlobalWorkerOptions.workerSrc =
"../../node_modules/pdfjs-dist/build/pdf.worker.js";
function buildSVG(viewport, textContent) {
// Building SVG with size of the viewport (for simplicity)
const svg = document.createElementNS(SVG_NS, "svg:svg");
svg.setAttribute("width", viewport.width + "px");
svg.setAttribute("height", viewport.height + "px");
// items are transformed to have 1px font size
svg.setAttribute("font-size", 1);
// processing all items
textContent.items.forEach(function (textItem) {
// we have to take in account viewport transform, which includes scale,
// rotation and Y-axis flip, and not forgetting to flip text.
const tx = pdfjsLib.Util.transform(
pdfjsLib.Util.transform(viewport.transform, textItem.transform),
[1, 0, 0, -1, 0, 0]
);
const style = textContent.styles[textItem.fontName];
// adding text element
const text = document.createElementNS(SVG_NS, "svg:text");
text.setAttribute("transform", "matrix(" + tx.join(" ") + ")");
text.setAttribute("font-family", style.fontFamily);
text.textContent = textItem.str;
svg.append(text);
});
return svg;
}
async function pageLoaded() {
// Loading document and page text content
const loadingTask = pdfjsLib.getDocument({ url: PDF_PATH });
const pdfDocument = await loadingTask.promise;
const page = await pdfDocument.getPage(PAGE_NUMBER);
const viewport = page.getViewport({ scale: PAGE_SCALE });
const textContent = await page.getTextContent();
// building SVG and adding that to the DOM
const svg = buildSVG(viewport, textContent);
document.getElementById("pageContainer").append(svg);
// Release page resources.
page.cleanup();
}
document.addEventListener("DOMContentLoaded", function () {
if (typeof pdfjsLib === "undefined") {
// eslint-disable-next-line no-alert
alert("Please build the pdfjs-dist library using\n `gulp dist-install`");
return;
}
pageLoaded();
});
I extracted text with out Font and i extract all text. I need extract text as image.
If i do this:
pdfDoc_.getPage(pageNumber).then(function (page) {
var canvasEl = document.createElement('canvas');
var context = canvasEl.getContext('2d');
var viewport = page.getViewport({scale: imagesSetting_reader.scaleText});
canvasEl.height = viewport.height;
canvasEl.width = viewport.width;
var back;
var renderContext = {
canvasContext: context,
background:back,
viewport: viewport
};
page.render(renderContext).promise.then(function () {
resolve(canvasEl.toDataURL("image/png"));
})
});
It extracted text and background image.
if i do like this :
page.getOperatorList().then(opList => {
var svgGfx = new pdfjsLib.SVGGraphics(page.commonObjs, page.objs);
return svgGfx.getSVG(opList, viewport);
}).then(svg => {
console.log(svg)
return svg;
});
And extracted text from svg, i got error :
error on line 1 at column 101: Namespace prefix svg on svg is not defined
How i can extract only svg text with font and convert it to image ?
Like this:

Image canvas toDataURL function is not wokring on ios

I have a drawImage function in my application which loads the image from a blob and then from that image object calls the toDataURL function for the canvas to draw image. The problem is that this code works on android and browser but not working on iphone or ipad.
I have tried passing the image type to the toDataURL function and tried setting the default width and height of the canvas to prevent width getting 0 for the canvas but nothing seems to work on iphone or ipad. It only shows a blank screen inplace of the image.
the code works fine on mac/safari as well but not in iphone/ipad on any browser.
here is my drawImage function
_drawImage(img) {
// console.log("drawimage");
this.setState({ isGenerating: true });
if (img) {
fetch(img)
.then((r) => r.blob())
.then((blob) => {
loadImage(
blob,
(img) => {
if (img.type === "error") {
this.setState({ error: true });
// console.log(img, "Error loading image ");
} else {
const image = new window.Image();
const height = this.props.height;
const width = this.props.width;
image.src = img.toDataURL('image/jpeg');
console.log(image.src, height, width)
image.onload = () => {
let offsetX,
offsetY,
renderableWidth = image.width,
renderableHeight = image.height;
var imageDimensionRatio = image.width / image.height;
var canvasDimensionRatio = width / height;
// console.log(
// "ratios of image and canvas =",
// imageDimensionRatio,
// canvasDimensionRatio
// );
if (imageDimensionRatio < canvasDimensionRatio) {
renderableHeight = height;
renderableWidth =
image.width * (renderableHeight / image.height);
offsetX = (width - renderableWidth) / 2;
offsetY = 0;
} else if (imageDimensionRatio > canvasDimensionRatio) {
renderableWidth = width;
renderableHeight =
image.height * (renderableWidth / image.width);
offsetX = 0;
offsetY = (height - renderableHeight) / 2;
} else {
renderableHeight = height;
renderableWidth = width;
offsetX = 0;
offsetY = 0;
}
console.log(renderableHeight, renderableWidth, image)
this.setState(
{
image: image,
renderableHeight,
renderableWidth,
imgHeight: image.height,
imgWidth: image.width,
offsetX,
offsetY,
height,
width,
},
() => {
this.setState({ isGenerating: false });
}
);
};
}
},
{
orientation: true,
canvas: true,
}
);
});
}
}
EDIT
I've solved the issue by passing maxWidth to loadImage params along with orientation and canvas, which limits the width to not to exceed in ios devices and thus onload function works properly.
basically I've added the below code.
maxWidth: 10000

HighChart and PDF generation

I am trying to generate a PDF from the high-chat graph. The graph renders correctly on the canvas created, but the PDF generated just has a "black" patch.
var trendChart=$("#trendChart").highcharts();
let trendSvgString = trendChart.getSVG({
exporting: {
sourceWidth: trendChart.chartWidth,
sourceHeight: trendChart.chartHeight
}
});
let parser = new DOMParser();
var EXPORT_WIDTH = 1000;
var render_width = EXPORT_WIDTH;
var render_height = render_width * trendChart.chartHeight / trendChart.chartWidth
var canvas = document.createElement('canvas');
canvas.height = render_height;
canvas.width = render_width;
document.body.appendChild(canvas);
var ctx = canvas.getContext("2d");
var image = new Image;
image.onload = function() {
canvas.getContext('2d').drawImage(this, 0, 0, render_width, render_height);
};
image.src = 'data:image/svg+xml;base64,' + window.btoa(trendSvgString);
var dataURL = canvas.toDataURL("image/jpeg");
console.log(dataURL);
var doc = new window.jspdf.jsPDF('p','pt','a4');
doc.addImage(dataURL, 'JPEG', 10, 10, 500, 200);
doc.save('a4.pdf')
console.log('pdf generated');
What could be missing here?

How to get PNG image data from a Canvas in Flutter?

I have a Flutter widget that accepts user input and draws to a canvas using a custom painter:
class SPPoint {
final Point point;
final double size;
SPPoint(this.point, this.size);
String toString() => "SPPoint $point $size";
}
class SignaturePadPainter extends CustomPainter {
final List<SPPoint> allPoints;
final SignaturePadOptions opts;
Canvas _lastCanvas;
Size _lastSize;
SignaturePadPainter(this.allPoints, this.opts);
ui.Image getPng() {
if (_lastCanvas == null) {
return null;
}
if (_lastSize == null) {
return null;
}
var recorder = new ui.PictureRecorder();
var origin = new Offset(0.0, 0.0);
var paintBounds = new Rect.fromPoints(_lastSize.topLeft(origin), _lastSize.bottomRight(origin));
var canvas = new Canvas(recorder, paintBounds);
paint(canvas, _lastSize);
var picture = recorder.endRecording();
return picture.toImage(_lastSize.width.round(), _lastSize.height.round());
}
paint(Canvas canvas, Size size) {
_lastCanvas = canvas;
_lastSize = size;
for (var point in this.allPoints) {
var paint = new Paint()..color = colorFromColorString(opts.penColor);
paint.strokeWidth = 5.0;
var path = new Path();
var offset = new Offset(point.point.x, point.point.y);
path.moveTo(point.point.x, point.point.y);
var pointSize = point.size;
if (pointSize == null || pointSize.isNaN) {
pointSize = opts.dotSize;
}
canvas.drawCircle(offset, pointSize, paint);
paint.style = PaintingStyle.stroke;
canvas.drawPath(path, paint);
}
}
bool shouldRepaint(SignaturePadPainter oldDelegate) {
return true;
}
}
Currently currently getPng() returns a dart:ui Image object, but I can't tell how to get the bytes from the image data (if this is even possible)
Here's the solution I came up with, now that toByteData() was added to the SDK:
var picture = recorder.endRecording();
var image =
picture.toImage(lastSize.width.round(), lastSize.height.round());
ByteData data = await image.toByteData(format: ui.ImageByteFormat.png);
return data.buffer.asUint8List();
This solution is working and has now been published to pub as part of the signature_pad_flutter package: https://github.com/apptreesoftware/signature-pad-dart/blob/master/signature_pad_flutter/lib/src/painter.dart#L17

for embedded PDFs, can PDFJS support both scrolling and jump to a page number at the same time?

This seems like it should be very standard behavior.
I can display a scrollable PDF with:
var container = document.getElementById('viewerContainer');
var pdfViewer = new PDFJS.PDFViewer({
container: container,
});
PDFJS.getDocument(DEFAULT_URL).then(function (pdfDocument) {
pdfViewer.setDocument(pdfDocument);
});
and I can display the PDF page by page with something like:
PDFJS.getDocument(URL_ANNOTATED_PDF_EXAMPLE).then(function getPdfHelloWorld(pdf) {
pdf.getPage(pageNumber).then(function getPageHelloWorld(page) {
var scale = 1.5;
var viewport = page.getViewport(scale);
var canvas = document.getElementById('the-canvas');
var context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
var renderContext = {
canvasContext: context,
viewport: viewport
};
page.render(renderContext);
});
But can't seem to find any reference in the API to both allow scrolling and jumping to a particular page, besides:
pdfViewer.currentPageNumber = 3;
which doesn't work...
So I found a way to make this work (mixed with a little Angular code, "$scope.$watch...") I now have other problems with font decoding. But here is a solution that might help someone else.
var me = this;
PDFJS.externalLinkTarget = PDFJS.LinkTarget.BLANK;
var container = document.getElementById('capso-court-document__container');
function renderPDF(url, container) {
function renderPage(page) {
var SCALE = 1;
var pdfPageView = new PDFJS.PDFPageView({
container: container,
id: page.pageIndex + 1,
scale: SCALE,
defaultViewport: page.getViewport(SCALE),
textLayerFactory: new PDFJS.DefaultTextLayerFactory(),
annotationLayerFactory: new PDFJS.DefaultAnnotationLayerFactory()
});
pdfPageView.setPdfPage(page);
return pdfPageView.draw();
}
function renderPages(pdfDoc) {
var pageLoadPromises = [];
for (var num = 1; num <= pdfDoc.numPages; num++) {
pageLoadPromises.push(pdfDoc.getPage(num).then(renderPage));
}
return $q.all(pageLoadPromises);
}
PDFJS.disableWorker = true;
return PDFJS.getDocument(url)
.then(renderPages);
}
$scope.$watch(function() {
return {
filingUrl: me.filingUrl,
whenPageSelected: me.whenPageSelected,
};
}, function(newVal, oldVal) {
if (newVal.filingUrl) {
//newVal.filingUrl = URL_EXAMPLE_PDF_ANNOTATED;
//newVal.filingUrl = URL_EXAMPLE_PDF_ANNOTATED_2;
//newVal.filingUrl = URL_EXAMPLE_PDF_MULTI_PAGE;
if (newVal.filingUrl !== oldVal.filingUrl &&
newVal.whenPageSelected &&
newVal.whenPageSelected.page) {
scrollToPage(newVal.whenPageSelected.page);
}
//HACK - create new container for each newly displayed PDF
container.innerHTML = '';
var newContainerForNewPdfSelection = document.createElement('div');
container.appendChild(newContainerForNewPdfSelection);
renderPDF(newVal.filingUrl, newContainerForNewPdfSelection).then(function() {
if (newVal.whenPageSelected &&
newVal.whenPageSelected.page) {
scrollToPage(newVal.whenPageSelected.page);
}
});
}
}, true);
function scrollToPage(pageNumber) {
var pageContainer = document.getElementById('pageContainer' + pageNumber);
if (pageContainer) {
container.scrollTop = pageContainer.offsetTop;
} else {
console.warn('pdf pageContainer doesn\'t exist for index', pageNumber);
}
}

Resources