I'm trying to add a background in a PDF using Scalable Vector Graphics (.svg). Initially the recommended way was to transform the SVG into an Image object and then use scaleToFit to get it to the right size, then add it to the document. This works partially as it transforms the small and scalable SVG into a Bitmap. Next I've made a PdfFormXObject in order to get back the scaling by having it drawn on each page. However, now it does not display anything at all.
ByteArrayInputStream inputStream = new ByteArrayInputStream(backgroundBytes);
PdfFormXObject svg = SvgConverter.convertToXObject(inputStream, pdf);
PdfCanvas canvas = new PdfCanvas(pdf.getFirstPage());
Rectangle rect = new Rectangle(PageSize.A4.getWidth(), PageSize.A4.getHeight());
canvas.addXObject(svg, rect);
How should I be adding SVG backgrounds to iText 7 PDFs? Can this be done properly in the first place? I have not been able to find good code examples.
Update:
Here is the code for converting the SVG to a properly scaled Image. The issue with this is that it works for adding the image, but it adds it as an element so it pushes everything else down.
ByteArrayInputStream inputStream = new ByteArrayInputStream(svgAsBytes);
Image image = SvgConverter.convertToImage(inputStream, pdf);
image.scaleAbsolute(PageSize.A4.getWidth(), PageSize.A4.getHeight());
int totalPages = pdf.getNumberOfPages()+1;
for(int pageNumber = 1; pageNumber < totalPages; pageNumber++ ) {
document.add(image);
}
Hi i have a similar Problem. I am trying to add a SVG image as a table cell background. The problem is that i can not scale the image. Here is my code:
InputStream triangleSteam = this.getClass().getResourceAsStream("/AH-AddressTriangle.svg");
Image triangle = SvgConverter.convertToImage(triangleSteam, pdfDocument);
//triangle.setHeight(UnitValue.createPointValue(127.83f));
//triangle.setWidth(UnitValue.createPointValue(78.63f));
triangle.scaleAbsolute(78.63f, 127.83f);
Cell headerCell_12 = new Cell();
headerCell_12.setBorder(Border.NO_BORDER);
headerCell_12.setPadding(0f);
headerCell_12.setHeight(UnitValue.createPointValue(127.83f));
headerCell_12.setWidth(UnitValue.createPointValue(78.63f));
headerCell_12.setNextRenderer(new ImageBackgroundCellRenderer(headerCell_12, triangle));
headerTable.addCell(headerCell_12);
And here ist the BackgroundCellRenderer I am using:
protected class ImageBackgroundCellRenderer extends CellRenderer {
Image img;
public ImageBackgroundCellRenderer(Cell modelElement, Image img) {
super(modelElement);
this.img = img;
}
#Override
public IRenderer getNextRenderer() {
return new ImageBackgroundCellRenderer((Cell) modelElement, img);
}
#Override
public void draw(DrawContext drawContext) {
try {
img.scaleToFit(getOccupiedAreaBBox().getWidth(), getOccupiedAreaBBox().getHeight());
drawContext.getCanvas().addXObject(img.getXObject(), getOccupiedAreaBBox());
super.draw(drawContext);
} catch(Exception e) {
e.printStackTrace();
}
}
}
The background is added but the image is not scaled (see picture)
Screenshot from Adobe Illustrator
The SVG becomes even bigger that it actually was!
Thank you!
Related
There is a logo image displayed on Login screen inside JPanel. This image looks blurry on large monitor screens. Can anybody tell me how to fix the issue of blurred images, so that images looks sharp and clear on large monitor screens ?
Do I have to make high resolution images and scale down according to screen size ?
Below is the method to resize images in proportion.
public ImagePanel(String url, int w, int h) {
try {
InputStream is = getFileFromResourceAsStream(url);
image = ImageIO.read(is);
imageurl = url;
width=w;
height=h;
isscaled = true;
outputImage = new BufferedImage(w,h, image.getType());
} catch (IOException ex) {
ex.printStackTrace();
}
}
Here how to calculate the new height and width to be passed as parameter according to screen size ?
Thank you.
I am using itext7 to create pdf file
,and at the footer I am trying to add png images as follows:
PdfDocumentEvent documentEvent = (PdfDocumentEvent) event;
PdfPage page = documentEvent.getPage();
PdfCanvas canvas = new PdfCanvas(page);
byte[] signature = null; // retrieved from database
PngImageData imageData = (PngImageData) ImageDataFactory.createPng(signature);
canvas.addImageAt(imageData, 5f, 25f, false);
the original image itself has good resolution, but when the image is added to the pdf it appears with poor quality although I am adding the image without any changes or scaling.
how can I improve the image quality in the final pdf ?
This is snippet of my code for adding image to PDF:
PdfContentByte cbLogo = writer.getDirectContent();
if (instanceSettings.getDocumentHeaderImageLocation() != null) {
try {
String encodedString = instanceSettings.getDocumentHeaderImageLocation();
byte[] decodedBytes = Base64
.getDecoder()
.decode(encodedString);
Image imgLogo = Image.getInstance(decodedBytes);
imgLogo.scaleToFit(220f, 150f);
imgLogo.setAbsolutePosition((writer.getPageSize().getWidth() / 4) - (imgLogo.getScaledWidth() / 2),
writer.getPageSize().getHeight() - imgLogo.getScaledHeight() - 30);
cbLogo.addImage(imgLogo);
} catch (Exception e){
ErrorHandler.handle(e);
}
}
And here is another:
Image qr = Image.getInstance(file.getAbsolutePath());
qr.scaleToFit(70f, 70f);
qr.setSpacingBefore(0);
qr.setSpacingAfter(0);
qr.setPaddingTop(0);
PdfPCell cell = new PdfPCell();
cell.setPadding(0f);
cell.setUseAscender(true);
cell.setUseDescender(true);
cell.addElement(qr);
Image is of type:
import com.itextpdf.text.Image;
You can give it a try with this code. For me, both works as expected but as I said in the comments, I sometimes have dificulties viewing it in PDF application. As far as I know, itext has nothing to do with it.
I'm trying to overlay a PDF on-top of all pages in a PDF, at the top left hand side of each page. The PDFs that will be of different sizes. The PDF overlay is a constant size, which is smaller than all the pages of the PDF.
I can only seem to get PDFBox to put the overlay in the middle of the PDFs.
I would prefer not to convert the PDF overlay to a bitmap (PDImageXObject) and insert it onto the pages. Here is some rough code which I'm playing about with:-
public static void main(String[] args) throws Exception {
String overlayPath = "C:\\OverlayPdf.pdf";
String overlayOnMePath = "C:\\ToBeOverlayedOn.pdf";
PDDocument overlayOnMe = PDDocument.load(new File(overlayOnMePath)); //Document to write to.
overlayPath = overlayPath + "Anno.pdf";
HashMap<Integer, String> overlayGuide = new HashMap<>();
for (int i = 0; i < overlayOnMe.getNumberOfPages(); i++) {
overlayGuide.put(i + 1, overlayPath);
}
Overlay overlay = new Overlay();
overlay.setInputPDF(overlayOnMe);
overlay.setOverlayPosition(Overlay.Position.FOREGROUND);
overlay.overlay(overlayGuide);
overlayOnMe.save(new File(overlayOnMePath + "_OVERLAYED.pdf"));
overlay.close();
}
My gut feeling is its an affine transformation but I couldn't get that working either.
I have created a new issue and it allows to pass a transform, this will be in version 2.0.10 or higher. This will be done in calculateAffineTransform by extending the overlay class. To put the stamp on the top left, the new method would look like this:
protected AffineTransform calculateAffineTransform(PDPage page, PDRectangle overlayMediaBox)
{
AffineTransform at = new AffineTransform();
PDRectangle pageMediaBox = page.getMediaBox();
at.translate(0, pageMediaBox.getHeight() - overlayMediaBox.getHeight());
return at;
}
With javafx, when I read images the PixelFormat is rgb and I want to apply filters on them.I use writableImage.pixelWriter to set the pixels color but the PixelFormat is rgba.
I use ImageIO.write() and it work for .png, but when I try to save this modified image in .jpg or .jpeg, the color change. I find that's because rgba don't work with jpg but i don't know how to change this PixelFormat.
Is there a way to change rgba format in rgb ? Do you know another way to save javafx Image as .jpg/.jpeg ?
Edit : How I save file (it works for png)
fileChooser.getExtensionFilters().addAll(new FileChooser.ExtensionFilter("JPG Files", "*.jpg"));
File outputFile = fileChooser.showSaveDialog(null);
BufferedImage bImage = SwingFXUtils.fromFXImage(modifiedImage.getImage(), null); // getImage() return a javafx.scene.image.Image;
try {
ImageIO.write(bImage, "jpg", outputFile);
} catch (IOException e) {
throw new RuntimeException(e);
}
How I modify image (example)
Image currentImage = modifiedImage.getImage();
WritableImage writableImage = new WritableImage((int) currentImage.getWidth(), (int) currentImage.getHeight());
PixelReader pixelReader = currentImage.getPixelReader();
PixelWriter pixelWriter = writableImage.getPixelWriter();
for (int i = 0; i < (int) currentImage.getWidth(); i++) {
for (int j = 0; j < (int) currentImage.getHeight(); j++) {
pixelWriter.setColor(i, j, new Color(0,0,0,1));
}
}
modifiedImage.setImage(writableImage);
When I get the PixelFormat of the reader it's rgb but for the writer it's rgba. If I save an image without modification it's good, but when I apply a filter on it and I save the image as jpg, the colors change.
On my app the colors are good but if I open the jpg file outside they aren't. With png files there is no problem. I can allow to save only as png but it would be better if i can choose.
Solution :
BufferedImage bImage = SwingFXUtils.fromFXImage(modifiedImage.getImage(), null);
BufferedImage bImage2 = new BufferedImage(bImage.getWidth(), bImage.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
bImage2.getGraphics().drawImage(bImage, 0, 0, null);
try {
ImageIO.write(bImage2, "jpg", outputFile);
} catch (IOException e) {
throw new RuntimeException(e);
}
You are again one of the many people who are hit by this bug https://bugs.openjdk.java.net/browse/JDK-8119048 which is not considered important enough to be fixed. If you read the comments in there you will find a work-arround. Basically the idea is to copy the image after the conversion into a new image without alpha channel.
I'd really like to know how many more people have to waste their time until this bug finally gets enough attention to be fixed.
I am trying to implement a simple class that will allow a user to crop an image to be used for their profile picture. This is a java web application.
I have done some searching and found that java.awt has a BufferedImage class, and this appears (at first glance) to be perfect for what I need. However, it seems that there is a bug in this (or perhaps java, as I have seen suggested) that means that the cropping does not always work correctly.
Here is the code I am using to try to crop my image:
BufferedImage profileImage = getProfileImage(form, modelMap);
if (profileImage != null) {
BufferedImage croppedImage = profileImage
.getSubimage(form.getStartX(), form.getStartY(), form.getWidth(), form.getHeight());
System.err.println(form.getStartX());
System.err.println(form.getStartY());
File finalProfileImage = new File(form.getProfileImage());
try {
String imageType = getImageType(form.getProfileImage());
ImageIO.write(croppedImage, imageType, finalProfileImage);
}
catch (Exception e) {
logger.error("Unable to write cropped image", e);
}
}
return modelAndView;
}
protected BufferedImage getProfileImage(CropImageForm form, Map<String, Object> modelMap) {
String profileImageFileName = form.getProfileImage();
if (validImage(profileImageFileName) && imageExists(profileImageFileName)) {
BufferedImage image = null;
try {
image = getCroppableImage(form, ImageIO.read(new File(profileImageFileName)), modelMap);
}
catch (IOException e) {
logger.error("Unable to crop image, could not read profile image: [" + profileImageFileName + "]");
modelMap.put("errorMessage", "Unable to crop image. Please try again");
return null;
}
return image;
}
modelMap.put("errorMessage", "Unable to crop image. Please try again.");
return null;
}
private boolean imageExists(String profileImageFileName) {
return new File(profileImageFileName).exists();
}
private BufferedImage getCroppableImage(CropImageForm form, BufferedImage image, Map<String, Object> modelMap) {
int cropHeight = form.getHeight();
int cropWidth = form.getWidth();
if (cropHeight <= image.getHeight() && cropWidth <= image.getWidth()) {
return image;
}
modelMap.put("errorMessage", "Unable to crop image. Crop size larger than image.");
return null;
}
private boolean validImage(String profileImageFileName) {
String extension = getImageType(profileImageFileName);
return (extension.equals("jpg") || extension.equals("gif") || extension.equals("png"));
}
private String getImageType(String profileImageFileName) {
int indexOfSeparator = profileImageFileName.lastIndexOf(".");
return profileImageFileName.substring(indexOfSeparator + 1);
}
The form referred to in this code snippet is a simple POJO which contains integer values of the upper left corner to start cropping (startX and startY) and the width and height to make the new image.
What I end up with, however, is a cropped image that always starts at 0,0 rather than the startX and startY position. I have inspected the code to make sure the proper values are being passed in to the getSubimage method, and they appear to be.
Are there simple alternatives to using BufferedImage for cropping an image. I have taken a brief look at JAI. I would rather add a jar to my application than update the jdk installed on all of the production boxes, as well as any development/testing servers and local workstations.
My criteria for selecting an alternative are:
1) simple to use to crop an image as this is all I will be using it for
2) if not built into java or spring, the jar should be small and easily deployable in a web-app
Any suggestions?
Note: The comment above that there is an issue with bufferedImage or Java was something I saw in this posting: Guidance on the BufferedImage.getSubimage(int x, int y, int w, int h) method?
I have used getSubimage() numerous times before without any problems. Have you added a System.out.println(form.getStartX() + " " + form.getStartY()) before that call to make sure they're not both 0?
Also, are you at least getting an image that is form.getWidth() x form.getHeight()?
Do make sure you are not modifying/disposing profileImage in any way since the returned BufferedImage shares the same data array as the parent.
The best way is to just simply draw it across if you want a completely new and independent BufferedImage:
BufferedImage croppedImage = new BufferedImage(form.getWidth(),form.getHeight(),BufferedImage.TYPE_INT_ARGB);
Graphics g = croppedImage.getGraphics();
g.drawImage(profileImage,0,0,form.getWidth(),form.getHeight(),form.getStartX(),form.getStartY(),form.getWidth(),form.getHeight(),null);
g.dispose();
You can do it in this manner as well (code is not 100% tested as I adopted for example from an existing app i did):
import javax.imageio.*;
import java.awt.image.*;
import java.awt.geom.*;
...
BufferedImage img = ImageIO.read(imageStream);
...
/*
* w = image width, h = image height, l = crop left, t = crop top
*/
ColorModel dstCM = img.getColorModel();
BufferedImage dst = new BufferedImage(dstCM, dstCM.createCompatibleWritableRaster(w, h), dstCM.isAlphaPremultiplied(), null);
Graphics2D g = dst.createGraphics();
g.drawRenderedImage(img, AffineTransform.getTranslateInstance(-l,-t));
g.dispose();
java.io.File outputfile = new java.io.File(sessionScope.get('absolutePath') + java.io.File.separator + sessionScope.get('lastUpload'));
ImageIO.write(dst, 'png', outputfile);
Thanks for all who replied. It turns out that the problem was not in the cropping code at all.
When I displayed the image to be cropped, I resized it to fit into my layout nicely, then used a javascript cropping tool to figure out the coordinates to crop.
Since I had resized my image, but didn't take the resizing into account when I was determining the cropping coordinates, I ended up with coordinates that appeared to coincide with the top left corner.
I have changed the display to no longer resize the image, and now cropping is working beautifully.