How can I configure the width and height of html for jspdf? - html

I am wanting to generate a pdf based on an html file, using the jsPDF library. I want to set the width and height to render the pdf in the correct way.
At this moment a very large html is generated and thus not being able to see the PDF properly
I was researching the documentation of jsPDF, but I can not find exactly what I'm looking for.
var content = $('.template-view');
var id = $('#view input[name=tipo]').val();
var name = $(this).attr('data-filename');
if(id === "4" || id === "3"){
var doc = new jsPDF('l', 'px', 'a4')
}else{
var doc = new jsPDF('p', 'px', 'a4')
}
var width = doc.internal.pageSize.getWidth();
var height = doc.internal.pageSize.getHeight()
doc.html(content[0], {
width: width,
height: height,
callback: function(doc){
doc.save();
}
});

Related

jspdf saves document before images load

I am trying to save multiple large base64 images to a pdf file
exportPdfv3p3(imgPath:string, x:number, y:number, width:number, height:number)
{
var pdfFile = this.pdfItem;
var localNumImagesLoaded = this.numImagesLoaded + 1;
var totalNumImages = this.numImages;
var img = new Image;
img.src = imgPath;
var pdfWidth = pdfFile.internal.pageSize.getWidth();
img.onload = function()
{
pdfFile.addImage(img, 'PNG', pdfWidth - width - 5, y, width, height);
console.log("localNumImagesLoaded",localNumImagesLoaded);
if (localNumImagesLoaded > totalNumImages)
alert("numImagesLoaded desync (too many images)");
else if (localNumImagesLoaded < totalNumImages){}
else // (localNumImagesLoaded == numImages)
{
// Total page number plugin only available in jspdf v1.0+
if (typeof pdfFile.putTotalPages === 'function')
{
pdfFile.putTotalPages(2);
}
// pdfFile.save("test.pdf");
pdfFile.output('datauri');
}
};
++this.numImagesLoaded;
console.log("this.numImagesLoaded", this.numImagesLoaded);
}
however, img.onLoad seems to be async, causing pdfFile.output to run prematurely and outputting blank spaces into the pdf.
how can i know when the images are actually loaded and added to pdf, so that i can save the pdf file at the correct time?

Google apps script getAs('application/pdf') layout

