Exporting more than one image in one JPG file - java

I have a JSP that allows the user to export some data. You can choose differents formats (excel, csv). Also, with the excel are exported the charts corresponding to the data (pie chart, line chart and bar chart) The user want to export the charts in a unique jpg file.
What I did is (all in Java):
Generate the charts using JFreeChart
Convert the chart into a JPG image using: ChartUtilities.saveChartAsJPEG
Then I retrieve theimage bytes:
The code:
InputStream is = null;
try {
is = new FileInputStream(image);
}catch (FileNotFoundException e) {
e.printStackTrace();
}
byte[] bytes = null;
try {
bytes = IOUtils.toByteArray(is);
}catch (IOException e) {
e.printStackTrace();
}
This is working well, I have the bytes for each chart. Then I put the bytes for each chart in a byte array:
byte[] imageBytes = getImageAsBytes(chart1,chart2,chart3);
res.setContentType("image/jpg");
res.setHeader("Content-Disposition", "attachment; filename=" + "MyCharts" + ".jpg");
res.setContentLength(imageBytes.length);
try{
OutputStream output = res.getOutputStream();
output.write(imageBytes);
output.flush();
output.close();
} catch (IOException e) {
e.printStackTrace();
}
The problem is: when I open the JPG, only one image is displayed. I tested the export for each chart and works well, but when I put all the chart bytes, is only displayed one image (always the first in the imageBytes array)
I don't know if I have to create some kind of canvas, or just is not possible put 3 images or more in the same JPG by this way.

The JPG file format isn't going to let you get away with that. My suggestion would be to create a new BufferedImage with a large enough canvas to contain all three images, render your three images onto it at staggered Y axis offsets, and then dump it out to JPG with ImageIO.

Related

Writing a GIF image over PNG image

