Now I used pdfCanvas to graph a rectangle, code like below:
PdfPage page = pdf.getFirstPage();
PdfCanvas canvas = new PdfCanvas(page, true);
float x = 35;
float y = 480;
canvas.rectangle(x, y, 30, 30).stroke();
In fact, I want to add the rectangle into a table
Table table = new Table(2);
table.setWidth(261.5f);
iText 5, the canvas can be set to an image object and add to table. But in iText 7 the function doesn't work. How can i draw a picture to a table in iText7?
You can create a PdfCanvas from a standalone XObject, transform that XObject into an Image and then add the Image to the Table:
Rectangle boundingBox = new Rectangle(20,470,50,50);
PdfFormXObject xObject = new PdfFormXObject(boundingBox);
xObject.makeIndirect(pdfDoc);//Make sure the XObject gets added to the document
PdfCanvas canvas = new PdfCanvas(xObject, pdfDoc);//Create a canvas from the XObject
canvas.setStrokeColor(Color.BLUE).setLineWidth(3f).rectangle(35, 480, 30, 30).stroke();
Image rect = new Image(xObject);
table.addCell(rect);
There is a comprehensive tutorial on the developers corner of the iText website, explaining (through various examples) how to add an image to a table.
Check out http://developers.itextpdf.com/examples/tables/clone-adding-images-table
Related
I know that it is possible to set the color of the run by: How can I set background colour of a run (a word in line or a paragraph) in a docx file by using Apache POI?
The relevant code is for example (see the answer in the referenced question):
XWPFRun run=paragraph.createRun();
run.setText("background color");
CTShd cTShd = run.getCTR().addNewRPr().addNewShd();
cTShd.setVal(STShd.CLEAR);
cTShd.setColor("auto");
cTShd.setFill("00FFFF");
I would like to use an image instead as a pattern, is it possible? I know that the argument used for the fill argument is an object, so is it possible to use a picture reference or something like that?
I also know how to add directly a picture in a docx document, for example:
Image image = // my image to use
float widthEMU = // the width of the image in EMU
float heightEMU = // the height of the image in EMU
BufferedImage bimage = new BufferedImage((int) width, (int) height, BufferedImage.TYPE_INT_ARGB);
// Draw the image on to the buffered image
Graphics2D bGr = bimage.createGraphics();
bGr.drawImage(_image, 0, 0, null);
bGr.dispose();
ByteArrayOutputStream os = new ByteArrayOutputStream();
ImageIO.write(bimage, "png", os);
InputStream is = new ByteArrayInputStream(os.toByteArray());
XWPFPicture pic = run.addPicture(is, XWPFDocument.PICTURE_TYPE_PNG, "Picture", widthEMU, heightEMU);
I am unable to put stamp using itext7 using Java language on only skia generated pdf (skia is pdf library used by google; if someone has worked on google docs-> Clicks on Print -> Save as Pdf ). It Stamps incorrectly; if I stamp at top left position of pdf page then it would stamp at bottom left and show (inverted mirror) image and (inverted mirror) text. For all other pdfs it gives correct stamping.
It seems pdf generated by skia has missing meta -data.
Since you didn't share any code, nor any document, I created a PDF document from Google docs, and I used the code I wrote in answer to the Itextsharp 7 - Scaled and Centered Image as watermark question to add a Watermark in the center.
The result looked like this:
As you can see in the Document Properties, the original document was created using Skia/PDF m67; modified using iText® 7.1.3.
You need a Watermark in the top left, so I adapted the code like this:
public void createPdf(String src, String dest) throws IOException {
PdfDocument pdfDoc = new PdfDocument(
new PdfReader(src), new PdfWriter(dest));
Document document = new Document(pdfDoc);
PdfCanvas over;
PdfExtGState gs1 = new PdfExtGState();
gs1.setFillOpacity(0.5f);
int n = pdfDoc.getNumberOfPages();
Rectangle pagesize;
ImageData img = ImageDataFactory.create(IMG);
float iW = img.getWidth();
float iH = img.getHeight();
float x, y;
for (int i = 1; i <= n; i++)
{
PdfPage pdfPage = pdfDoc.getPage(i);
pagesize = pdfPage.getPageSize();
x = pagesize.getLeft();
y = pagesize.getTop() - iH;
over = new PdfCanvas(pdfDoc.getPage(i));
over.saveState();
over.setExtGState(gs1);
over.addImage(img, iW, 0, 0, iH, x, y);
over.restoreState();
}
document.close();
pdfDoc.close();
}
The result looks like this:
The image isn't mirrored; it's at the top-left position of the page. In short: there doesn't seem to be any problem with PDF's created with Skia/PDF m67.
I want to move text with iText7. I have a source bounding box, that can be somewhere on the page and I have a target bounding box, that has a fixed position (incl. width and height). I'll stay on the same page. The source and target boxes can overlap. The source bounding box can also be larger than the target box. In this case I have to reduce the font size. The text should retain font, color and so on.
There is a cut and paste example on the iText website . But in the result pdf file you can select the text at the new and old position (tried it only with a normal pdf reader). I don't want the text to be selectable at the old position.
I thought, that maybe I could select the text and just place it at the new position and remove it from the old position. For the latter i would need pdfSweep, but this is ok. Adding the text at the new position should be no problem. Even if the text has different fonts, sizes and so on. There are plenty of examples on the iText website. The only way I know to select the text is like shown in this example. This gives me only the text. But to place it at the target position with the same font, color and so on, I need all those informations, too.
I know, that pdf is not meant for editing. This is often mention in answers on StackOverflow.
Is there a way to do this with iText7?
There is no high level API in iText allowing you to move page content, in particular not all content from some rectangle. One reason may be that in general this is no mere moving. PDFs often contain structures influencing larger areas, and such structures would not simply have to be moved but instead copied, and each copy restricted to its area.
It is indeed possible, though, to combine the cut and paste example the OP found with the pdfSweep module already considered by the OP to a solution which prevents the text from being selectable at the old position, e.g. like this:
public void moveCleanSection(PdfReader pdfReader, String targetFile, int page, Rectangle from, Rectangle to) throws IOException
{
LicenseKey.loadLicenseFile("itextkey-multiple-products.xml");
ByteArrayOutputStream interimMain = new ByteArrayOutputStream();
ByteArrayOutputStream interimPage = new ByteArrayOutputStream();
ByteArrayOutputStream interimSection = new ByteArrayOutputStream();
try ( PdfDocument pdfMainDocument = new PdfDocument(pdfReader);
PdfDocument pdfPageDocument = new PdfDocument(new PdfWriter(interimPage)) )
{
pdfMainDocument.setCloseReader(false);
pdfMainDocument.copyPagesTo(page, page, pdfPageDocument);
}
try ( PdfDocument pdfMainDocument = new PdfDocument(pdfReader, new PdfWriter(interimMain));
PdfDocument pdfSectionDocument = new PdfDocument(new PdfReader(new ByteArrayInputStream(interimPage.toByteArray())),
new PdfWriter(interimSection)) )
{
List<PdfCleanUpLocation> cleanUpLocations = new ArrayList<PdfCleanUpLocation>();
cleanUpLocations.add(new PdfCleanUpLocation(page, from, null));
cleanUpLocations.add(new PdfCleanUpLocation(page, to, null));
PdfCleanUpTool cleaner = new PdfCleanUpTool(pdfMainDocument, cleanUpLocations);
cleaner.cleanUp();
cleanUpLocations = new ArrayList<PdfCleanUpLocation>();
Rectangle mediaBox = pdfSectionDocument.getPage(1).getMediaBox();
if (from.getTop() < mediaBox.getTop())
cleanUpLocations.add(new PdfCleanUpLocation(1, new Rectangle(mediaBox.getLeft(), from.getTop(), mediaBox.getWidth(), mediaBox.getTop() - from.getTop()), null));
if (from.getBottom() > mediaBox.getBottom())
cleanUpLocations.add(new PdfCleanUpLocation(1, new Rectangle(mediaBox.getLeft(), mediaBox.getBottom(), mediaBox.getWidth(), from.getBottom() - mediaBox.getBottom()), null));
if (from.getLeft() > mediaBox.getLeft())
cleanUpLocations.add(new PdfCleanUpLocation(1, new Rectangle(mediaBox.getLeft(), mediaBox.getBottom(), from.getLeft() - mediaBox.getLeft(), mediaBox.getHeight()), null));
if (from.getRight() < mediaBox.getRight())
cleanUpLocations.add(new PdfCleanUpLocation(1, new Rectangle(from.getRight(), mediaBox.getBottom(), mediaBox.getRight() - from.getRight(), mediaBox.getHeight()), null));
cleaner = new PdfCleanUpTool(pdfSectionDocument, cleanUpLocations);
cleaner.cleanUp();
}
try ( PdfDocument pdfSectionDocument = new PdfDocument(new PdfReader(new ByteArrayInputStream(interimSection.toByteArray())));
PdfDocument pdfMainDocument = new PdfDocument(new PdfReader(new ByteArrayInputStream(interimMain.toByteArray())), new PdfWriter(targetFile)) )
{
float scale = Math.min(to.getHeight() / from.getHeight(), to.getWidth() / from.getWidth());
pdfSectionDocument.getPage(1).setMediaBox(from);
PdfFormXObject pageXObject = pdfSectionDocument.getFirstPage().copyAsFormXObject(pdfMainDocument);
PdfPage pdfPage = pdfMainDocument.getPage(page);
PdfCanvas pdfCanvas = new PdfCanvas(pdfPage);
pdfCanvas.addXObject(pageXObject, scale, 0, 0, scale, (to.getLeft() - from.getLeft() * scale), (to.getBottom() - from.getBottom() * scale));
}
}
(From MoveSectionCleanly.java)
Beware: Due to the nature of pdfSweep, text being on the border of the source area is removed both from the source and the copy of it.
I have created BitMapSource from a list of RGBA pixels:
BitmapSource bmp = BitmapSource.Create(imageStrideInPixels, height, 96, 96, PixelFormats.Bgra32, null, imageData, imageStrideInPixels * pixelWidth);
I then create an image from the BitMapSource:
// create image and set image as source
Image BmpImg = new Image();
BmpImg.SetValue(Canvas.ZIndexProperty, 0);
BmpImg.Width = imageScaleWidth;
BmpImg.Height = imageScaleHeight;
BmpImg.Source = bmp;
I then add the Image to the Canvas:
mycanvas.Width = imageScaleWidth;
mycanvas.Height = imageScaleHeight;
mycanvas.Children.Clear();
mycanvas.Children.Add(BmpImg);
Canvas.SetLeft(BmpImg, 0); // to set position (x,y)
Canvas.SetTop(BmpImg, 0);
The problem is that it is not getting scaled to imageScaleWidth and imageScaleHeight, and it is being displayed half way down the canvas.
Note, I was able to do this in Java SWT by:
imageData = imageData.scaledTo(imageScaleWidth, imageScaleHeight);
gc.drawImage(imageData, 0, 0);
You can scale your image using a ScaleTransform:
// scale the original bitmap source
var transformedBitmap = new TransformedBitmap(
bmp,
new ScaleTransform(
imageScaleWidth / (double) bmp.PixelWidth,
imageScaleHeight / (double) bmp.PixelHeight));
// create image and set image as source
Image bmpImg = new Image();
bmpImg.SetValue(Canvas.ZIndexProperty, 0);
bmpImg.Source = transformedBitmap;
mycanvas.Width = imageScaleWidth;
mycanvas.Height = imageScaleHeight;
mycanvas.Children.Clear();
mycanvas.Children.Add(bmpImg);
Note that your image will be positioned at offset 0, 0 by default.
Instead of this
mycanvas.Children.Add(BmpImg);
Try this
mycanvas.Background = new VisualBrush(BmpImg);
This should render properly.
Are you sure the image is half way down the canvas and not the canvas itself is centered in its parent? I tested it and it appears that you can control the canvas position by setting vertical/horizontal alignment on canvas' parent. And also it scales properly when using the code you provided. However I created a BitmapSource in a different way. I used the following code:
PngBitmapDecoder decoder = new PngBitmapDecoder(new Uri(#"..."), BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
BitmapSource bmp = decoder.Frames[0];
I would like to draw lines and polygons with transparent lines in PDFBox. Here is some sample code of how I am drawing a blue line, but I cannot figure out to change the alpha value of the color.
PDDocument document = new PDDocument();
PDPage page = new PDPage();
document.addPage(page);
PDPageContentStream contentStream = new PDPageContentStream(document, page);
contentStream.setStrokingColor(66, 177, 230);
contentStream.drawLine(100, 100, 200, 200);
As of PDFBox 2.0 appendRawCommands is deprecated.
float alpha = 0.5f;
PDExtendedGraphicsState graphicsState = new PDExtendedGraphicsState();
graphicsState.setStrokingAlphaConstant(alpha);
stream.setGraphicsStateParameters(graphicsState);
// draw line here
You can achieve this by using a custom extended graphics state:
PDExtendedGraphicsState graphicsState = new PDExtendedGraphicsState();
graphicsState.setStrokingAlphaConstant(0.5f);
COSName graphicsStateName = page.getResources().add(graphicsState);
try (PDPageContentStream cs = new PDPageContentStream(document, page, true, true, true)) {
cs.appendRawCommands("/" + graphicsStateName.getName() + " gs\n");
// draw your line here.
}
You cannot use the alpha value of the java.awt.Color as PDFBox only uses the RGB value. As per javadoc of public void setStrokingColor(Color color) it just:
Set the stroking color, specified as
RGB.
One option could be that you set the background color as the stroking color to make your line invisible.
NOTE - Invisible != Transparent (so you won't get the see through effect)