I am generating a PDF file from a spreadsheet using an app script I found here.
This one uses the good old
Method getAs('application/pdf') and works great.
The problem is that the PDF document generated in this way has unwanted asymmetric margins (larger on the right, narrow on the left). I just wanted the page to be centered. The weird thing is that when I print from the Google menu File -> Print (or Ctrl + P) the document appears centered correctly.
My code looks like this:
function CreaPDF() {
//The function prints an invoice to PDF. First it copies spreadsheet to a new document.
//Deletes all sheet except the one to print. Saves it to PDF.
//It overwrites any existing doc with same name.
var sourceSpreadsheet = SpreadsheetApp.getActive();
var sheetName = "Factura";
var folderID = getParentFolder(); // Folder id to save in a folder.
var sourceSheet = sourceSpreadsheet.getSheetByName(sheetName);
var folder = DriveApp.getFolderById(folderID);
var numf = sourceSpreadsheet.getRangeByName("NumeroFactura").getValue();
var anof = numf.split("/",2); // Seeks number and year -> filename
var pdfName = anof[1] +"_Factura_" + anof[0]+ "_Dra_Salazar"; // Nombre del documento;
//Copy whole spreadsheet 2 temporary sheet
var destSpreadsheet = SpreadsheetApp.open(DriveApp.getFileById(sourceSpreadsheet.getId()).makeCopy("tmp_convert_to_pdf", folder))
//delete redundant sheets
var sheets = destSpreadsheet.getSheets();
for (i = 0; i < sheets.length; i++) {
if (sheets[i].getSheetName() != sheetName){
destSpreadsheet.deleteSheet(sheets[i]);
}
}
//Deletes pdf if already exists
var files = DriveApp.getFilesByName(pdfName);
while (files.hasNext()) {
files.next().setTrashed(true);
}
var destSheet = destSpreadsheet.getSheets()[0];
//repace cell values with text (to avoid broken references)
var sourceRange = sourceSheet.getRange(1, 1,sourceSheet.getMaxRows(),sourceSheet.getMaxColumns());
var sourcevalues = sourceRange.getDisplayValues();
var destRange = destSheet.getRange(1, 1, destSheet.getMaxRows(), destSheet.getMaxColumns());
destRange.setValues(sourcevalues);
SpreadsheetApp.getActiveSpreadsheet().toast('Creando PDF');
//save to pdf
var theBlob = destSpreadsheet.getBlob().getAs('application/pdf').setName(pdfName);
var newFile = folder.createFile(theBlob);
//Delete the temporary sheet
DriveApp.getFileById(destSpreadsheet.getId()).setTrashed(true);
return true;
}
My settings when I print are:
Paper size: "A4"
Scale: "Normal" (I also tried: "fit to width" and
"fit on page")
Orientation: "Portrait"
Margins: "Normal"
As seen in the Google Help Forums it seems like an old issue with the way google prints. In summary, it seems that print settings are not saved and there is no way to pass any parameter to the getAs('application/pdf') method either. So i assume that the method (and menu print options) use default parameters that can not be modified. Any solution for this? The "Print or change page setup" help page does not help too much.
Thank you very much
Try this solution based on https://ctrlq.org/code/19869-email-google-spreadsheets-pdf
Using export url parameters you can set needed options for result pdf. Also you can set specific id of sheet to export, so you don't need to make duplicate of your whole spreadsheet anymore.
function CreaPDF() {
//The function prints an invoice to PDF. First it copies spreadsheet to a new document.
//Deletes all sheet except the one to print. Saves it to PDF.
//It overwrites any existing doc with same name.
var sourceSpreadsheet = SpreadsheetApp.getActive();
var sheetName = "Factura";
var folderID = getParentFolder(); // Folder id to save in a folder.
var sourceSheet = sourceSpreadsheet.getSheetByName(sheetName);
var folder = DriveApp.getFolderById(folderID);
var numf = sourceSpreadsheet.getRangeByName("NumeroFactura").getValue();
var anof = numf.split("/",2); // Seeks number and year -> filename
var pdfName = anof[1] +"_Factura_" + anof[0]+ "_Dra_Salazar"; // Nombre del documento;
SpreadsheetApp.getActiveSpreadsheet().toast('Creando PDF');
// export url
var url = 'https://docs.google.com/spreadsheets/d/'+sourceSpreadsheet.getId()+'/export?exportFormat=pdf&format=pdf' // export as pdf / csv / xls / xlsx
+ '&size=A4' // paper size legal / letter / A4
+ '&portrait=true' // orientation, false for landscape
+ '&fitw=false' // fit to page width, false for actual size
+ '&sheetnames=false&printtitle=false' // hide optional headers and footers
+ '&pagenumbers=false&gridlines=false' // hide page numbers and gridlines
+ '&fzr=false' // do not repeat row headers (frozen rows) on each page
+ '&gid='+sourceSheet.getSheetId(); // the sheet's Id
var token = ScriptApp.getOAuthToken();
// request export url
var response = UrlFetchApp.fetch(url, {
headers: {
'Authorization': 'Bearer ' + token
}
});
var theBlob = response.getBlob().setName(pdfName+'.pdf');
// delete pdf if already exists
var files = folder.getFilesByName(pdfName);
while (files.hasNext())
{
files.next().setTrashed(true);
}
// create pdf
var newFile = folder.createFile(theBlob);
return true;
}
Before solution provided by Kos I had finally managed to adjust my sheet to the size of the paper by playing with the size of the cells, making it appear "centered". But anyway many thanks to Kos. Your answer definitely solves the problem. Great!

Google script change sheet cell to fit image

Below sample script will get youtube thumbnail and show it in sheet cells. How can we make sure the cell width/height fit the image width/height? Current script will shrink the image to cell so it's too small.
I try to call autoResizeColumn API but it seems doesn't work for image.
function searchYoutubeByKeyword() {
var results = YouTube.Search.list('id,snippet', {
q:'Cpp',
order:'date',
maxResults: 20
});
var lr = 1;
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheetByName("Sheet1");
for (var i = 0; i < results.items.length; i++) {
var item = results.items[i];
Logger.log('[%s] Title: %s', item.id.videoId,item.snippet.publishedAt);
var url = 'http://www.youtube.com/watch?v='+item.id.videoId;
var desc = item.id.videoId;
var link = '=HYPERLINK'+'("' + url+'","'+ desc +'")';
sheet1.getRange(lr, 1).setValue(link);
sheet1.getRange(lr, 2).setValue(item.snippet.publishedAt.substring(0,10));
sheet1.getRange(lr, 3).setValue(item.snippet.title);
var thumbnail = item.snippet.thumbnails["medium"].url;
sheet1.getRange(lr, 4).setValue('=image("'+thumbnail+'")');
lr++;
}
sheet1.getRange(1,1,sheet1.getLastRow(),3).setNumberFormat('#STRING#');
sheet1.autoResizeColumn(4);
}

Printing with only pdf.js (without the viewer)

