iText7:How to ignore PDF Page Rotation

2019-07-25 17:36发布

问题:

I have been struggling with this issue for a long time now. I am simply trying to implement a stamping feature using iText7.NET. The issue first arises from transparency. If I use an image (tried it with transparent png), the pdf gets stamped, but the background is color black as opposed to being transparent:

For the sake of interest, the associated code is the following:

Rectangle location = new Rectangle(crop.GetLeft(),crop.GetBottom(),iWidth/4,iHeight/4);

PdfStampAnnotation stamp = new PdfStampAnnotation(location).SetStampName(new PdfName("Logo"));

PdfFormXObject xObj = new PdfFormXObject(new Rectangle(iWidth, iHeight));
PdfCanvas canvas = new PdfCanvas(xObj, pdfDoc);
canvas.AddImage(img, 0, 0,iWidth, false);
stamp.SetNormalAppearance(xObj.GetPdfObject());

stamp.SetFlags(PdfAnnotation.PRINT);

pdfDoc.GetFirstPage().AddAnnotation(stamp);
pdfDoc.Close();

In an effort to resolve the issue, I tried to emulate what Adobe does with stamp insertion - Merging the stamp PDF into the existing document. The results were great in hindsight, but it turns out, once you copy the stamp document as a PdfFormXObject, the merge process takes the rotation into account -- as result, a stamping document that happens to have a nonzero rotation value (commonly due to scans) is oriented in the wrong direction (or otherwise will get overstretched due to flipped aspect ratio)

The associated code looks like the following:

// Document to be edited and documented to be merged in
PdfDocument newDoc = new PdfDocument(reader, writer);
PdfDocument srcDoc = new PdfDocument(new PdfReader(stampsrc));

// CropBox And Dimensions
Rectangle crop = newDoc.GetFirstPage().GetCropBox();
float width = crop.GetWidth();
float height = crop.GetHeight();

// Create FormXObject and Canvas
PdfFormXObject page = srcDoc.GetPage(1).CopyAsFormXObject(newDoc);
//Extract Page Dimensions
float xWidth = srcDoc.GetFirstPage().GetCropBox().GetWidth();
float xHeight = srcDoc.GetFirstPage().GetCropBox().GetHeight();

Rectangle location = new Rectangle(crop.GetLeft(), crop.GetBottom(), xWidth , xHeight );

Debug.WriteLine(location.GetWidth());

PdfStampAnnotation stamp = new PdfStampAnnotation(location).SetStampName(new PdfName("Logo"));
PdfCanvas canvas = new PdfCanvas(newDoc.GetFirstPage().NewContentStreamBefore(), newDoc.GetFirstPage().GetResources(), newDoc);

// canvas.AddXObject(page,location.GetLeft(),location.GetBottom(),page.GetWidth());
stamp.SetNormalAppearance(page.GetPdfObject());
stamp.SetFlags(PdfAnnotation.PRINT);
newDoc.GetFirstPage().AddAnnotation(stamp);

srcDoc.Close();
newDoc.Close();

Another method involved using the CopyPageTo method, but it had no desirable result as I couldn't associate it with a stamp, nor did it contain transparency. So, as can be seen, I am stuck between trying to resolve one of two problems. It's either I manage to find a way to keep my Image background transparent without worrying about rotation, or simply counteract the rotation of the merged page (more desirable).

Additionally, I have been exploring other options such as lower level manipulation using AffineTransform and the ConcatMatrix methods - I am not well versed in them yet, but it seems that it isn't directly applicable to my stamping scenario? I used the ConcatMatrix with values (0 -1 1 0 1 1) thinking that corresponds to a 90 degrees rotation, but my stamp simply disappeared. I believe the last pair of numbers are incorrect - but again, no complete understanding there, so I can't make claims.

Another thing I tried (but not clearly understand) is messing with the setIgnorePageRotationForContent method for either documents to see if it affects the placement. Setting it to either true or false did not alter the result however.

Any further advice? Is this issue really as difficult as I make it sound? I couldn't find any online discussion that addressed this directly.

Thanks in advance

回答1:

The code for adding a transparent image is perfectly valid and should actually work for most of PNG images.

In case it doesn't work for some reason, you can set image mask explicitly in the following way:

// Circle mask
byte circledata[] = {(byte) 0x3c, (byte) 0x7e, (byte) 0xff,
            (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x7e,
            (byte) 0x3c};
ImageData mask = ImageDataFactory.Create(8, 8, 1, 1, circledata, null);
mask.MakeMask();
mask.SetInverted(true);
img.SetImageMask(mask);

PdfCanvas canvas = new PdfCanvas(xObj, pdfDoc);
canvas.AddImage(img, 0, 0, iWidth, false);

You can also load a mask from disk. Just create an image of the same dimensions as your original image for the stamp, and provide the levels of transparency in that mask image. After that, you can load the mask and set it to your image in a way similar to the described above:

ImageData mask = ImageDataFactory.create(MASK_PATH);
mask.MakeMask();
img.SetImageMask(mask);

See also this sample for more details.