I wonder if there is a way in java to put a gif image over png image at particular location (say at particular value of x,y). If so please help me through this.
This is the case :
I have a base Image which is of png type. and I have gif images of size 62*62. I wanted to put several such gif images on png image and I need to render the png image on front end at every 5 seconds..
To extract image from GIF file.. This save the first image into png file from GIF.
try {
ImageReader reader = ImageIO.getImageReadersByFormatName("gif").next();
ImageInputStream stream = ImageIO.createImageInputStream(new File("c:/aaa.gif");
reader.setInput(stream);
int count = reader.getNumImages(true);
if(count>0){
BufferedImage frame = reader.read(0);
ImageIO.write(frame, "png", new File(filePath+fileName+".png"));
System.out.println("Donesss");
}
} catch (IOException ex) {
}

PDFBox draw black image from BufferedImage

I try to draw an image from a bufferedImage into a PDF using PDFBox but fails, and I get black images and Acrobat Reader warns whith errors like "Out of memory" (but PDF is display).
I use a bufferedImage because I need to draw a JavaFX Image object (with came from call to Funciones.crearImagenDesdeTexto(), is a function which converts a text into an Image) into PDF. Rest of images works well without using bufferedimage.
PDPixelMap img = null;
BufferedImage bi;
try {
//If item has id, I try to get image with that id (image it's shows OK on PDF)
img = new PDPixelMap(documento, read(getClass().getResourceAsStream("/com/img/" + item.getId() + ".png")));
}
catch (Exception e) {
//If item has not id or fails load image, I create image on the fly (which contains item name. This not work on PDF, shows black images)
bi = new BufferedImage(alto, ancho, BufferedImage.TYPE_INT_ARGB);
bi.createGraphics().drawImage(SwingFXUtils.fromFXImage(Funciones.crearImagenDesdeTexto(item.getNombre()), null), ancho, alto, null);
img = new PDPixelMap(documento, bi);
}
finally {
contenedor.drawXObject(img, x, y, alto, ancho);
}
NOTE: crearImagenDesdeTexto() returns a JavaFX Image Object that is create on the fly (I try this function in other parts of the program and works well, function is take from other stackOverflow response).
Your code is confusing, you have three "new PDJpeg" and one of them is in a catch (which should just handle the error). And what does "read()" do? Does it pass a stream or a BufferedImage? If it is a stream, then it is wrong, because PDJpeg is for JPEGs, not for PNG.
The second one
img = new PDJpeg(documento, (getClass().getResourceAsStream("/com/img/" + Byte.toString(item.getId()) + ".png")));
is definitively wrong for the same reason: PDJPeg is not for PNG files / streams.
If you want to create an image from a PNG file / stream, use PDPixelMap.
It is possible to create a PDJpeg object from a BufferedImage, but this is recommended only if the image wasn't encoded before. Because if you would read a BufferedImage from a JPEG, and then use PDJPeg for this, you'll have a slight loss of quality as the image is decoded and encoded again (JPEG is a "lossy" compression format).
If my advice doesn't help, please upload the JPEG file and the PDF somewhere.
Also make sure that you're using the latest version, which is 1.8.7.
Update after comments:
the parameters to createGraphics.drawImage() should be 0, 0 and not width, height. The two parameters are a location, not a size.
Finally, I find a solution (thanks also to Tilman Hausherr):
private void dibujarImagen(Item i, int x, int y, int alto, int ancho) throws IOException {
PDPixelMap img = null;
try {
img = new PDPixelMap(documento, read(getClass().getResourceAsStream("/com/img/" + i.getId() + ".png")));
}
catch (IllegalArgumentException e) {
img = new PDPixelMap(documento, SwingFXUtils.fromFXImage(Funciones.crearImagenDesdeTexto(i.getNombre()),null));
}
finally {
contenedor.drawXObject(img, x, y, alto, ancho);
}
}

BufferedImage to File with black background

I'm trying to save a BufferedImage (came from byte[]) to a File, but it's producing a black background without the image. I'm using the photoCam from primefaces.
This is my ManagedBean method:
public void webcamCapture(CaptureEvent captureEvent) {
try {
byte[] data = captureEvent.getData();
InputStream in = new ByteArrayInputStream(data);
BufferedImage fotoBuffered = ImageIO.read(in);
String idImagem = ImagemHelper.getInstance().salvarImagemFromImageObject(fotoBuffered);
paciente.getPessoaFisica().setFoto(idImagem);
} catch (Exception e) {
addErrorMessage("Erro ao capturar imagem da webcam");
FacesContext.getCurrentInstance().validationFailed();
}
}
The method "salvarImagemFromImageObject" simple make a "ImageIO.write(image,"jpg",destFile)" to save a file, but this file don't have nothing, just a black background.
Primefaces PhotoCam component renders PNG images. PNG format is by design. If you want to work with another file format, you'll need to post-process the PNG image rendered by the PF component.
Refactor your salvarImagemFromImageObject function with a .png destFile:
ImageIO.write(fotoBuffered, "png", destFile);
EDIT
Writes the resulting png data to jpeg format:
//Converts PNG image to plain RGB format
BufferedImage newBufferedImage = new BufferedImage(fotoBuffered.getWidth(), fotoBuffered.getHeight(), BufferedImage.TYPE_INT_RGB);
newBufferedImage.createGraphics().drawImage(fotoBuffered , 0, 0, Color.WHITE, null);
//Then, writes to jpeg file
ImageIO.write(newBufferedImage, "jpg", destFile);

ImageIO saves back to original size

I've been searching for some solutions from the internet yet I still haven't found an answer to my problem.
I've been working or doing a program that would get an image file from my PC then will be edited using Java Graphics to add some text/object/etc. After that, Java ImageIO will save the newly modified image.
So far, I was able to do it nicely but I got a problem about the size of the image. The original image and the modified image didn't have the same size.
The original is a 2x3inches-image while the modified one which supposedly have 2x3inches too sadly got 8x14inches. So, it has gone BIGGER than the original one.
What is the solution/code that would give me an output of 2x3inches-image which will still have a 'nice quality'?
UPDATE:
So, here's the code I used.
public Picture(String filename) {
try {
File file = new File("originalpic.jpg");
image = ImageIO.read(file);
width = image.getWidth();
}
catch (IOException e) {
throw new RuntimeException("Could not open file: " + filename);
}
}
private void write(int id) {
try {
ImageIO.write(image, "jpg", new File("newpic.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
}
2nd UPDATE:
I now know what's the problem of the new image. As I check it from Photoshop, It has a different image resolution compared to the original one. The original has a 300 pixels/inch while the new image has a 72 pixels/inch resolution.
How will I be able to change the resolution using Java?
To set the image resolution (of the JFIF segment), you can probably use the IIOMetatada for JPEG.
Something along the lines of:
public class MetadataTest {
public static void main(String[] args) throws IOException {
BufferedImage image = new BufferedImage(100, 100, BufferedImage.TYPE_3BYTE_BGR);
ImageWriter writer = ImageIO.getImageWritersByFormatName("jpeg").next();
writer.setOutput(ImageIO.createImageOutputStream(new File("foo.jpg")));
ImageWriteParam param = writer.getDefaultWriteParam();
IIOMetadata metadata = writer.getDefaultImageMetadata(ImageTypeSpecifier.createFromRenderedImage(image), param);
IIOMetadataNode root = (IIOMetadataNode) metadata.getAsTree(metadata.getNativeMetadataFormatName());
IIOMetadataNode jfif = (IIOMetadataNode) root.getElementsByTagName("app0JFIF").item(0);
jfif.setAttribute("resUnits", "1");
jfif.setAttribute("Xdensity", "300");
jfif.setAttribute("Ydensity", "300");
metadata.mergeTree(metadata.getNativeMetadataFormatName(), root);
writer.write(null, new IIOImage(image, null, metadata), param);
}
}
Note: this code should not be used verbatim, but adding iteration, error handling, stream closing etc, clutters the example too much.
See JPEG Image Metadata DTD for documentation on the metadata format, and what options you can control.

Convert a layout to an image, how to have a good quality?

I have a layout in an Android activity, I convert it as an image and then share it on different social networks.
The things is that the quality is not good at all, I have artifacts on the image, and the quality depend of the size of the screen.
Is there any way to improve the quality ? I can't store the complete layout image as a static image in the application directory, I need it to be generated on the go.
Here is code I use to transform the layout into a PNG.
Bitmap bitmap = null;
try {
bitmap = Bitmap.createBitmap(dashboardView.getWidth(),
dashboardView.getHeight(), Bitmap.Config.ARGB_4444);
dashboardView.draw(new Canvas(bitmap));
} catch (Exception e) {
// Logger.e(e.toString());
}
FileOutputStream fileOutputStream = null;
File path = Environment
.getExternalStorageDirectory();
File file = new File(path, "wayzupDashboard" + ".png");
try {
fileOutputStream = new FileOutputStream(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream);
bitmap.compress(CompressFormat.PNG, 100, bos);
try {
bos.flush();
bos.close();
fileOutputStream.flush();
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
Edit: My bad, I left ARGB_4444, the fact is I made a lot of test before posting the question on SO, I just forgot to put ARGB_8888 in. Still the image quality is bad on Android phone with tiny screen. If only I could tell to always use HDPI drawable while capturing the layout.
ARGB_4444 means that you have only 4 bits per channel (a really poor quality).
Use ARGB_8888.
you are using Bitmap.Config.ARGB_4444. I suggest you to use ARGB_8888, like Google tells us
ARGB_4444 This field was deprecated in API level . Because of the
poor quality of this configuration, it is advised to use ARGB_8888
instead.

Categories

Resources