Java Printing on thermal printer cutts off content from either side - java

I am trying to print content from a bean object to a thermal printer with the code above, it works perfectly on other printers but not on a thermal printer,
Content is cutt-off from either side and only incomplete content placed in the middle of the paper roll is visible.
I am using barbacue to generate a bar-code and draw the image to the graphic as well,
Any help would be highly appreciated.
package com.iwar.utility;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.print.Book;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JOptionPane;
import net.sourceforge.barbecue.Barcode;
import net.sourceforge.barbecue.BarcodeException;
import net.sourceforge.barbecue.BarcodeFactory;
import net.sourceforge.barbecue.BarcodeImageHandler;
import net.sourceforge.barbecue.output.OutputException;
import com.iware.connection.db.GetStuff;
import com.iware.pos.beans.PrintableBean;
public class PrinterManager {
public static boolean PrintTicket(final PrintableBean printable, final String input){
try
{
// printable is a bean containing all the information to be printed.
final Book book = new Book();//java.awt.print.Book
// here i create a new printable object where draw all the content from the bean //object onto the graphic g
Printable b= new Printable() {
#Override
public int print(Graphics g, PageFormat pf, int page)
throws PrinterException {
// TODO Auto-generated method stub
// We have only one page, and 'page'
// is zero-based
if (page > 0) {
return NO_SUCH_PAGE;
}
// User (0,0) is typically outside the
// imageable area, so we must translate
// by the X and Y values in the PageFormat
// to avoid clipping.
// Paper paper = pf.getPaper();
Paper paper = new Paper();
double paperWidth = 3;//3.25
double paperHeight = 5;//11.69
double leftMargin = 0.12;
double rightMargin = 0.10;
double topMargin = 0.75;
double bottomMargin = 0.01;
paper.setSize(paperWidth * 100, paperHeight * 100);
paper.setImageableArea(leftMargin * 200, topMargin * 200,
(paperWidth - leftMargin - rightMargin) * 200,
(paperHeight - topMargin - bottomMargin) * 200);
pf.setOrientation(PageFormat.PORTRAIT);
Graphics2D g2d = (Graphics2D)g;
g2d.translate(pf.getImageableX(), pf.getImageableY());
g.setFont(new Font("Copperplate Gothic Bold", Font.CENTER_BASELINE, 10));
g.drawString("HUB ENTERTAINMENT LIMITED", 0, 25);
g.setFont(new Font("Copperplate Gothic Bold", Font.CENTER_BASELINE, 8));
g.setColor(Color.BLACK);
g.drawString("Ticket Number : " + printable.getTicket_entry_number(), 0, 90);
g.drawString("Ticket Type : " + printable.getTicket_type(), 0, 110);
g.drawString("Movie Name : " + printable.getMovie_name(), 0, 130);
g.drawString("Date : " + printable.getShow_date(), 0, 150);
g.drawString("Time : " + printable.getSpecific_time(), 0, 170);
g.drawString("Theater : " + printable.getTheater(), 0, 190);
g.drawString("Cinema Room : " + printable.getCinema_room(), 0, 210);
g.drawString("Cost : " + printable.getCost(), 0, 230);
g.drawString("Cashier : " + printable.getCashier(), 0, 250);
g.drawString("Printed On : " + GetStuff.getCurrentDate(), 0, 270);
g.drawString("Seat Number : " + input , 0, 290);
g.drawLine(380, 310, 0, 310);
g.drawString("Ticket Number : " + printable.getTicket_entry_number(), 0, 350);
g.drawString("Ticket Type : " + printable.getTicket_type(), 0, 370);
g.drawString("Movie Name : " + printable.getMovie_name(), 0, 390);
g.drawString("Date : " + printable.getShow_date(), 0, 410);
g.drawString("Time : " + printable.getSpecific_time(), 0, 430);
g.drawString("Theater : " + printable.getTheater(), 0, 450);
g.drawString("Cinema Room : " + printable.getCinema_room(), 0, 470);
g.drawString("Cost : " + printable.getCost(), 0, 490);
g.drawString("Cashier : " + printable.getCashier(), 0, 510);
g.drawString("Printed On : " + GetStuff.getCurrentDate(), 0, 530);
g.drawString("Seat Number : " + input, 0, 550);
g.drawLine(380, 570, 0, 570);
// String combo = "Combo";
BufferedImage img = null;
g.setFont(new Font("Eras Bold ITC", Font.ROMAN_BASELINE, 20));
if(printable.getTicket_type().equals("VIP")){
g.drawString("VIP SEATING", 0, 610);
g.drawString("DRINK + SNACK", 0, 630);
try {
String number = Integer.toString(printable.getTicket_entry_number());
Barcode barCode = BarcodeFactory.createCode128(number);
img = BarcodeImageHandler.getImage(barCode);
//ImageIO.read(new File("image/logo.png"));
} catch (BarcodeException | OutputException e) {
JOptionPane.showMessageDialog(null,"Failed to Load Image");
}
int w = img.getWidth(null);
int h = img.getHeight(null);
BufferedImage bi = new
BufferedImage(w, h, BufferedImage.TRANSLUCENT);
g = bi.getGraphics();
g.drawImage(img, 0, 0, null);
/* Draw the image, applying the filter */
g2d.drawImage(bi, null, 0, 650);
}else if(printable.getTicket_type().equals("Combo")){
g.drawString("FREE SODA", 0, 610);
g.drawString("FREE PORPCORN", 0, 630);
try {
String number = Integer.toString(printable.getTicket_entry_number());
Barcode barCode = BarcodeFactory.createCode128(number);
img = BarcodeImageHandler.getImage(barCode);
//ImageIO.read(new File("image/logo.png"));
} catch (BarcodeException | OutputException e) {
JOptionPane.showMessageDialog(null,"Failed to Load Image");
}
int w = img.getWidth(null);
int h = img.getHeight(null);
BufferedImage bi = new
BufferedImage(w, h, BufferedImage.TRANSLUCENT);
g = bi.getGraphics();
g.drawImage(img, 0, 0, null);
/* Draw the image, applying the filter */
g2d.drawImage(bi, null, 0, 650);
}else{
try {
String number = Integer.toString(printable.getTicket_entry_number());
Barcode barCode = BarcodeFactory.createCode128(number);
img = BarcodeImageHandler.getImage(barCode);
//ImageIO.read(new File("image/logo.png"));
} catch (BarcodeException | OutputException e) {
JOptionPane.showMessageDialog(null,"Failed to Load Image");
}
int w = img.getWidth(null);
int h = img.getHeight(null);
BufferedImage bi = new
BufferedImage(w, h, BufferedImage.TRANSLUCENT);
g = bi.getGraphics();
g.drawImage(img, 0, 0, null);
/* Draw the image, applying the filter */
g2d.drawImage(bi, null, 0, 590);
}
BufferedImage img2 = null;
try {
img2 = ImageIO.read(new File("images/logo.png"));
} catch (IOException e) {
}
int wi = 150; //img.getWidth(null);
int hi = 50; //img.getHeight(null);
BufferedImage bin = new
BufferedImage(wi, hi, BufferedImage.TRANSLUCENT);
g = bin.getGraphics();
g.drawImage(img2, 0, 0, null);
/* Draw the image, applying the filter */
g2d.drawImage(bin, null, 0, 26);
book.append(this, pf);
// tell the caller that this page is part
// of the printed document
return PAGE_EXISTS;
}
};
PrinterJob job = PrinterJob.getPrinterJob();
job.setPrintable(b);
if (job.printDialog())
{
//job.setPageable(book);
job.print();
return true;
}
}
catch (Exception e)
{
e.printStackTrace();
}
return false;
}
}

