Images
editPdfImage.Load reads an image file, and DrawImage draws it in a rectangle of the page:
public static void DrawImage(string imagePath, string outputPath)
{
// A JPEG file is embedded as it is; another format (PNG, WebP...) is decoded, with its transparency
var image = PdfImage.Load(imagePath);
var document = new PdfDocument();
var builder = document.Pages.Add(new PdfSize(300, 150)).CreateContentBuilder()
.SetFillRgb(0.9, 0.93, 0.97).Rectangle(0, 0, 300, 150).Fill();
// The image is stretched to the rectangle it is drawn in: compute the width that keeps its aspect ratio
var height = 120.0;
var width = height * image.Width / image.Height;
builder.DrawImage(image, 15, 15, width, height)
.DrawImage(image, 30 + width, 15, width / 2, height / 2); // drawn again: the file stores it once
document.Save(outputPath);
}
- The image fills the rectangle it is drawn in: compute the width or the height from Width and Height, its size in pixels, to keep its aspect ratio.
- An image drawn several times, on one page or on several, is stored once in the file.
- A PdfImage does not belong to a document and is thread-safe: each document that uses it gets its own copy.
Where images come from
| Method | Stores |
|---|---|
PdfImage.Load(path), PdfImage.Load(bytes) | A JPEG file as it is; any other format Meziantou.Framework.Imaging reads (PNG, WebP, GIF, TIFF...) decoded, as with FromImage |
PdfImage.FromJpeg(bytes) | A JPEG file as it is (gray, YCbCr or CMYK, 8 bits per sample), without decoding it |
PdfImage.FromImage(image) | The first frame of an Image of Meziantou.Framework.Imaging, whose pixels are copied |
PdfImage.FromImageAsJpeg(image, encoder) | The first frame of an Image, compressed as JPEG: see Photos |
- A JPEG file is kept as it is: it is not decoded and compressed again, so no quality is lost.
- The other images are stored as gray or RGB samples of 8 or 16 bits, compressed without loss. The save applies the PNG predictors to the samples when they make them smaller, as they do for most photos and gradients. Their transparent pixels become a soft mask (HasSoftMask), so the page shows through them as in the example.
- The ICC profile of an image is kept, so that its colors are shown as they were meant.
- FromImage throws
ArgumentExceptionfor an image with floating-point pixels: convert it to an integer pixel format first.
To resize, crop or convert an image before drawing it, process it with Meziantou.Framework.Imaging, then pass it to FromImage. A large photo drawn small still stores all its pixels: resize it to the resolution the page needs.
Photos
The samples of a photo compressed without loss are large. FromImageAsJpeg compresses the image as JPEG instead, with the settings of a JpegEncoder (quality, chroma subsampling, progressive coding):
private static void DrawPhotoAsJpeg(Image photo, string outputPath)
{
// A photo is much smaller as JPEG than as samples compressed without loss; its transparency stays a soft mask
var image = PdfImage.FromImageAsJpeg(photo, new Imaging.Formats.JpegEncoder { Quality = 85 });
var document = new PdfDocument();
document.Pages.Add(new PdfSize(300, 150)).CreateContentBuilder().DrawImage(image, 10, 10, 128, 128);
document.Save(outputPath);
}- JPEG loses details, and blurs sharp edges: keep FromImage for drawings, screenshots and text.
- The samples of 16 bits are rounded to 8 bits, the precision of JPEG in PDF.
- The transparent pixels still become a soft mask, compressed without loss, and the ICC profile of the image is kept.
- A JPEG file you already have is better drawn with Load or FromJpeg: it is kept as it is, without a second loss.
Black and white images
A scan, a fax or a line drawing has one bit per pixel. FromBilevel stores it in one bit per pixel with a compression made for such images, which is much smaller than the gray samples of FromImage:
// A 16 x 2 image, one bit per pixel: a set bit is a black pixel
byte[] pixels = [0b1111_0000, 0b0000_1111, 0b1010_1010, 0b0101_0101];
var image = PdfImage.FromBilevel(pixels, width: 16, height: 2, PdfBilevelCompression.CcittGroup4);
var document = new PdfDocument();
document.Pages.Add(PdfSize.A4).CreateContentBuilder().DrawImage(image, 50, 700, 160, 20);
var data = document.ToByteArray();The pixels are the rows of the image from top to bottom, each of (width + 7) / 8 bytes, the most significant bit of a byte first: a set bit is a black pixel. The bits after the last pixel of a row are ignored.
| PdfBilevelCompression | Stores |
|---|---|
| CcittGroup4 (default) | The Group 4 coding of fax machines and scanners (CCITTFaxDecode), which every reader decodes |
| Jbig2 | JBIG2 arithmetic coding (JBIG2Decode, PDF 1.4): usually smaller, especially for dithered images and halftones |
| Flate | The rows of bits compressed with FlateDecode |
- Every compression is lossless: a reader shows the pixels of the image. The JBIG2 image is one generic region; the symbol coding of text, which some encoders use to replace similar glyphs by one another, is not used.
- The image is compressed when FromBilevel is called. Group 4 coding supports images of up to 1048576 pixels per row.