17.8.1 Feature Overview
As of Version 3.6, AspPDF.NET is capable of replacing images in an existing PDF documents with other images or graphics. This feature is useful, among other things,
for reducing the overall size of a PDF document by replacing its high-resolution images with their lower-resolution versions.
The image replacement feature is built on top of the document stitching functionality described in Section 14.1.
Consider the following code:
PdfDocument objDoc2 = objPDF.OpenDocument(path);
PdfDocument objDoc1 = objPDF.CreateDocument();
objDoc1.AppendDocument(objDoc2);
objDoc1.Save(path2);
This code creates an empty new document, objDoc1, and appends objDoc2 to it, thus creating a document almost completely identical to objDoc2.
All items comprising objDoc2 are copied to objDoc1 during the appending operation, including images.
If a certain image in objDoc2 needs to be replaced with another image, the new image needs to be opened via the objDoc1 object's OpenImage method,
and a mapping between the new and old images needs to be added
with the method AddImageReplacement (introduced in Version 3.6):
PdfDocument objDoc2 = objPDF.OpenDocument(path1);
PdfDocument objDoc1 = objPDF.CreateDocument();
PdfImage objImage = objDoc1.OpenImage(imagePath);
objDoc1.AddImageReplacement(imageID, objImage);
objDoc1.AppendDocument(objDoc2);
objDoc1.Save(path2);
This code copies all items from objDoc2 to objDoc1 except the image item specified by imageID. That item is not copied and the objImage object is used in its place.
The 1st argument to the AddImageReplacement method specifies the internal ID of the image item to be replaced within objDoc2, and the 2nd argument is an instance of the PdfImage object
to replace it with. The 2nd argument can also be an instance of the PdfGraphics object if the image needs to be replaced with a graphics as opposed to another image.
The method AddImageReplacement can be called multiple times if multiple images need to be replaced.
An image ID is a string containing two numbers separated by an underscore, such as "123_0". The 2nd number is usually 0.
Image IDs can be obtained via the Log property of the object representing an extracted image, or via the PdfPreview.ImageItems collection, as described below.
17.8.2 Combining Image Extraction and Image Replacement
The following code sample replaces all images in a PDF document with their resized versions. Image resizing is performed with the help of .NET's built-in Bitmap object.
First, the code sample extracts all images from the document using the procedure described in Section 17.5 earlier in this chapter.
The extracted images are then resized by 50%. Their names and image IDs are recorded in arrays. The image ID of an extracted image is returned by the Log property of the
PdfPreview representing this extracted image.
Lastly, the AddImageReplacement method is called for every resized image in the array, followed by a call to AppendDocument and Save to complete the image replacement operation.
C# |
// Arrays to store image IDs and filenames
string[] ImageIDs = new string[100];
string[] Filenames = new string[100];
PdfManager objPDF = new PdfManager();
PdfDocument objOriginalDoc = objPDF.OpenDocument(Server.MapPath("twoimages.pdf"));
// Extract all images, resize, build a list of names and image IDs
PdfPage objPage = objOriginalDoc.Pages[1];
PdfPreview objPreview = objPage.ToImage();
PdfPreview objImage;
int i = 1;
while ((objImage = objPreview.ExtractImage(i++)) != null)
{
using (MemoryStream ms = new MemoryStream( objImage.SaveToMemory() ) )
{
Bitmap objBitmap = new Bitmap(ms);
Bitmap objResized = new Bitmap(objBitmap,
new Size(objBitmap.Width / 2, objBitmap.Height / 2));
string strImageName = String.Format("extractedimage{0}.jpg", i);
// These lines control quality (and hence size) of JPEG output
System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality;
EncoderParameters myEncoderParameters = new EncoderParameters(1);
EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, 50L);
myEncoderParameters.Param[0] = myEncoderParameter;
objResized.Save(Server.MapPath(strImageName), GetEncoder(ImageFormat.Jpeg), myEncoderParameters);
ImageIDs[i - 2] = objImage.Log; // Log property returns Image ID
Filenames[i - 2] = strImageName;
}
}
// Now perform image replacement
PdfDocument objNewDoc = objPDF.CreateDocument();
for (int n = 0; n < i - 2; n++)
{
PdfImage objExtractedImage = objNewDoc.OpenImage(Server.MapPath(Filenames[n]));
objNewDoc.AddImageReplacement(ImageIDs[n], objExtractedImage);
}
objNewDoc.AppendDocument(objOriginalDoc);
string strFilename = objNewDoc.Save(Server.MapPath("imagereplacement.pdf"), false);
|
VB.NET |
Dim ImageIDs(200) As String
Dim Filenames(200) As String
Dim objPDF As PdfManager = New PdfManager()
Dim objOriginalDoc As PdfDocument = objPDF.OpenDocument(Server.MapPath("twoimages.pdf"))
' Extract all images, resize, build a list of names and image IDs
Dim objPage As PdfPage = objOriginalDoc.Pages(1)
Dim objPreview As PdfPreview = objPage.ToImage()
Dim i As Integer = 1
Do While True
Dim objImage As PdfPreview = objPreview.ExtractImage(i)
If objImage Is Nothing Then Exit Do
Using ms As MemoryStream = new MemoryStream( objImage.SaveToMemory() )
Dim objBitmap As Bitmap = new Bitmap(ms)
Dim objResized As Bitmap = new Bitmap(objBitmap,
new Size(objBitmap.Width / 2, objBitmap.Height / 2))
Dim strImageName As String = String.Format("extractedimage{0}.jpg", i)
' These lines control quality (and hence size) of JPEG output
Dim myEncoder As System.Drawing.Imaging.Encoder = System.Drawing.Imaging.Encoder.Quality
Dim myEncoderParameters As EncoderParameters = new EncoderParameters(1)
Dim myEncoderParameter As EncoderParameter = new EncoderParameter(myEncoder, 50L)
myEncoderParameters.Param(0) = myEncoderParameter
objResized.Save(Server.MapPath(strImageName), GetEncoder(ImageFormat.Jpeg), myEncoderParameters)
ImageIDs(i - 1) = objImage.Log ' Log property returns Image ID
Filenames(i - 1) = strImageName
i = i + 1
End Using
Loop
' Now perform image replacement
Dim objNewDoc As PdfDocument = objPDF.CreateDocument()
For n As Integer = 0 To i - 2
Dim objExtractedImage As PdfImage = objNewDoc.OpenImage(Server.MapPath(Filenames(n)))
objNewDoc.AddImageReplacement(ImageIDs(n), objExtractedImage)
Next
objNewDoc.AppendDocument(objOriginalDoc)
Dim strFilename As String = objNewDoc.Save(Server.MapPath("imagereplacement.pdf"), false)
lblResult.Text = "Success! Download your PDF file here"
|
Click on the links below to run this code sample:
http://localhost/asppdf.net/manual_17/17_imagereplacement.cs.aspx
http://localhost/asppdf.net/manual_17/17_imagereplacement.vb.aspx
This code sample reduces the size of the PDF document twoimages.pdf (included in the installation) from 117 KB to 20 KB.
17.8.3 Obtaining Image Information
In addition to the AddImageReplacement method, AspPDF.NET 3.6 also offers a way to obtain a list of images in a PDF document, including information about each image's pixel size, displacement,
scaling, rotation, image ID and coordinate transformation matrix, without actually performing image extraction. This information is obtained via the PdfPreview object's
ImageItems property which returns a collection of PdfRect objects, each representing an image within the PDF document. This collection is similar to that returned by the TextItems
property described above.
To populate the ImageItems collection, the PdfPage.ToImage method must be called with the parameter ImageInfo set to True.
The width and height of the image are returned by the PdfRect properties Right and Top, respectively. The image ID is returned by the PdfRect property Text.
The displacement, scaling, rotation and coordinate transformation matrix values are encapsulated in a PdfParam object returned by the PdfRect property ImageInfo
(introduced in Version 3.6). For example, the following code snippet displays the object ID, width, height and scaling factors for all images of a document:
PdfManager objPDF = new PdfManager();
PdfDocument objDoc = objPDF.OpenDocument(@"c:\path\doc.pdf");
string strOutput = "";
foreach( PdfPage objPage in objDoc.Pages )
{
PdfPreview objPreview = objPage.ToImage("imageinfo=true");
foreach( PdfRect rect in objPreview.ImageItems )
{
strOutput = "Object ID=" + rect.Text + "<br>";
strOutput += "Width=" + rect.Right + "<br>";
strOutput += "Height=" + rect.Top + "<br>";
strOutput += "ScaleX=" + rect.ImageInfo["ScaleX"] + "<br>";
strOutput += "ScaleY=" + rect.ImageInfo["ScaleY"] + "<br>";
}
}
The full list of values encapsulated in the PdfParam object returned by the Rect.ImageInfo property is as follows:
Property | Meaning |
shiftX | Horizontal displacement |
shiftY | Vertical displacement |
rotation | Rotation in degrees |
scaleX | Horizontal scaling |
scaleY | Vertical scaling |
hasMask | 1 if the image has transparency, 0 otherwise |
a, b, c, d, e, f | The 6 components of the coordinate transformation matrix |
Access to this information can be quite useful when an image needs to be replaced with a graphics, as discussed below.
17.8.4 Replacing Images with Graphics
As shown in the Section 17.8.2 code sample, replacing images with other images with the same aspect ratio is very straightforward.
However, if the aspect ratio of the replacement image is different from that of the original image, a vertical or horizontal
distortion will occur as the new image will be stretched to fill the area occupied by the old image.
To avoid distortions, an image can be replaced with a graphics as opposed to another image. The graphics may have arbitrary content, including other images, drawings, text, etc.
The following code sample replaces all images in a PDF document with a red image with the caption "Image Removed" on a yellow background filling the entire area of the original image.
The red image is not stretched in any way and centered inside the yellow area.
C# |
PdfManager objPDF = new PdfManager();
PdfDocument objOriginalDoc = objPDF.OpenDocument(Server.MapPath("twoimages.pdf"));
// Replace images with graphics
PdfDocument objNewDoc = objPDF.CreateDocument();
PdfImage objImage = objNewDoc.OpenImage(Server.MapPath("17_imageremoved.png"));
foreach( PdfPage objPage in objOriginalDoc.Pages )
{
PdfPreview objPreview = objPage.ToImage("imageinfo=true");
foreach( PdfRect rect in objPreview.ImageItems )
{
// Create a graphics which will host the image on the new document.
float fWidth = rect.Right * rect.ImageInfo["ScaleX"];
float fHeight = rect.Top * rect.ImageInfo["ScaleY"];
PdfParam param = objPDF.CreateParam();
param["left"] = param["bottom"] = 0;
param["right"] = fWidth;
param["top"] = fHeight;
// Neutralize image coordinate transformation matrix
param["a"] = 1 / fWidth;
param["d"] = 1 / fHeight;
param["b"] = param["c"] = param["e"] = param["f"] = 0;
PdfGraphics gr = objNewDoc.CreateGraphics(param);
gr.Canvas.SetFillColor( 1, 1, 0 ); // yellow
gr.Canvas.FillRect( 0, 0, fWidth, fHeight );
gr.Canvas.SetColor( 0, 0, 0 ); // black
gr.Canvas.LineWidth = 10; // border
gr.Canvas.DrawRect( 0, 0, fWidth, fHeight );
PdfParam param2 = objPDF.CreateParam();
param2["x"] = (fWidth - objImage.Width) / 2;
param2["y"] = (fHeight - objImage.Height) / 2;
gr.Canvas.DrawImage( objImage, param2 );
// Replace image with graphics
objNewDoc.AddImageReplacement( rect.Text, gr );
}
}
objNewDoc.AppendDocument( objOriginalDoc );
string strFilename = objNewDoc.Save(Server.MapPath("replacedimage_gr.pdf"), false);
|
VB.NET |
Dim objPDF As PdfManager = New PdfManager()
Dim objOriginalDoc As PdfDocument = objPDF.OpenDocument(Server.MapPath("twoimages.pdf"))
' Replace images with graphics
Dim objNewDoc As PdfDocument = objPDF.CreateDocument()
Dim objImage As PdfImage = objNewDoc.OpenImage(Server.MapPath("17_imageremoved.png"))
For Each objPage As PdfPage In objOriginalDoc.Pages
Dim objPreview As PdfPreview = objPage.ToImage("imageinfo=true")
For Each rect As PdfRect In objPreview.ImageItems
' Create a graphics which will host the image on the new document.
Dim fWidth As Single = rect.Right * rect.ImageInfo("ScaleX")
Dim fHeight As Single = rect.Top * rect.ImageInfo("ScaleY")
Dim param As PdfParam = objPDF.CreateParam()
param("left") = 0
param("bottom") = 0
param("right") = fWidth
param("top") = fHeight
' Neutralize image coordinate transformation matrix
param("a") = 1 / fWidth
param("d") = 1 / fHeight
param("b") = 0
param("c") = 0
param("e") = 0
param("f") = 0
Dim gr As PdfGraphics = objNewDoc.CreateGraphics(param)
gr.Canvas.SetFillColor( 1, 1, 0 ) ' yellow
gr.Canvas.FillRect( 0, 0, fWidth, fHeight )
gr.Canvas.SetColor( 0, 0, 0 ) ' black
gr.Canvas.LineWidth = 10 ' border
gr.Canvas.DrawRect( 0, 0, fWidth, fHeight )
Dim param2 As PdfParam = objPDF.CreateParam()
param2("x") = (fWidth - objImage.Width) / 2
param2("y") = (fHeight - objImage.Height) / 2
gr.Canvas.DrawImage( objImage, param2 )
' Replace image with graphics
objNewDoc.AddImageReplacement( rect.Text, gr )
Next
Next
objNewDoc.AppendDocument( objOriginalDoc )
Dim strFilename As String = objNewDoc.Save(Server.MapPath("replacedimage_gr.pdf"), false)
|
Click on the links below to run this code sample:
http://localhost/asppdf.net/manual_17/17_image2graphics.cs.aspx
http://localhost/asppdf.net/manual_17/17_image2graphics.vb.aspx