There are already two questions about this, but the specific question remains unanswered.
I have a multipage pdf document. I have successfully used pdf.js core to write a page to a canvas. Soon I'm sure I'll have prev / next paging functions so I can see each page. See my existing code at bottom. The reason I am not using the viewer is because my boss doesn't like it. He wants a totally different interface that is extremely minimal and simple, and I have successfully built that minus the full print, ala:
Please note that there is no url to a pdf document. I get the data from a api call that returns base64 data. My code loads the data from an array into the pdf.
My current print function seems like a hack, and I know it isn't how the pdf.js viewer does it. I want to print the pdf as the pdf.js viewer does; meaning, true to form. I'm not sure if converting each page to an image gets it done, but I remain open to suggestions.
The problems are: extra margin not in the original document, and headers / footers. Not to mention pdf documents actually can contain different page layouts and sizes for each page and throwing an image tag into a new window completely ignores that.
I did check the pdf.js examples on Github. None of them are print and they say that using the pdf.js without the viewer is not supported and we are on our own if we do that (is that right?). Anyway, nothing on Google that I could find.
var pdfDocument;
var canvas;
// load from base64 data
loadPdfDocument(file.Content);
function print() {
var doc = document.getElementById('document');
var html = doc.innerHTML;
if (canvas)
html = "<img src='" + canvas.toDataURL() + "'";
var win = window.open('', '', '');
win.document.write(html);
win.document.close();
win.focus();
win.print();
win.close();
};
function loadPdfDocument(base64Data) {
PDFJS.disableWorker = true;
var pdfData = base64ToUint8Array(base64Data);
PDFJS.getDocument(pdfData).then(function(pdf) {
canvas = document.getElementById('pdfPage');
pdfDocument = pdf;
loadPdfPage(1);
});
}
function base64ToUint8Array(base64) {
var raw = atob(base64); // convert base 64 string to raw string
var uint8Array = new Uint8Array(raw.length);
for (var i = 0; i < raw.length; i++) {
uint8Array[i] = raw.charCodeAt(i);
}
return uint8Array;
}
function loadPdfPage(pageIndex) {
pdfDocument.getPage(pageIndex).then(function(page) {
var scale = 1;
var viewport = page.getViewport(scale);
var context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
page.render({
canvasContext: context,
viewport: viewport
});
});
}
<div id="document">
<canvas id="pdfPage" />
</div>

Resize image and then upload it to server using bootstrap-fileupload plugin

I am trying to upload the converted version of some image files on client-side with bootstrap-fileupload plugin for a custom view. In my search, I came up with this question, and pretty much figured out how to upload a file using a custom tag with ASP.NET.
Now what I want to do is to resize that image file before the upload (as some image files may be > 15MP - which equals to > 5MB per file) to the server. Everyone is talking about Plupload, but that one has its own design interface and created to allow multiple files by default. What I want to use is to resize a single file and upload it to the server with a single click of a button.
I am avoiding Flash, Silverlight and anything like these ones which requires to install something on the computer in order to use it. I prefer HTML5 based solutions as my users aren't using any ancient browsers like IE8, IE9 etc.
I am working with ASP.NET 4.5, using all the latest versions of plugins and scripts. As it's a new project, I am open to add, modify anything neccessary in order to achieve my goal.
Thanks for reading my question, and contributing.
Cheers!
EDIT: Let's add some code here.
HTML
<input type="file" class="default" id="ctrl_Upload" runat="server" accept="image/*" onchange="resizeImage(this)" />
<br />
<asp:Button runat="server" ID="btn_Upload" Text="Upload" OnClick="btn_Upload_Click" />
JS
function resizeImage(input) {
var filesToUpload = input.files;
var file = filesToUpload[0];
var img = document.createElement("img");
var reader = new FileReader();
reader.onload = function (e) { img.src = e.target.result }
reader.readAsDataURL(file);
// reader returns null (actually, "e" is returning null here)
var canvas = document.createElement('canvas');
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
var MAX_WIDTH = 80;
var MAX_HEIGHT = 60;
var width = img.width;
var height = img.height;
if (width > height) {
if (width > MAX_WIDTH) {
height *= MAX_WIDTH / width;
width = MAX_WIDTH;
}
} else {
if (height > MAX_HEIGHT) {
width *= MAX_HEIGHT / height;
height = MAX_HEIGHT;
}
}
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, width, height);
var dataurl = canvas.toDataURL("image/png");
img.src = dataurl;
}
CS
protected void btn_Upload_Click(object sender, EventArgs e)
{
if (ctrl_Upload.PostedFile != null)
{
// File was sent
var postedFile = ctrl_Upload.PostedFile;
int dataLength = postedFile.ContentLength;
byte[] myData = new byte[dataLength];
postedFile.InputStream.Read(myData, 0, dataLength);
postedFile.SaveAs(Server.MapPath("/Uploads/image01.jpg"));
}
else
{
// No file was sent
}
}
That's pretty much all I have in my hands. Couldn't figure out how to create a canvas properly using file input's selected file information. Then I need to recreate the image, and send it back to file input with this
var dataurl = canvas.toDataURL("image/png");
I guess...
Any ideas how to fix this?

Resources