Following gm convert command converts first page of source.pdf to output.tif
convert source.pdf[0] output.tif
I wonder how to do it with Magick.NET library? Following code does not work for me.
using (MagickImage image = new MagickImage("source.pdf"))
{
image.Write("output.tif");
}
ImageMagick cannot handle PostScript and PDF files itself and by its own,
for this it uses a third party software called Ghostscript.
So, you need to install the latest version of GhostScript before you can convert a pdf using Magick.NET.
After installing GhostScript use following code to extract first page to TIF-file.
using (MagickImageCollection image = new MagickImageCollection())
{
MagickReadSettings settings = new MagickReadSettings();
settings.Density = new Density(300, 300); // Settings the density to 300 dpi will create an image with a better quality
settings.FrameIndex = 0; // First page
settings.FrameCount = 1; // Number of pages
image.Read(#"source.pdf", settings);
image.Write(#"output.tif");
}
You can adjust quality of resulting TIF by changing settings.Density param (300 dpi is for high quality offset/digital printing, 72 dpi is ok for monitor screens only).
I am not a ImageMagick Magick.NET expert, but have you tried simply add [0] to your command as
using (MagickImage image = new MagickImage("source.pdf[0]"))
{
image.Write("output.tif");
}
ImageMagick does require Ghostscript to be installed to read PDF files As was mentioned previously.
Related
I have a program in .NETCoreApp 3.1 and I use the SixLabors.ImageSharp version 2.1.3 to handle the processing of images in our CDN for all our sites.
The application run in docker container linux and for testing locally, I use WSL2 with ubuntu.
We are planning to review all our image and provide better format with a compressed version et a webp version.
For now the objective was to use TunyPNG (https://tinypng.com/developers/reference/dotnet) to provide a compressed and webp version from the original image and use Imagesharp to resize these versions in the different dimensions that exists.
The first tests were successfull but I found a problem. I had an original transparent PNG (587x444) with filesize of 244k. The compressed version is 70k and webp converted is 16k using TinyPNG API.
The process after is to resize these versions and then i have a problem. The webp version resized to 581x439 using Imagesharp library has a filesize of 266k.
Here is the part of the code :
...
using var image = Image.Load(absoluteFilePath, out var format);
image.Mutate(x => x.Resize(width, height));
using var fileStream = new FileStream(convertedAbsolutePath, FileMode.Create);
await image.SaveAsync(fileStream, format);
...
I tried to force webp encoder and decoder but no amelioration.
With an image without transparent background, I don't have this problem.
If I use TinyPNG to do the resize, i don't have this problem and the filesize is 14k.
Is there some configurations to change or is it a problem with the Imagesharp library ?
You can compress the image more when you use a IImageEncoder in the SaveAsyncinstead of the format. For Webp the encoder would be WebpEncoder. That has a few properties that you can change for example the NearLosslessQuality or Quality, which you can decrease to get a smaller file size. If you want to use the same method to process multiple formats you can save them as IImageEncoder and put that in SaveAsync. An example how you could do that is the following:
using var image = Image.Load(absoluteFilePath, out var format);
image.Mutate(x => x.Resize(width, height));
var encoder = GetImageEncoder(format);
using var fileStream = new FileStream(convertedAbsolutePath, FileMode.Create);
await image.SaveAsync(fileStream, encoder);
Where GetImageEncoder(IImageFormat format) is defined the following:
static IImageEncoder GetImageEncoder(IImageFormat format) {
if(format is WebpFormat) {
return new WebpEncoder() {
Quality = 20,
NearLosslessQuality = 50,
};
} else if(format is PngFormat) {
return new PngEncoder();
}
throw new NotSupportedException();
}
The Quality and NearLosslessQuality have to be in the range between 0 and 100, where a 100 is highest Quality and 0 is the worst.
GDI+ and System.Drawing have no support for WebP images. To handle them in my C# Windows desktop app, I'm using Magick.NET to convert them to Gif images, which are supported. This works well, unless the WebP image is animated. The code I'm using to test animated image conversions is as follows:
public void TestConvertImageType() {
using (var animatedWebP = new MagickImage("animated.webp")) {
animatedWebP.Write("animated-generated.gif", MagickFormat.Gif);
}
using (var animatedGif = new MagickImage("animated.gif")) {
animatedGif.Write("animated-generated.webp", MagickFormat.WebP);
}
}
Both animated.webp and animated.gif will play if dragged into a chrome browser. Neither generated image will play, however. In chrome, they simply display the first frame of the animated source image.
Using the command line version of ImageMagick, I can convert animated.webp and animated.gif to playable images with the following script:
magick animated.webp animated-generated.gif
magick animated.gif animated-generated.webp
So I know that conversion of animated images is supported by ImageMagick.
My installed version of Magick.NET is Magick.NET-Q8-AnyCPU version 8.5.0
My installed version of ImageMagick is ImageMagick-7.1.0-Q8
My C# app is using .NET Framework 4.8
Can anyone tell me what my C# app needs to do to generate playable animated gif's from animated webp's?
A MagickImage is only a single image. When an animated image is read this will be the first frame. If you want to read all the frames you will need to read the files with a MagickImageCollection instead.
public void TestConvertImageType() {
using (var animatedWebP = new MagickImageColection("animated.webp")) {
animatedWebP.Write("animated-generated.gif", MagickFormat.Gif);
}
using (var animatedGif = new MagickImageColection("animated.gif")) {
animatedGif.Write("animated-generated.webp", MagickFormat.WebP);
}
}
And you don't need to also install ImageMagick on your machine. The ImageMagick library comes with the Magick.NET library.
I use the WordToPdfConverter from evo to convert a Word document to a PDF. The Word document, which is in RTF format, contains images such as a QR code.
Unfortunately, the image quality in the resulting PDF is very poor (hence the QR code won't be readable). Even if I disable image compression or set it to the lowest level (=> best quality), the resulting image has a very poor quality.
Is there any other way to control the image quality? Or is there a way to tell evo's WordToPdfConverter not to use JPG as the resulting image format but to stuck with the source format (e.g. PNG)?
var pdfConverter = new WordToPdfConverter();
// Set Pdf image options
pdfConverter.PdfDocumentOptions.JpegCompressionEnabled = false;
pdfConverter.PdfDocumentOptions.JpegCompressionLevel = 0;
var filename = #"C:\temp\evo\TestWordDoc.rtf";
pdfConverter.ConvertWordFileToFile(filename, Path.Combine(Path.GetDirectoryName(filename), $"{Path.GetFileNameWithoutExtension(filename)}_{DateTime.Now:yyyyMMddHHmmss}.pdf"));
Since RTF is a text format, you should convert it to PDF without having to do any image compression as that will take longer to process and will result in a larger output file + you might have issues with the image quality from embedded images.
I created a sample RTF file (test.rtf) that contains a QR code as you described:
I then took the RTF and ran it through the Document Converter from the Leadtools.Document.sdk Nuget. Just as a disclaimer: I am associated with this library.
This document converter preserves the text and parses the images as-is from the source document, then outputs it to PDF.
You can download the output PDF from here: test.pdf
Here is some sample code:
using (var documentConverter = new DocumentConverter())
{
var filename = #"C:\temp\evo\TestWordDoc.rtf";
var document = DocumentFactory.LoadFromStream(filename, new LoadDocumentOptions());
var jobData = DocumentConverterJobs.CreateJobData(filename, Path.Combine(Path.GetDirectoryName(filename), $"{Path.GetFileNameWithoutExtension(filename)}_{DateTime.Now:yyyyMMddHHmmss}.pdf"), DocumentFormat.Pdf);
var job = documentConverter.Jobs.CreateJob(jobData);
documentConverter.Jobs.RunJob(job);
}
I am failing to see why people have issues with QR codes such as this one which is just a template (I could not download any of the older samples above for comparison.)
It is a PNG demo template file designed to be scanned from up to 4 feet away (e.g. a poster) but it could be for production, much smaller i.e. lower scale for page scanning.
I drop the RTF on the WordPad print to pdf shortcut and get the pdf shown in the viewer almost instantly.
There is some natural degradation using RTF PNG and an aliased viewer, but the key is maintaining natural scales. Every thing you need is native as supplied with windows.
MSPaint, WordPad, CMD printing I could have sent preview to the PDFium viewer in Edge.
I have a lot of very large PDF files, which contains huge images (scans).
The goal is to open PDF , read all images , change dpi, resolution and compress it.
How to managed it with Itex7?
And generally ho to iterate through all images in PDF?
using (iText.Kernel.Pdf.PdfReader pdfReader = new iText.Kernel.Pdf.PdfReader(inputPdfFile))
{
using (iText.Kernel.Pdf.PdfDocument pdfDocument = new iText.Kernel.Pdf.PdfDocument(pdfReader))
{
//??
//foreach (var image in pdfDocumentImagesList)
//{
// //image.SetNewDPI()
//}
}
}
How to go through all the PDF's images?
https://github.com/itext/i7js-book/blob/develop/src/test/java/com/itextpdf/samples/book/part4/chapter15/Listing_15_30_ExtractImages.java
https://github.com/itext/i7js-book/blob/develop/src/test/java/com/itextpdf/samples/book/part4/chapter15/Listing_15_31_MyImageRenderListener.java
How to change the image's dpi and resolution?
That's not a part of iText functionality, since iText is a PDF- rather than an image-proccessing library. I advise you to process the extracted images with some other tools and then either put them into a new document or replace the image in the PDF. The latter is not very easy. Probably the next SO answer would shed some light on it: http://stackoverflow.com/questions/26580912/pdf-convert-to-black-and-white-pngs
(its code, but in iText7: https://github.com/itext/i7js-examples/blob/develop/src/test/java/com/itextpdf/samples/sandbox/images/ReplaceImage.java)
How to compress an image?
https://github.com/itext/i7js-book/blob/develop/src/test/java/com/itextpdf/samples/book/part3/chapter10/Listing_10_12_CompressImage.java
Hope that would be useful!
Right now I am using ghostscript in Unity to convert pdfs to jpgs and view them in my project.
Currently it flows like so:
-Pdfs are converted into multiple jpegs (one for each page)
-The converted jpegs are written to disk
-They are then read in by bytes into a 2D texture
-And this 2D texture is assigned to a GameObjects RawImage component
This works perfectly in Unity, but... (now comes the hiccup) my project is intended to run on the Microsoft Hololens.
The Hololens runs on the Windows 10 API, but in a limited capacity.
Where the issue arises is when I try to convert pdfs and view them on the Hololens. Quite simply, the Hololens cannot create or delete files outside of its known folders (Pictures, Documents, etc).
My imagined solution to this problem is to instead of write the converted jpeg files to disk, write them to memory and view them from there.
In talking with GhostScript devs, I was told GhostScript.NET does what I am looking to do - convert pdfs and view them from memory (It does this with the Rasterizer/Viewer classes, I believe, but again I don't understand it quite well).
I've been lead to look at the latest GhostScript.NET docs to route out how this is done, but I simply don't understand them well enough to approach this.
My question is then, based on how I'm using ghostscript now, how do I use GhostScript.NET in my project to write the converted jpegs into memory and view them there?
Here's how I'm doing it now (code-wise):
//instantiate
byte[] fileData;
Texture2D tex = null;
//if a PDF file exists at the current head path
if (File.Exists(CurrentHeadPath))
{
//Transform pdf to jpg
PdfToImage.PDFConvert pp = new PDFConvert();
pp.OutputFormat = "jpeg"; //format
pp.JPEGQuality = 100; //100% quality
pp.ResolutionX = 300; //dpi
pp.ResolutionY = 500;
pp.OutputToMultipleFile = true;
CurrentPDFPath = "Data/myFiles/pdfconvimg.jpg";
//this call is what actually converts the pdf to jpeg files
pp.Convert(CurrentHeadPath, CurrentPDFPath);
//this just loads the first image
if (File.Exists("Data/myFiles/pdfconvimg" + 1 + ".jpg"))
{
//reads in the jpeg file by bytes
fileData = File.ReadAllBytes("Data/myFiles/pdfconvimg" + 1 + ".jpg");
tex = new Texture2D(2, 2);
tex.LoadImage(fileData); //..this will auto-resize the texture dimensions.
//Read Texture into RawImage component
PdfObject.GetComponent<RawImage>().texture = tex;
PdfObject.GetComponent<RawImage>().rectTransform.sizeDelta = new Vector2(288, 400);
PdfObject.GetComponent<RawImage>().enabled = true;
}
else
{
Debug.Log("reached eof");
}
}
The convert function is from a script called PDFConvert which I obtained from code project. Specifically How To Convert PDF to Image Using Ghostscript API.
From the GhostScript.Net documentation, take a look at the example code labeled: "Using GhostscriptRasterizer class". Specifically the following lines:
Image img = _rasterizer.GetPage(desired_x_dpi, desired_y_dpi, pageNumber);
img.Save(pageFilePath, ImageFormat.Png);
The Image class seems to be part of the System.Drawing package, and System.Drawing.Image has another Save method where the first parameter is a System.IO.Stream.