Related

Java 2D rotate BufferedImage

This question was answered many time but I still can't apply it to my situation.
I want to rotate image on 90 degrees clockwise.
I'm currently having following code:
private void writeImage(BufferedImage sourceImage, String Path) throws IOException {
BufferedImage result;
Graphics2D g;
AffineTransform at = new AffineTransform();
//Do some magic right here to correctly rotate the image itself
if (sourceImage.getWidth() > sourceImage.getHeight()) {
//Do some stuff that somehow works:
result = new BufferedImage(sourceImage.getHeight(null), sourceImage.getWidth(null), BufferedImage.TYPE_INT_RGB);
g = result.createGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);// Anti-alias!
g.translate((result.getHeight() - result.getWidth()) / 2, (result.getHeight() - result.getWidth()) / 2);
g.rotate(Math.toRadians(90f), sourceImage.getHeight() / 2, sourceImage.getWidth() / 2);//simple try
} else {
result = new BufferedImage(sourceImage.getWidth(null), sourceImage.getHeight(null), BufferedImage.TYPE_INT_RGB);
g = result.createGraphics();
}
//result = new BufferedImage(sourceImage.getWidth(null), sourceImage.getHeight(null), BufferedImage.TYPE_INT_RGB);
//g = result.createGraphics();
/*
if (result.getWidth() > result.getHeight()) {
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);// Anti-alias!
//g.translate(170, 0);
g.rotate(Math.toRadians(90));
//g.translate((result.getHeight() - result.getWidth()) / 4, (result.getHeight() - result.getWidth()) / 4);
//g.rotate(Math.PI / 2, result.getHeight() / 2, result.getWidth() / 2);
//g.drawImage(sourceImage, 0, 0, result.getHeight(), result.getWidth(), Color.WHITE, null);
//AffineTransformOp op = new AffineTransformOp(rotateClockwise90(result), AffineTransformOp.TYPE_BILINEAR);
//op.filter(sourceImage, result);
int tempHeight = result.getHeight();
int tempWidth = result.getWidth();
BufferedImage rotated = resize(result, tempHeight, tempWidth);
//result = rotated;
result = resize(result, result.getHeight(), result.getWidth());
}*/
g.drawImage(sourceImage, 0, 0, result.getWidth(), result.getHeight(), Color.WHITE, null);
//g.drawImage(sourceImage, at, null);
g.dispose();
//BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_RGB);
//g = bufferedImage.createGraphics();
//Color.WHITE estes the background to white. You can use any other color
//g.drawImage(image, 0, 0, bufferedImage.getWidth(), bufferedImage.getHeight(), Color.WHITE, null);
File output = new File(Path);
OutputStream out = new FileOutputStream(output);
ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next();
ImageOutputStream ios = ImageIO.createImageOutputStream(out);
writer.setOutput(ios);
ImageWriteParam param = writer.getDefaultWriteParam();
if (param.canWriteCompressed()) {
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(IMAGE_QUALITY);
}
writer.write(null, new IIOImage(result, null, null), param);
out.close();
ios.close();
writer.dispose();
}
Current Result
The source image and 'BufferedImage sourceImage' looks like this:
Source Image
And what I expect to see is this:
Expected
Thanks!
Here is a more general solution that will allow rotation of any specified degrees:
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.border.*;
public class Rotation
{
public static BufferedImage rotateImage(BufferedImage original, double theta)
{
// Determine the size of the rotated image
double cos = Math.abs(Math.cos(theta));
double sin = Math.abs(Math.sin(theta));
double width = original.getWidth();
double height = original.getHeight();
int w = (int)(width * cos + height * sin);
int h = (int)(width * sin + height * cos);
// Create empty image and fill in background
BufferedImage rotated = new BufferedImage(w, h, original.getType());
Graphics2D g2 = rotated.createGraphics();
g2.setPaint(UIManager.getColor("Panel.background"));
g2.fillRect(0, 0, w, h);
// Rotate the image
double x = w/2;
double y = h/2;
AffineTransform at = AffineTransform.getRotateInstance(theta, x, y);
x = (w - width)/2;
y = (h - height)/2;
at.translate(x, y);
g2.drawRenderedImage(original, at);
g2.dispose();
return rotated;
}
private static void createAndShowGUI()
{
BufferedImage bi;
try
{
String path = "mong.jpg";
ClassLoader cl = Rotation.class.getClassLoader();
bi = ImageIO.read( cl.getResourceAsStream(path) );
}
catch (Exception e) { return; }
JLabel label = new JLabel( new ImageIcon( bi ) );
label.setBorder( new LineBorder(Color.RED) );
label.setHorizontalAlignment(JLabel.CENTER);
JPanel wrapper = new JPanel();
wrapper.add( label );
JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 360, 0);
slider.addChangeListener(new ChangeListener()
{
public void stateChanged(ChangeEvent e)
{
int value = slider.getValue();
BufferedImage rotated = Rotation.rotateImage(bi, Math.toRadians(value) );
label.setIcon( new ImageIcon(rotated) );
}
});
JFrame frame = new JFrame("Rotation");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(wrapper, BorderLayout.CENTER);
frame.add(slider, BorderLayout.PAGE_END);
frame.setSize(600, 600);
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
java.awt.EventQueue.invokeLater( () -> createAndShowGUI() );
}
}
Try
g.drawImage(sourceImage, 0, 0, sourceImage.getWidth(), sourceImage.getHeight(), Color.WHITE, null);

