i try to print a label using qz tray, my technical specs were :
React web apps
Get data from API and then render it as html element, using html2pdf.js convert it as pdf
Convert the pdf to base64 string and feed it to qz tray
I can see the html element as well the pdf output. All is good quality.
Problem is, the label output have a CODE128 barcode and when i try to scan it, it's not readable. I have try to scan the pdf one, and it works fine. Have try to tweak the html, html2pdf.js config and qz, but it looks like the output never in a hi-res output.
my qz tray code :
const qzPrinter = qz.printers.find("Wincode C342 (Copy 3)");
const funcUpdateLoading = this.updateLoading;
qzPrinter().then(function(printer) {
let objPrinter = printer;
var config = qz.configs.create(objPrinter, {
margins: { left: 0.1, bottom: 0.1 }
});
var source = window.document.getElementById("dummyAwb").innerHTML;
var opt = {
margin: [0,0],
filename: "myfile.pdf",
image: { type: "jpeg", quality: 1 },
html2canvas: { dpi: 192, letterRendering: true },
jsPDF: { unit: "mm", format: [365, 305], orientation: "portrait" },
pagebreak: { mode: "avoid-all", before: ".akhirTable" }
};
html2pdf()
.set(opt)
.from(source)
.toPdf()
.output("datauristring")
.then(function(pdfAsString) {
let arrStr = pdfAsString.split(",");
var data = [
{
type: "pdf",
format: "base64",
data: arrStr[1]
}
];
qz.print(config, data).then(function() {
funcUpdateLoading();
});
});
});
Can please someone pointed out, how to adjust the quality in qz tray ? TIA
[...] how to adjust the quality in qz tray?
You have three major factors influencing quality.
html2pdf
qz-tray
barcode
html2pdf
According to html2pdf's page, it uses html2canvas to render its content:
html2pdf converts any webpage or element into a printable PDF entirely client-side using html2canvas and jsPDF.
The disadvantage of this approach is you're grabbing content as a raster graphic removing any vector print data. Worse, it's at web-resolution, which is generally 96 dpi.
Fortunately, html2pdf uses html2canvas for it's render, so a better resolution is possible using a custom { scale: ...} option:
var opt = {
...
html2canvas: { scale: 6 },
...
};
The scale can be calculated by dividing the target DPI by 96. For example, most printers are 600 dpi, so a scale factor of 6 or 7 will be pretty good.
Another factor that should eventually be considered is the choice of jpeg for image compression. png will often yield higher quality results however, may require a shim.
qz-tray
QZ Tray can print PDF, Images, HTML as well as "raw" documents.
The choice to use PDF is interesting here, as QZ Tray can print HTML content directly, but assuming you're certain about using PDF, it's strongly recommended to provide the configuration option { rasterize: false }.
var config = qz.configs.create("Printer Name", { rasterize: "false" }); // use vector rendering
This option will prevent QZ Tray from creating yet another raster graphic when printing. Note, since QZ Tray 2.1, this options has been toggled off by default.
barcode
The title makes the following claim:
barcode low quality
In order for the barcode to render at the same quality as the above, the barcode must also be rendered at a resolution that will scale. This means, the barcode image should be a size that's comparable to the same scale factor (e.g. 6x).
You can avoid having a large barcode by leveraging a vector barcode instead. Most barcode libraries offer various options (e.g. PNG, SVG, etc). Vector will be using SVG or custom HTML (e.g. divs with background color) which will scale properly with the above utilities. As an example, JsBarcode renders an SVG element to the page, which will scale indefinitely without special size multipliers.
Summary
Combined, these above techniques should yield a good quality print. It's worth noting that there are several ways to render HTML to be ready for a printer and that you may be happy using other techniques such as:
Server-side PDF render which will result in vector graphics (e.g. FPDF, mPDF, DOMPDF, wkhtmltopdf, TCPDF)--OR--
Preparing the HTML directly for QZ Tray consumption
Related
I have converted a TIF into a PDF with System.Drawing and PDFsharp-gdi (version 1.50.5147) in my .NET 6 API. I am sending the file as a base64-encoded string to my react frontend that uses wojtekmaj/react-pdf as the PDF viewer. However, the TIF needed to be resized due to being larger than the max allowed size for PDFs (200in x 200in) in the API which I did with the following:
System.Drawing.Image MyImg = System.Drawing.Image.FromStream(inStrm);
XImage img = XImage.FromGdiPlusImage(MyImg);
var p = new PdfPage();
double maxRez = 14400.0;
if (MyImg.Width > maxRez || MyImg.Height > maxRez)
{
double factor = 0.0;
if(MyImg.Width > MyImg.Height)
{
factor = (double)(MyImg.Width) / maxRez;
}
else{
factor = (double)(MyImage.Height) / maxRez;
}
p.Width = MyImg.Width / factor;
p.Height = MyImg.Height / factor;
}
doc.Pages.Add(p);
XGraphics xgr = XGraphics.FromPdfPage(doc.Pages[PageIndex]);
xgr.DrawImage(img, 0, 0, p.Width, p.Height);
Normally sized images (not beyond 200inx200in are converted and displayed fine). Why would PDFs generated after being resized not load correctly? This issue also occurs if I download the file and load it as a PDF in Firefox, which uses PDF.js under the hood I believe.
In Firefox, the error is An error occurred while rendering the page. PDF.js v2.4.152 (build 827eb64b) Message: Stack: putBinaryImageData#resource://pdf..., which I have tried looking up but no solutions have been suggested.
The solution was to resize the image being embedded first, then adding it to the PDF page after it has already been resized. I was previously trying to resize the PDF which would allow the PDF to be loaded but none of the images because their resolution was greater than what is supported in PDF files. Refer to this article for how to resize images.
If you are working with multi-page images, scale each one iteratively with MyImg.GetFrameCount(FrameDimension.Page) and select active frame with MyImg.SelectActiveFrame(FrameDimension.Page, PageNum).
I am using React Native to make an Android App for the billing app and the output paper is 216mmX279mm which is not true PDF size,
I am using expo-print, printToFileAsync and from the expo
I want PDF output exactly A4 size which 210mmX297mm
I looked it up at the expo print documentation
and it took me .#page docs on MDN website
How do I Change Output to A4 size
I checked the Documentation of print andFilePrintOptions
it says
Height of the single page in pixels. Defaults to 792 which is a height of US Letter paper format with 72 PPI.
So How Can I change default to A4 and increase DPI?
Found It.
const printToFile = async () => {
const { uri } = await Print.printToFileAsync({
html, height:842, width:595
});
console.log('File has been saved to:', uri);
await shareAsync(uri, { UTI: '.pdf', mimeType: 'application/pdf' });
So, By default, height:792, width:612 of US letter paper at 72 PPI as I ask in the question,
html is a string and also takes height and width as number
as shown code block,
if you wanna change PPI change pixel size
for example
A4 72PPI = H842, W595
A4 150PPI = H1754,W1240
I think it only takes "px"
I am currently using webcam (not native camera) on a web page to take a photo on users' mobile phone. Like this:
var video: HTMLVideoElement;
...
var context = canvas.getContext('2d');
context.drawImage(video, 0, 0, width, height);
var jpegData = canvas.toDataURL('image/jpeg', compression);
In such a way, I can now successfully generate a JPEG image data from web camera, and display it on the web page.
However, I found that the EXIF data is missing.
according to this:
Canvas.drawImage() will ignore all EXIF metadata in images,
including the Orientation. This behavior is especially troublesome
on iOS devices. You should detect the Orientation yourself and use
rotate() to make it right.
I would love the JPEG image contain the EXIF GPS data. Is there a simple way to include camera EXIF data during the process?
Thanks!
Tested on Pixel 3 - it works. Please note - sometimes it does not work with some desktop web-cameras. you will need exif-js to get the EXIF object from example.
const stream = await navigator.mediaDevices.getUserMedia({ video : true });
const track = stream.getVideoTracks()[0];
let imageCapture = new ImageCapture(track);
imageCapture.takePhoto().then((blob) => {
const newFile = new File([blob], "MyJPEG.jpg", { type: "image/jpeg" });
EXIF.getData(newFile, function () {
const make = EXIF.getAllTags(newFile);
console.log("All data", make);
});
});
unfortunately there's no way to extract exif from canvas.
Although, if you have access to jpeg, you can extract exif from that. For that I'd recommend exifr instead of widely popular exif-js because exif-js has been unmaintained for two years and still has breaking bugs in it (n is undefined).
With exifr you can either parse everything
exifr.parse('./myimage.jpg').then(output => {
console.log('Camera:', output.Make, output.Model))
})
or just a few tags
let output = await exifr.parse(file, ['ISO', 'Orientation', 'LensModel'])
First of, according to what I found so far, there is no way to include exif data during canvas context drawing.
Second, there is a way to work around, which is to extract the exif data from the original JPEG file, then after canvas context drawing, put the extracted exif data back into the newly drawn JPEG file.
It's messy and a little hacky, but for now this is the work around.
Thanks!
I'm using jsPDF (https://parall.ax/products/jspdf, https://github.com/MrRio/jsPDF) to produce dynamic PDFs in a web application.
It works well, but I'd like to figure out whether it's possible to use Google web fonts in the resulting PDF.
I've found a variety of links that are related to this question (including other questions on SO), but most are out of date, and nothing looks definitive, so I'm hoping someone clarify whether/how this would work.
Here's what I've tried so far, with no success:
First, load the font, and cache it as a base64-encoded string:
var arimoBase64;
var request = new XMLHttpRequest()
request.open('GET', './fonts/Arimo-Regular.ttf');
request.responseType = 'blob';
request.onload = function() {
var reader = new FileReader();
reader.onloadend = function() {
arimoBase64 = this.result.split(',')[1];
}
reader.readAsDataURL(this.response);
};
request.send()
Next, create the pdf doc:
doc = new jsPDF({
orientation: "landscape",
unit: "pt",
format: "letter"
});
doc.addFileToVFS("Arimo-Regular.ttf", arimoBase64);
doc.addFont("Arimo-Regular.ttf", "Arimo Regular", "normal");
doc.setFont("Arimo Regular", "normal");
doc.text("Hello, World!", 100, 100);
doc.save("customFontTest");
When the PDF is saved - if I view it in my browser - I can see the custom font. However - if I view it using Adobe Reader or the Mac Preview app - the fonts are not visible.
I assume that's because the font is rendered in the browser using the browser's font cache, but the font is not actually embedded in the PDF, which is why it's not visible using Adobe Reader.
So - is there a way to accomplish what I'm trying to do?
OK - I finally figured it out, and have gotten it to work. In case this is useful for anyone else - here is the solution I'm using...
First - you need two libraries:
jsPDF: https://github.com/MrRio/jsPDF
jsPDF-CustomFonts-support: https://github.com/sphilee/jsPDF-CustomFonts-support
Next - the second library requires that you provide it with at least one custom font in a file named default_vfs.js.
That file should look like this:
(function (jsPDFAPI) {
"use strict";
jsPDFAPI.addFileToVFS("[Your font's name]","[Base64-encoded string of your font]");
})(jsPDF.API);
I'm using two custom fonts - Arimo-Regular.ttf and Arimo-Bold.ttf - both from Google Fonts. So, my default_vfs.js file looks like this:
(function (jsPDFAPI) {
"use strict";
jsPDFAPI.addFileToVFS("Arimo-Regular.ttf","[Base64-encoded string of your font]");
jsPDFAPI.addFileToVFS("Arimo-Bold.ttf","[Base64-encoded string of your font]");
})(jsPDF.API);
There's a bunch of ways to get the Base64-encoded string for your font, but I used this: https://www.giftofspeed.com/base64-encoder/.
It lets you upload a font .ttf file, and it'll give you the Base64 string that you can paste into default_vfs.js.
You can see what the actual file looks like, with my fonts, here: https://cdn.rawgit.com/stuehler/jsPDF-CustomFonts-support/master/dist/default_vfs.js
So, once your fonts are stored in that file, your HTML should look like this:
<script src="js/jspdf.min.js"></script>
<script src="js/jspdf.customfonts.min.js"></script>
<script src="js/default_vfs.js"></script>
Finally, your JavaScript code looks something like this:
const doc = new jsPDF({
unit: 'pt'
});
doc.addFont("Arimo-Regular.ttf", "Arimo", "normal");
doc.addFont("Arimo-Bold.ttf", "Arimo", "bold");
doc.setFont("Arimo");
doc.setFontType("normal");
doc.setFontSize(28);
doc.text("Hello, World!", 100, 100);
doc.setFontType("bold");
doc.text("Hello, BOLD World!", 100, 150);
doc.save("customFonts.pdf");
This is probably obvious to most, but in that addFont() method, the three parameters are:
The font's name you used in the addFileToVFS() function in the default_vfs.js file
The font's name you use in the setFont() function in your JavaScript
The font's style you use in the setFontType() function in your JavaScript
You can see this working here: https://codepen.io/stuehler/pen/pZMdKo
Hope this works as well for you as it did for me.
I recently ran into this same issue, but it looks like the jsPDF-CustomFonts-support repo was rolled into MrRio's jsPDF repository, so you no longer need it to get this working.
I happen to be using it in a React App and did the following:
npm install jspdf
Create a new file fonts/index.js (Note: You can download the Google Font as a .ttf and turn it into the Base64 encoded string using the tool in mattstuehler's answer)
export const PlexFont = "[BASE64 Encoded String here]";
Import that file where you need it:
import jsPDF from 'jspdf';
import { PlexFont } from '../fonts';
// Other Reacty things...
exportPDF = () => {
const doc = new jsPDF();
doc.addFileToVFS('IBMPlexSans-Bold.ttf', PlexBold);
doc.addFont('IBMPlexSans-Bold.ttf', 'PlexBold', 'normal')
doc.setFont('PlexBold');
doc.text("Some Text with Google Fonts", 0, 0);
// Save PDF...
}
// ...
Just wanted to add an updated answer - for version 1.5.3:
Convert the font file to base64 = https://www.giftofspeed.com/base64-encoder/
const yanone = "AAWW...DSES"; // base64 string
doc.addFileToVFS('YanoneKaffeesatz-Medium.ttf', yanone);
doc.addFont('YanoneKaffeesatz-Medium.ttf', 'YanoneKaffeesatz', 'normal');
doc.setFont('YanoneKaffeesatz');
I’m trying to convert XML data into PDF files from a web page and I was hoping I could do this entirely within JavaScript. I need to be able to draw text, images and simple shapes. I would love to be able to do this entirely in the browser.
I've just written a library called jsPDF which generates PDFs using Javascript alone. It's still very young, and I'll be adding features and bug fixes soon. Also got a few ideas for workarounds in browsers that do not support Data URIs. It's licensed under a liberal MIT license.
I came across this question before I started writing it and thought I'd come back and let you know :)
Generate PDFs in Javascript
Example create a "Hello World" PDF file.
// Default export is a4 paper, portrait, using milimeters for units
var doc = new jsPDF()
doc.text('Hello world!', 10, 10)
doc.save('a4.pdf')
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.5/jspdf.debug.js"></script>
Another javascript library worth mentioning is pdfmake.
pdfmake playground
pdfmake on github
The browser support does not appear to be as strong as jsPDF, nor does there seem to be an option for shapes, but the options for formatting text are more advanced then the options currently available in jsPDF.
I maintain PDFKit, which also powers pdfmake (already mentioned here). It works in both Node and the browser, and supports a bunch of stuff that other libraries do not:
Embedding subsetted fonts, with support for unicode.
Lots of advanced text layout stuff (columns, page breaking, full unicode line breaking, basic rich text, etc.).
Working on even more font stuff for advanced typography (OpenType/AAT ligatures, contextual substitution, etc.). Coming soon: see the fontkit branch if you're interested.
More graphics stuff: gradients, etc.
Built with modern tools like browserify and streams. Usable both in the browser and node.
Check out http://pdfkit.org/ for a full tutorial to see for yourself what PDFKit can do. And for an example of what kinds of documents can be produced, check out the docs as a PDF generated from some Markdown files using PDFKit itself: http://pdfkit.org/docs/guide.pdf.
You can also try it out interactively in the browser here: http://pdfkit.org/demo/browser.html.
Another interesting project is texlive.js.
It allows you to compile (La)TeX to PDF in the browser.
For react fans there is another great resource for PDF generation: React-PDF
It is great for creating PDF files in React and even let the user download them from the client side itself with no server required!
this is a small example snippet of React-PDF to create a 2 section PDF file
import React from 'react';
import { Page, Text, View, Document, StyleSheet } from '#react-pdf/renderer';
// Create styles
const styles = StyleSheet.create({
page: {
flexDirection: 'row',
backgroundColor: '#E4E4E4'
},
section: {
margin: 10,
padding: 10,
flexGrow: 1
}
});
// Create Document Component
const MyDocument = () => (
<Document>
<Page size="A4" style={styles.page}>
<View style={styles.section}>
<Text>Section #1</Text>
</View>
<View style={styles.section}>
<Text>Section #2</Text>
</View>
</Page>
</Document>
);
This will produce a PDF document with a single page. Inside, two different blocks, each of them rendering a different text. These are not the only valid primitives you can use. you can refer to the Components or Examples sections for more information.
It is worth mentioning PDF-LIB which is an awesome library:
Supports pure JavaScript.
Can edit existing PDF templates even with pure JavaScript. (Most impotently. Many JavaScript libraries can't do it)
It is generating a PDF with select-able/copy-able/highlight-able text not an image file inside an PDF like many other libraries generate.
More easy to use. (I love it)
If you are interested in using it with pure JavaScript this may
help.
If you are interested to do the same with the most popular JavaScript
library as of now JSPDF this may help. (Simply JSPdf can't do most time saving thing we want, editing an existing template.)
See how pretty the code is
<script type="text/javascript">
async function downloadPdf() {
const url = './print-templates/pquot-template.pdf';
const existingPdfBytes = await fetch(url).then(res => res.arrayBuffer());
// Getting the document
const pdfDoc = await PDFLib.PDFDocument.load(existingPdfBytes);
// Getting the first page
const pages = pdfDoc.getPages();
const firstPage = pages[0];
// Customer name
firstPage.drawText('Customer name is here with more text (GAR004) quick brown customerm jumps over lazy dog.', {
x: 10.5*9,
y: 76.6*9,
size: 10,
maxWidth: 28*9, // Wrap text with one line. WOW :O
lineHeight: 1.5*9
});
// Currency short code
firstPage.drawText('LKR', {
x: 10.5*9,
y: 73.5*9,
size: 10
});
var itemName = 'Here is the item name with some really really long text and quick brown fox jumps over lazy dog. long text and quick brown fox jumps over lazy dog:)';
// Item name
firstPage.drawText(itemName, {
x: 5*9,
y: 67*9,
size: 10,
maxWidth: 31*9,
lineHeight: 2*9
});
const pdfDataUri = await pdfDoc.saveAsBase64({ dataUri: true });
document.getElementById('pdf').src = pdfDataUri;
}
</script>
UPDATE: Free service no longer available. But there is a reasonably priced service you can use if you need something in a crunch and it's should be reliable.
https://pdfmyurl.com/plans
You can use this free service by adding a link which creates pdf from any url (e.g. http://www.phys.org):
http://freehtmltopdf.com/?convert=http%3A%2F%2Fwww.phys.org&size=US_Letter&orientation=portrait&framesize=800&language=en
Even if you could generate the PDF in-memory in JavaScript, you would still have the issue of how to transfer that data to the user. It's hard for JavaScript to just push a file at the user.
To get the file to the user, you would want to do a server submit in order to get the browser to bring up the save dialog.
With that said, it really isn't too hard to generate PDFs. Just read the spec.