I'm trying to create a pdf that auto-pages when a content increases.
This is my sample code. Any help would be greatly appreciated :)
HTML code
<div *ngFor="let data of data">
<button click = "previewPdf(data)"> Preview </button>
</div>
Javascript
previewPdf(data) {
var doc = new jsPDF();
let bodyContent = doc.splitTextToSize(data.body, 250);
let lineheight = 6;
let offsety = 5;
this.data.forEach(function(i) {
doc.setFontSize(20);
doc.text(10,10 + lineheight * 0 + offsety, bodyContent);
doc.output("dataurlnewwindow");
});
}
JSON
data[{
"body": "A very long letter content...";
}];
Edit:
I have tried this sample code below and its giving me 2 pages and the last page is blank
previewPdf(data) {
var doc = new jsPDF('p', 'mm', 'a4');
let pageHeight = doc.internal.pageSize.getHeight();
let bodyContent = doc.splitTextToSize(data.body, 250);
let lineheight = 6;
let offsetY = 5;
doc.text(10, 10, bodyContent);
// Before adding new content
let y = 840; // Height position of new content
if (y >= pageHeight) {
doc.addPage();
y = 0 // Restart height position
}
// this.data.forEach(function(i) {
// doc.setFontSize(20);
//
// });
doc.output("dataurlnewwindow");
}
You can use addHTML for that using pagesplit parameter
Edit:
There's another dirty hack where you can calculate the height of the page remaining before adding content
doc = new jsPdf();
pageHeight= pdf.internal.pageSize.height; //get total page height
Then when adding content check height condition like below
pdf.text(x, y, "value");
if (y>=pageHeight)
{
pdf.addPage();
}
Working solution
previewPdf(data) {
var doc = new jsPDF();
var bodyContent = doc.splitTextToSize(data.body, 250);
var pageHeight = doc.internal.pageSize.getHeight();
doc.setFontType("normal");
doc.setFontSize("12");
var y = 15;
for (var i = 0; i < bodyContent.length; i++) {
if (y+10 > pageHeight) {
y = 15;
doc.addPage();
}
doc.text(10, y, bodyContent[i]);
y = y + 7;
}
doc.output('dataurlnewwindow');
}
Related
I can't get the problem fixed that my image is always cut off in the PDF file. The PDF size seems to be correct but I can't see my entire page as an image.
I have been trying for hours but without success.
Code:
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.3/jspdf.min.js"></script>
<script src="https://html2canvas.hertzen.com/dist/html2canvas.js"></script>
<script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
<script>
function addWaterMark(pdf) {
var totalPages = pdf.internal.getNumberOfPages();
for (i = 1; i <= totalPages; i++) {
pdf.setPage(i);
pdf.addImage("data:image/png;base64,......", "JPEG", 20, 40, 130, 30);
}
return pdf;
}
function getPDF(){
var HTML_Width = $("div#mycontent").width();
var HTML_Height = $("div#mycontent").height();
var top_left_margin = 100;
var PDF_Width = HTML_Width+(top_left_margin*2);
var PDF_Height = $("div#mycontent").height();
var canvas_image_width = HTML_Width;
var canvas_image_height = HTML_Height/1.1;
var totalPDFPages = Math.ceil(HTML_Height/PDF_Height)-1;
html2canvas($("div#mycontent")[0],{allowTaint:true},{pagesplit: false},{scrollY: -window.scrollY}).then(function(canvas) {
canvas.getContext('2d');
console.log(canvas.height+" "+canvas.width);
var imgData = canvas.toDataURL("image/jpeg", 0.99);
var pdf = new jsPDF('p', 'pt', [PDF_Width, PDF_Height]);
pdf.addImage(imgData, 'JPEG', top_left_margin, top_left_margin,canvas_image_width,canvas_image_height);
pdf = addWaterMark(pdf);
pdf.save("test.pdf");
});
};
</script>
Now:
Image Now
What i want:
Image what i want
In Developer Tool the Content Height is: 20887
Any Solution for this?
You could try changing to portrait or landscape according to width-height of the image. I was getting some cut images and it got fixed this way.
If width > height use landscape "l", if height > width use portrit "p":
html2canvas(document.getElementById(id_div)).then(canvas => {
var w = document.getElementById(id_div).offsetWidth;
var h = document.getElementById(id_div).offsetHeight;
var img = canvas.toDataURL("image/jpeg", 1);
if(w > h){
var doc = new jsPDF('l', 'mm', [w+100, h+50]);
}
else{
var doc = new jsPDF('p', 'mm', [h+100, w+50]);
}
doc.addImage(img, 'JPEG', 10, 10);
doc.save('chart.pdf');
}).catch(function(e) {
console.log(e.message);
});
I have made the following script to batch resize and center JPG photos in an SVG file:
function container()
{
var sourceFolder = Folder.selectDialog();
var TypeList = prompt("Enter file types to act on","ai,eps,pdf,jpg,png","File Types");
var reg = new RegExp("\.(" + TypeList.replace(/,/g, '|') + ")$", 'i');
var filesToProcess = sourceFolder.getFiles(reg);
var x = 400;
var y = 300;
var w = 800;
var h = 600;
var userDesktop = Folder.desktop;
var f = new File(userDesktop+'/Satz 2.aia'); // make a file object first, using a string
function fitObjectToArtboardBounds()
{
var idoc = app.activeDocument;
var layers = idoc.layers;
var scriptID = "Random Select v0.2";
var selec = idoc.selection;
for(var x=0,len=layers.length;x<len;x++)
{
layers[x].hasSelectedArtwork = true;
}
selec = idoc.selection;
if (selec.length == 1)
{
var docw = idoc.width;
var doch = idoc.height;
var activeAB = idoc.artboards[idoc.artboards.getActiveArtboardIndex()]; // get active AB
docLeft = activeAB.artboardRect[0];
docTop = activeAB.artboardRect[1];
var sel = idoc.selection[0];
var selVB = sel.visibleBounds;
var selVw = selVB[2] - selVB[0];
var selVh = selVB[1] - selVB[3];
var selGB = sel.geometricBounds;
var selGw = selGB[2] - selGB[0];
var selGh = selGB[1] - selGB[3];
var deltaX = selVw - selGw;
var deltaY = selVh - selGh;
if (sel.width > sel.height)
{
var newHeight = doch - deltaY;
var ratio = sel.height / newHeight;
sel.height = newHeight;
sel.width = sel.width / ratio;
}
else
{
var newHeight = doch - deltaY;
var ratio = sel.height / newHeight;
sel.height = newHeight;
sel.width = sel.width / ratio;
}
sel.top = (doch / 2) - (sel.height / 2);
sel.left = (docw / 2) - (sel.width / 2);
app.doScript('Aktion1', 'Satz 3');
app.executeMenuCommand('fitall');
}
else
{
alert("select ONE object before running");
}
}
var userDesktop = Folder.desktop;
var g = new File(userDesktop+'/Satz 4.aia'); // make a file object first, using a string
app.loadAction (g); // the argument here is a file object
g = new File(userDesktop+'/Satz 3.aia'); // make a file object first, using a string
app.loadAction (g); // the argument here is a file object
// Create progress bar
var win = new Window("palette", "ProgressBar", [300, 150, 750, 280]);
win.pnl = win.add("panel", [10, 10, 440, 120], "Script Progress");
win.pnl.progBar = win.pnl.add("progressbar", [20, 35, 410, 60], 0, 100);
win.pnl.progBarLabel = win.pnl.add("statictext", [20, 20, 320, 35], "0%");
win.pnl.fileLabel = win.pnl.add("statictext", [20, 65, 410, 80], "File processed: none");
win.show();
// Increment through the files
for (var i=0; i < filesToProcess.length; i++) {
app.open(filesToProcess[i]);
app.activeDocument.artboards[0].artboardRect = [x, -y, (x + w), -(y + h)];
fitObjectToArtboardBounds();
win.pnl.fileLabel.text = "File: " + app.activeDocument.name;
app.doScript ('Aktion3', 'Satz 4');
app.activeDocument.close();
win.pnl.progBar.value = parseInt( (i/filesToProcess.length)*100 );
win.pnl.progBarLabel.text = win.pnl.progBar.value+"%";
win.update();
}
win.pnl.progBar.value = 100;
win.pnl.progBarLabel.text = win.pnl.progBar.value+"%";
win.update();
alert('Done!');
win.close();
win.pnl.progBar.value = parseInt( (i/filesToProcess.length)*100 );
win.pnl.progBarLabel.text = win.pnl.progBar.value+"%";
win.update();
win.pnl.progBar.value = 100;
win.pnl.progBarLabel.text = win.pnl.progBar.value+"%";
win.update();
alert('Done!');
win.close();
}
container();
The output file size is as big as the original JPG file (around 5 MB) while it should be around max 200 kB.
How could I reduce size ?
I thought about SVG options, but I don't know how to make it since the Saving part in my script is just an Illustrator action app.doScript ('Aktion3', 'Satz 4'); and is not modifiable.
For information, JPEG photo inside the SVG file is linked I think, and while its dimensions is reduced to 800x600 px, its DPI is still very high (> 400).
Thanks in advance for your help !
Below is my script which was working fine.
But right now my image url was static at bottom of the script,
But i want to make it dynamic using file upload button.
Means if i select a file from upload button, then it will preview both images.
Below is the line
img.src = "https://image.ibb.co/bGtv0z/Product_Two.jpg";
where my image was fixed. i want to get this URL from file upload button.
Please help me to make it dynamic.
var img = new Image(),
$canvas = $("<canvas>"),
canvas = $canvas[0],
context;
var removeBlanks = function(imgWidth, imgHeight) {
var imageData = context.getImageData(0, 0, imgWidth, imgHeight),
data = imageData.data,
getRBG = function(x, y) {
var offset = imgWidth * y + x;
return {
red: data[offset * 4],
green: data[offset * 4 + 1],
blue: data[offset * 4 + 2],
opacity: data[offset * 4 + 3]
};
},
isWhite = function(rgb) {
// many images contain noise, as the white is not a pure #fff white
return rgb.red > 242 && rgb.green > 240 && rgb.blue > 240;
},
scanY = function(fromTop) {
var offset = fromTop ? 1 : -1;
// loop through each row
for (var y = fromTop ? 0 : imgHeight - 1; fromTop ? (y < imgHeight) : (y > -1); y += offset) {
// loop through each column
for (var x = 0; x < imgWidth; x++) {
var rgb = getRBG(x, y);
if (!isWhite(rgb)) {
return y;
}
}
}
return null; // all image is white
},
scanX = function(fromLeft) {
var offset = fromLeft ? 1 : -1;
// loop through each column
for (var x = fromLeft ? 0 : imgWidth - 1; fromLeft ? (x < imgWidth) : (x > -1); x += offset) {
// loop through each row
for (var y = 0; y < imgHeight; y++) {
var rgb = getRBG(x, y);
if (!isWhite(rgb)) {
return x;
}
}
}
return null; // all image is white
};
var cropTop = scanY(true),
cropBottom = scanY(false),
cropLeft = scanX(true),
cropRight = scanX(false),
cropWidth = cropRight - cropLeft,
cropHeight = cropBottom - cropTop;
var $croppedCanvas = $("<canvas>").attr({
width: cropWidth,
height: cropHeight
});
// finally crop the guy
$croppedCanvas[0].getContext("2d").drawImage(canvas,
cropLeft, cropTop, cropWidth, cropHeight,
0, 0, cropWidth, cropHeight);
$("#oldimg").
append("<p>same image with white spaces cropped:</p>").
append($croppedCanvas);
console.log(cropTop, cropBottom, cropLeft, cropRight);
};
img.crossOrigin = "anonymous";
img.onload = function() {
$canvas.attr({
width: this.width,
height: this.height
});
context = canvas.getContext("2d");
if (context) {
context.drawImage(this, 0, 0);
$("#newimg").append("<p>original image:</p>").append($canvas);
removeBlanks(this.width, this.height);
} else {
alert('Get a real browser!');
}
};
// define here an image from your domain
img.src = "https://image.ibb.co/bGtv0z/Product_Two.jpg";
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<body style="background-color:#ddd">
<input type="file" src="">
<div id="oldimg"></div>
<div id="newimg"></div>
</body>
When you choose a file in file input it is only in temporary memory and not on a server. Thus you will be unable to display it.
In order to do to what you want, you can either add a form that uploads the file and after file upload you can display it or use a FileReader. But this question was already answered, so please before asking a question try to find the solution by your own first.
Here is an answer with FileReader
My code is working correct. It's capturing and generating the whole page and prompting download too. But I need this to be saved on my server automatically in "uploads/pdfs/" folder. I actually want to send this through php mail and save it on the server instead of prompting. Please help me.
This is my script:
function makePDF() {
var quotes = document.getElementById('container-fluid');
html2canvas(quotes, {
onrendered: function(canvas) {
//! MAKE YOUR PDF
var pdf = new jsPDF('p', 'pt', 'letter');
for (var i = 0; i <= quotes.clientHeight/980; i++) {
//! This is all just html2canvas stuff
var srcImg = canvas;
var sX = 0;
var sY = 1278*i; // start 980 pixels down for every new page
var sWidth = 990;
var sHeight = 1278;
var dX = 0;
var dY = 0;
var dWidth = 990;
var dHeight = 1278;
window.onePageCanvas = document.createElement("canvas");
onePageCanvas.setAttribute('width', 990);
onePageCanvas.setAttribute('height', 1278);
var ctx = onePageCanvas.getContext('2d');
// details on this usage of this function:
// https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Using_images#Slicing
ctx.drawImage(srcImg,sX,sY,sWidth,sHeight,dX,dY,dWidth,dHeight);
// document.body.appendChild(canvas);
var canvasDataURL = onePageCanvas.toDataURL("image/png", 1.0);
var width = onePageCanvas.width;
var height = onePageCanvas.clientHeight;
//! If we're on anything other than the first page,
// add another page
if (i > 0) {
pdf.addPage(612, 791); //8.5" x 11" in pts (in*72)
}
//! now we declare that we're working on that page
pdf.setPage(i+1);
//! now we add content to that page!
pdf.addImage(canvasDataURL, 'PNG', 0, 0, (width*.62), (height*.62));
}
pdf.save('output.php')
}
});
}
I'm using Raphael.js. Everytime i load the page i get an error that reads:
con is undefined
x = con.x
I looked up con in the Raphael documentation, and this is what i found:
var con = R._getContainer.apply(0, arguments),
container = con && con.container,
x = con.x,
y = con.y,
width = con.width,
height = con.height;
//...
con is clearly defined here. Here is the code I am trying to load:
var paper = new Raphael(ele('canvas_container'), 500, 500);
window.onload = function() {
var circle = paper.circle(100,100,100);
for (i = 0; i < 5; i++) {
var multiplier = i * 5;
paper.circle(250 + (2 * multiplier), 100 + multiplier, 50 - multiplier);
}
}
Has anyone else gotten this error? Is this a bug in the version of Raphael that I have or is there some other problem?
Try moving the paper instantiation inside your window's load function:
window.onload = function() {
var paper = new Raphael(ele('canvas_container'), 500, 500);
var circle = paper.circle(100,100,100);
for (i = 0; i < 5; i++) {
var multiplier = i * 5;
paper.circle(250 + (2 * multiplier), 100 + multiplier, 50 - multiplier);
}
}
If you try to get an element by its id before the DOM is ready, getElementById won't return anything. As you can see here, trying your code on an empty document shows the same result.
Raphael.js expects there to be a hard coded HTML element on the page with the name of the Raphael canvas (ie: "canvas_container"). If the HTML element is created during run time (dynamically in your JavaScript code), it will throw this error.
R._engine.create = function () {
var con = R._getContainer.apply(0, arguments),
container = con && con.container,
x = con.x,
y = con.y,
width = con.width,
height = con.height;
if (!container) {
throw new Error("SVG container not found.");
}
var cnvs = $("svg"),
css = "overflow:hidden;",
isFloating;
x = x || 0;
y = y || 0;
width = width || 512;
height = height || 342;
$(cnvs, {
height: height,
version: 1.1,
width: width,
xmlns: "http://www.w3.org/2000/svg"
});
if (container == 1) {
cnvs.style.cssText = css + "position:absolute;left:" + x + "px;top:" + y + "px";
R._g.doc.body.appendChild(cnvs);
isFloating = 1;
} else {
cnvs.style.cssText = css + "position:relative";
if (container.firstChild) {
container.insertBefore(cnvs, container.firstChild);
} else {
container.appendChild(cnvs);
}
}
container = new R._Paper;
container.width = width;
container.height = height;
container.canvas = cnvs;
container.clear();
container._left = container._top = 0;
isFloating && (container.renderfix = function () {});
container.renderfix();
return container;
};