Load a black and white image into an binary array

I'm building a program that can recognise images from the air.
I am able to load the image and convert it to black and white, but I'm having trouble attempting to get the pixel values into an array so that I can use a union find to link clusters of white pixels and black pixels.
Here is what I have so far:
import javafx.stage.FileChooser;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class Image {
public static void main(String args[])
{
new Image();
}
public Image()
{
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception ex) {
}
JFrame frame = new JFrame("Image");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //closes application properly
frame.add(new ImagePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class ImagePane extends JPanel {
private BufferedImage image;
private BufferedImage bwImage;
public ImagePane() {
try {
FileChooser fileChooser = new FileChooser();
image = ImageIO.read(new File("C:/Users/Connor/Desktop/image.jpg"));
this.image = image;
bwImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_BYTE_BINARY);
this.bwImage = bwImage;
Graphics2D g2d = bwImage.createGraphics();
g2d.drawImage(image, 0, 0, this);
g2d.dispose();
} catch (IOException ex) {
ex.printStackTrace();
}
}
public Dimension getPreferredSize() {
Dimension size = super.getPreferredSize();
if (image != null) {
size = new Dimension(image.getWidth() * 2, image.getHeight());
}
return size;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (image != null) {
int x = (getWidth() - (image.getWidth() * 2)) / 2;
int y = (getHeight() - (image.getHeight()));
g.drawImage(image, x, y, this);
x += image.getWidth();
g.drawImage(bwImage, x, y, this);
}
}
}
}
I'm hoping to get some output like the following:
{ 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1 },
{ 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
{ 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1 },
{ 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0 },
{ 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0 },
{ 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0 }
So a way to do this would be using a BitSet.
A small code example how to go about this:
//img is your black and white image of type BufferedImage
// Get the width and height of your image
int width = img.getWidth();
int height = img.getHeight();
// create a BitSet of the correct size
BitSet bits = new BitSet(width * height);
// Iterate through your image's pixels and set the correct bits.
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
// Check against 0xffffffff which is the RGB value of white.
if (img.getRGB(x, y) == 0xffffffff)
{
bits.set(y * width + x);
}
}
}
After this you have a BitSet with a set bit representing the color white and an unset bit representing the color black. You can now do mathematical analysis on that as you please.

Java Swing draw html formatted string

I want to create a String which displays the time in the format: 10h 30min, but the units (h and min) should have a smaller font than the numbers. When using a JLabel, I get this work with a html formatted string with span attributes.
Now I want to add such a String to a custom object and write it with the drawAlignedString method. But, here the html passing does not working. The custom object than shows my code and not the formatted String.
Is there a way to get this working or any other solution for drawing Strings with diffrent Substrings?
This is what I've tried:
String time = String.format(
"<html>%d<span style=\"font-family:Arial Unicode MS;font-size:12px;\">h </span> %d<span "
+ "style=\"font-family:Arial Unicode MS;font-size:12px;\">min</span></html>",
absSeconds / 3600, (absSeconds % 3600) / 60);
g2.setFont(this.centerTextFont);
g2.setPaint(this.centerTextColor);
TextUtilities.drawAlignedString(time, g2, (float) area.getCenterX(), (float) area.getCenterY(),
TextAnchor.CENTER);
Once the label is configured, pass the Graphics to the paint method of the label.
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class LabelRenderTest {
public static void main(String[] args) {
SwingUtilities.invokeLater( new Runnable() {
public void run() {
String title = "<html><body style='width: 200px; padding: 5px;'>"
+ "<h1>Do U C Me?</h1>"
+ "Here is a long string that will wrap. "
+ "The effect we want is a multi-line label.";
JFrame f = new JFrame("Label Render Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
BufferedImage image = new BufferedImage(
400,
300,
BufferedImage.TYPE_INT_RGB);
Graphics2D imageGraphics = image.createGraphics();
GradientPaint gp = new GradientPaint(
20f,
20f,
Color.red,
380f,
280f,
Color.orange);
imageGraphics.setPaint(gp);
imageGraphics.fillRect(0, 0, 400, 300);
JLabel textLabel = new JLabel(title);
textLabel.setSize(textLabel.getPreferredSize());
Dimension d = textLabel.getPreferredSize();
BufferedImage bi = new BufferedImage(
d.width,
d.height,
BufferedImage.TYPE_INT_ARGB);
Graphics g = bi.createGraphics();
g.setColor(new Color(255, 255, 255, 128));
g.fillRoundRect(
0,
0,
bi.getWidth(f),
bi.getHeight(f),
15,
10);
g.setColor(Color.black);
textLabel.paint(g);
Graphics g2 = image.getGraphics();
g2.drawImage(bi, 20, 20, f);
ImageIcon ii = new ImageIcon(image);
JLabel imageLabel = new JLabel(ii);
f.getContentPane().add(imageLabel);
f.pack();
f.setLocationByPlatform(true);
f.setVisible(true);
}
});
}
}

setRGB() doesn't seem to change the color

could you please tell me why the pixels won't set to red
Color myColor = new Color(255, 0, 0);
int rgb = myColor.getRGB();
String fileName = Config.IMAGEFILEPATH + "first_nodal_domain "
+ "full.png";
BufferedImage bi = new BufferedImage(AZIMUTH_RES, ELEVATION_RES, BufferedImage.TYPE_USHORT_GRAY);
for (int i = 0; i < AZIMUTH_RES; i++){
for (int j = 0; j < ELEVATION_RES; j++){
bi.setRGB(i,j,(255 << 16) + (255 << 8) + 255);
}
}
for (Point draw: shadedPoints){
bi.setRGB(draw.x, draw.y, rgb);
}
BufferedImage scaledImage = new BufferedImage(
1000, 1000, BufferedImage.TYPE_USHORT_GRAY);
// Paint scaled version of image to new image
Graphics2D graphics2D = scaledImage.createGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
graphics2D.drawImage(bi, 0, 0, 1000, 1000, null);
try {
// write out image to file as .png
ImageIO.write(scaledImage, "png", new File(fileName));
} catch (IOException ex) {
Logger.getLogger(NodalDomainsDrawing.class.getName()).log(Level.SEVERE, null, ex);
}
bi.flush();
thanks in advance.
With respect, you seem to be going about this very strangely...
Rather then trying to draw directly to the pixel level, you should be making use of the Graphics API capabilities.
For example, clearing the image is going to be significantly faster using Graphics#fillRect then looping through and setting each pixel.
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
public class TestImage02 {
public static void main(String[] args) {
Color myColor = new Color(255, 0, 0);
// int rgb = myColor.getRGB();
List<Point> shadedPoints = new ArrayList<>(25);
for (int index = 0; index < 100; index++) {
shadedPoints.add(new Point(index, index));
}
BufferedImage bi = new BufferedImage(100, 100, BufferedImage.TYPE_USHORT_GRAY);
Graphics2D g2d = bi.createGraphics();
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, 100, 100);
// for (int i = 0; i < 100; i++) {
// for (int j = 0; j < 100; j++) {
// bi.setRGB(i, j, (255 << 16) + (255 << 8) + 255);
// }
// }
g2d.setColor(myColor);
for (Point draw : shadedPoints) {
// bi.setRGB(draw.x, draw.y, rgb);
g2d.drawLine(draw.x, draw.y, 1, 1);
}
g2d.dispose();
BufferedImage scaledImage = new BufferedImage(
1000, 1000, BufferedImage.TYPE_USHORT_GRAY);
// Paint scaled version of image to new image
Graphics2D graphics2D = scaledImage.createGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
graphics2D.drawImage(bi, 0, 0, 1000, 1000, null);
graphics2D.dispose();
try {
// write out image to file as .png
ImageIO.write(scaledImage, "png", new File("Test.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
bi.flush();
}
}
I ran your original code (with modifications to make it work) and it worked fine, but I've post some additional code that use Graphics instead.
You should make sure that you are calling Graphics#dispose. On different OS'es the Graphics object can behave differently, meaning that some times, until you dispose of the graphics object, it may not actually paint anything...

What is the most efficient way of building a scaled-down ImageIcon from pixels of type byte[]?

I'm keeping image pixels in a byte array using this statement:
bytePixels = ((DataBufferByte) bufferedImage.getRaster().getDataBuffer()).getData();
Now I need to construct a scaled-down version of the image and put it in an ImageIcon using this byte array. Note that the original image maybe huge, so constructing a new BufferedImage like this:
public Icon getImageIcon(int newWidth, int newHeight) throws IOException {
BufferedImage image = ImageIO.read(originalImageFile);
BufferedImage resizedImage = new BufferedImage(newWidth, newHeight, this.getType());
Graphics2D g = resizedImage.createGraphics();
g.drawImage(image, 0, 0, newWidth, newHeight, null);
g.dispose();
return new ImageIcon(resizedImage);
}
is not an option, because it will most likely cause an OutOfMemoryError if the original image was big.
So my question is: Using the original pixels in the byte array, what is the most efficient way (memory-wise) to get an ImageIcon with smaller size?
OutOfMemory Error, that is strange. The default JVM heap size is quite large. Most likely, it is over 100 MB. A buffered image, 4 bytes per pixel of 100 MB would be:
100 000 000 = x * 4 bytes
x = 25 000 000 pixels
This would mean you are using a image of nearly 5000 * 5000 pixels. Try to enlarge the maximum heap size using this command line argument:
java -XmX400M YourClass
Also, I would not store the pixels using a byte array. But simply as a BufferedImage, this way you are sure that the image data isn't twice in memory.
Use Scaled Image with with the intent to reduce the pixels size before usage of them in the GUI, you can use Image#getScaledInstance(int width, int height, int hints), for real code you have look for Java Advanced Imaging (JAI)
there no problem get OutOfMemoryError, you can test performace of JVM and/or profile in JProfiler with this code
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import java.io.ByteArrayOutputStream;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
class ImageCacheTest {
private JLabel imageLabel;
private Dimension halfScreenSize;
private Random random;
private JProgressBar memory;
private Font bigFont = new Font("Arial", Font.BOLD, 30);
private int count = 0;
private int startMem = 0;
private int maxMem = 0;
private int peakMem = 0;
private int useMem = 0;
ImageCacheTest() {
startMem = ((int) Runtime.getRuntime().freeMemory());
maxMem = ((int) Runtime.getRuntime().freeMemory());
peakMem = ((int) Runtime.getRuntime().freeMemory());
JPanel p = new JPanel(new BorderLayout(4, 4));
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
halfScreenSize = new Dimension(d.width / 2, d.height / 2);
//halfScreenSize = new Dimension(d.width - 11, d.height - 101);
//halfScreenSize = new Dimension(4000, 3000);
random = new Random();
imageLabel = new JLabel(new ImageIcon(convertToFromBytes(getImage())));
memory = new JProgressBar(0, (int) Runtime.getRuntime().maxMemory());
memory.setPreferredSize(new Dimension(200, 30));
p.add(imageLabel, BorderLayout.CENTER);
p.add(memory, BorderLayout.SOUTH);
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(p);
f.pack();
f.setVisible(true);
Runnable r = new Runnable() {
#Override
public void run() {
while (true) {
try {
imageLabel.setIcon(new ImageIcon(convertToFromBytes(getImage())));
memory.setValue((int) Runtime.getRuntime().freeMemory());
useMem = ((int) Runtime.getRuntime().freeMemory());
Thread.sleep(300);
} catch (InterruptedException ex) {
Logger.getLogger(ImageCacheTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
};
Thread t = new Thread(r);
t.start();
}
public BufferedImage getImage() {
GradientPaint gp = new GradientPaint(0f, 0f, new Color(127 + random.nextInt(128), 127 + random.nextInt(128), 127 + random.nextInt(128)),
(float) halfScreenSize.width, (float) halfScreenSize.width, new Color(random.nextInt(128), random.nextInt(128), random.nextInt(128)));
BufferedImage bi = new BufferedImage(halfScreenSize.width, halfScreenSize.height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = bi.createGraphics();
g2d.setPaint(gp);
g2d.fillRect(0, 0, halfScreenSize.width, halfScreenSize.height);
g2d.setFont(bigFont);
g2d.setColor(Color.BLACK);
if (maxMem < ((int) Runtime.getRuntime().freeMemory())) {
maxMem = ((int) Runtime.getRuntime().freeMemory());
}
if (peakMem > ((int) Runtime.getRuntime().freeMemory())) {
peakMem = ((int) Runtime.getRuntime().freeMemory());
}
useMem = ((int) Runtime.getRuntime().freeMemory()) - useMem;
g2d.drawString("" + ++count, 20, 100);
g2d.drawString("JVM memory status ---> ", 20, 195);
g2d.drawString("tot. memory ---> " + ((int) Runtime.getRuntime().totalMemory()), 20, 240);
g2d.drawString("max. memory ---> " + ((int) Runtime.getRuntime().maxMemory()), 20, 270);
g2d.drawString("free on startUp ---> " + startMem, 20, 300);
g2d.drawString("max free memory ---> " + maxMem, 20, 350);
g2d.drawString("min free memory ---> " + peakMem, 20, 380);
g2d.drawString("act free memory ---> " + ((int) Runtime.getRuntime().freeMemory()), 20, 410);
g2d.drawString("usage of memory ---> " + useMem, 20, 450);
return bi;
}
/** Not entirely sure this method is necessary for indicating 'no cache',
but since the claim was specific to byte arrays, we'll do it. */
public Image convertToFromBytes(BufferedImage image) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(image, "png", baos);
return Toolkit.getDefaultToolkit().createImage(baos.toByteArray());
} catch (Exception e) {
return null;
}
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
ImageCacheTest ict = new ImageCacheTest();
}
};
SwingUtilities.invokeLater(r);
}
}

Categories

Resources