When i use getRGB() and after that get pixel color Red or Green or Blue component (it does not matter because they equal in Gray image) and compare result with MS Paint Eyedropper result, its different things.
import java.awt.Color;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
public class Separator {
BufferedImage inputImg;
private int _inpupImgWidth;
private int _inpupImgHeight;
public Separator(){
try {
inputImg = ImageIO.read(new File("inputImg.bmp"));
_inpupImgWidth = inputImg.getWidth();
_inpupImgHeight = inputImg.getHeight();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(getGrayPixelData(60, 44));
try {
ImageIO.write(inputImg, "BMP", new File("outputImg.bmp"));
} catch (IOException e) {
e.printStackTrace();
}
}
public void getGrayPixelData(int x, int y){
Color myColor = new Color(inputImg.getRGB(x, y));
System.out.println("Red: " + myColor.getRed());
System.out.println("Green: " + myColor.getGreen());
System.out.println("Blue: " + myColor.getBlue());
}
public static void main(String[] args) {
new Separator();
System.out.println("The End");
}
}
here is the link of image i use http://postimage.org/image/t6tvlv941/
The image is in greyscale mode.
How you convert a greyscale value into R, G, B is quite arbitrary.
A naive way would be to assign an identical greyscale value to each of the R, G and B components.
A more sophisticated way would be to use some transformation that takes into account the eye's sensitivity to these different components, or which takes account of the profile of your monitor or other display device.
So clearly, Java and your program are using different transformations. But in either case, the precise R, G and B values are essentially meaningless: the original data is not in R, G, B format.
Related
I am trying to create a simple class that will help me organize my hundred's of text files that represent distinct color palettes in hex format. No size restrictions but in most cases colors are less than 256 per file and support transparency also (6 or 8 hex digits).
the format is simply a text file like this (a value per line):
546A817F
A7AC827F
ACBFB97F
9DB3BA7F
...
The goal is to create a preview png image per every palette file in a direcory. (format is PNG in order to support transparency, and when viewed in image viewers easily see/get the actual color).
Preferably constructed in colored rectangles side by side, preferably with the option to set a title with the hex value.
I have tried with the following code, but there are problems in the constriction of the Graphics2D object.
The functions goes like this:
1.scan a directory for all the files,
2.for every file, we scan contents and create a list of the hex values that holds
3. we count those colors and create a png image with those colors as filled rectangles, side by side. (and maybe print the hex value also inside/top/bottom of every rectangle)
4. The best would be not to have a fixed size image, but a variable one, taking care the amount of colors per list/file.
a simple example of placing colors can be found here: http://www.java2s.com/Code/Java/2D-Graphics-GUI/ColorGradient.htm
I am not a java developer, just trying to develop simple tools to make my life easier for my personal projects. I do not care a about good code practices, I am interested only in the final result, so I'm sorry for the mixed up code or mistakes!
code till now, the alignment of rectangles is broken, loops for scanning I think work simply ok, but images I think overlay the previous graphics object on top of each other (best seen with transparency).
any contribution welcomed. Thanks in advance.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import static java.nio.charset.Charset.defaultCharset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Stream;
import javax.imageio.ImageIO;
/**
*
* #author
*/
public class ConvertFromHexColorListToImage {
public Color c = new Color (0,0,0,0);
public List<String> list = new ArrayList<>();
int count;
private BufferedImage buffer;
// the size of our image
private int IMAGE_SIZE = 800;
public ConvertFromHexColorListToImage() throws IOException {
}
protected BufferedImage getBuffer() throws IOException {
if (buffer == null) {
buffer = new BufferedImage(IMAGE_SIZE, IMAGE_SIZE/2, BufferedImage.TYPE_INT_ARGB);
try (Stream<Path> filePathStream=Files.walk(Paths.get("data/multi_hex/hex_only/"))) {
filePathStream.forEach(filePath -> {
if (Files.isRegularFile(filePath)) {
System.out.println(filePath);
count++;
System.out.println("count = " +count);
try {
//list = new ArrayList<>();
list = Files.readAllLines(filePath);
System.out.println("list = "+list);
// one image per list index
for (int i = 0; i < count; i++) {
for(int j = 0; j < list.size(); j++){
Graphics2D g = (Graphics2D) buffer.getGraphics();
//c = new Color(0,0,0,0);
c = HexToColor(list.get(j));
Random rand = new Random();
// Show all the predefined colors.
float size = 25;
float x = -size * list.size() / 8;
float y = -size * 3 / 2;
Rectangle2D r = new Rectangle2D.Float(
x + IMAGE_SIZE/12 * (float)j, y, IMAGE_SIZE/12, IMAGE_SIZE/12);
// c = HexToColor(list.get(j));
g.setPaint(c);
g.fill(r);
g.dispose();
}
}
File f = new File("data/image_pal/MyFile"+""+count+".png"); // i=files, j=colors
System.out.println("Created IMAGE = "+f);
if (!ImageIO.write(buffer, "PNG", f)) {
throw new RuntimeException("Unexpected error writing image");
}
}catch (IOException ex) {
Logger.getLogger(ConvertFromHexColorListToImage.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
}
}
return buffer;
}
//https://stackoverflow.com/questions/4129666/how-to-convert-hex-to-rgb-using-java
/**
* Converts a hex string to a color. If it can't be converted null is
* returned.
*
* #param hex (i.e. #CCCCCCFF or CCCCCC)
* #return Color
*/
public static Color HexToColor(String hex)
{
hex = hex.replace("#", "");
switch (hex.length()) {
case 6:
return new Color(
Integer.valueOf(hex.substring(0, 2), 16),
Integer.valueOf(hex.substring(2, 4), 16),
Integer.valueOf(hex.substring(4, 6), 16));
case 8:
return new Color(
Integer.valueOf(hex.substring(0, 2), 16),
Integer.valueOf(hex.substring(2, 4), 16),
Integer.valueOf(hex.substring(4, 6), 16),
Integer.valueOf(hex.substring(6, 8), 16)); //alpha FF
}
//return null;
return new Color(0, 0, 0, 0);
}
public static void main(String[] args) throws IOException {
ConvertFromHexColorListToImage test0 = new ConvertFromHexColorListToImage();
test0.getBuffer();
System.out.println("bufferedimage = "+test0.buffer);
}
}
I have a weird issue that every other guide and answer seems to contradict, but the issue seems to be deeper. OS-level deep.
System details:
Ubuntu 18.04, Unity window manager, nVidia graphics (proprietary driver)
Tried with the following Java VMs:
-OpenJDK 11 & 17,
-Temurin 11 & 17,
-JBR-17
I have an application where I draw an image on a canvas, zoomed (so it's pixelated), and I can pan around and edit with the mouse (sort of like photoshop). I do this by defining a small rectangle in the image and drawing that to the entire panel (at 4K resolution):
g.drawImage(image,
x, // dst
y,
x + visibleImageWidth * blockSize,
y + visibleImageHeight * blockSize,
ul.x, // src
ul.y,
ul.x + visibleImageWidth,
ul.y + visibleImageHeight,
this);
This works fine statically, but when I start working it with the mouse, it progressively slows down to a crawl.
I analyzed this, and it seems that the mouse fires events at 1000Hz. Then paintComponent() somehow manages to finish within that same 1ms. The OS however chokes on the amount of visual data thrown at it, and every (visual) update takes longer than the last. As long as I keep dragging the mouse, the OS crawls to a complete stop. (It seems everything non-graphical still works at normal speed, e.g. my program keeps processing input) Also visual updates of other programs stop, so it's like the graphics card or driver chokes on the data and can't process/discard it fast enough. When I let go of the mouse it stays frozen until next visual update. Then all programs instantly update their visuals and everything is back to normal.
The (heavyweight) JPanel that I have doesn't collate repaint() calls where I expect it should. Every time I call it, it immediately (from my perspective) calls paintComponent(), which finishes within 1ms, before the next call to repaint().
* Why is Java so insistent on sending graphics data to the OS at such a ridiculous speed? My monitor runs at 60Hz, not 1000Hz.
I found a very dirty workaround that at least lets me use the program in any reasonable way at all: Adding
try {
Thread.sleep(10);
} catch (InterruptedException ignored) {
}
at the end of the paintComponent() method. The program now works super smooth, without visible tearing or microstuttering (even though 10ms != 60Hz).
Why do I need this delay to, of all things, speed up graphics? How can I make Java respect the monitor's refresh rate in a 'neater' way?
[Edit] MSSCC
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.concurrent.ThreadLocalRandom;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
public class Temp extends JPanel {
public static void main(String... args) {
System.out.println(LocalDate.now());
SwingUtilities.invokeLater(() -> {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.setContentPane(new Temp());
f.setExtendedState(Frame.MAXIMIZED_BOTH);
f.setVisible(true);
});
}
private final BufferedImage image = new BufferedImage(10000, 10000, BufferedImage.TYPE_INT_RGB);
public Temp() {
super(null);
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent e) {
int x = e.getX() / 5;
int y = e.getY() / 5;
int rgb = ThreadLocalRandom.current().nextInt(0xFFFFFF);
int[] pixels = new int[100];
Arrays.fill(pixels, rgb);
image.getRaster().setDataElements(x, y, 8, 8, pixels);
repaint();
((Frame)getTopLevelAncestor()).setTitle(" (" + x + ", " + y + ')');
}
});
}
#Override
public void paintComponent(Graphics g) {
g.drawImage(image,
0, 0, getWidth(), getHeight(),
0, 0, getWidth() / 5, getHeight() / 5,
null);
}
}
Back in the day I created a Paint widget to draw like you'd do in MS Paint - and I definitely did not experience mouse move events firing at the rate you are reporting. As #GilbertLeBlanc commented, it seems like you are probably in an infinite paint loop.
Nevertheless, if this isn't the issue, you can throttle event firing like this
public class Throttle extends MouseMotionAdapter {
public static final long THRESHHOLD = 30; //ms
private lastEvTime = 0;
public void mouseMoved(MouseEvent me) {
long time = System.currentTimeMillis();
if (time > (lastEvTime + THRESHHOLD)) {
lastEvTime = time;
//do graphical update
}
// else do nothing
}
}
I am trying to make a digital clock in this way:
As shown in the image 1 i want the clock to be reflected.
What i have tried:
I tried using java (Graphics2D)g by rotating the string and the using substring but i got this problem:
My code for this:
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.Calendar;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class DigitalClock extends JPanel {
JLabel label = new JLabel();
int c = 0;
Font font = null;
JFrame frame = new JFrame();
//Constructor
public DigitalClock(){
frame.setSize(700,500);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(this);
frame.setVisible(true);
DigitalThread();
}
//Paint Method
public void paintComponent(Graphics g){
Graphics2D g2d = (Graphics2D)g;
//The background
g2d.setColor(Color.BLACK);
g2d.fillRect(0,0,500,100);
//Show Time
g2d.setColor(Color.WHITE);
g2d.setFont(new Font(g.getFont().toString(),10,15));
g2d.drawString(timeNow(),100, 25);
//Show time Reflected
g2d.rotate(Math.PI,100,25);
g2d.drawString(timeNowRot(timeNow()),45, 20);
}
//Change time Value with this Thread
public void DigitalThread(){
new Thread(new Runnable(){
public void run(){
boolean flag=true;
while(flag==true){
try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}
repaint();
}
}}).start();
}
//Return time
public String timeNow(){
return zero(Calendar.getInstance().get(Calendar.HOUR_OF_DAY))+":"+
zero(Calendar.getInstance().get(Calendar.MINUTE))+":"+zero(Calendar.getInstance().get(Calendar.SECOND));
}
//Return time reflected
public String timeNowRot(String time){
return time.substring(time.length()-1,time.length())+time.substring(time.length()-2,time.length()-1)+":";
}
//Add Zero if value<10
public String zero(int num){
if(num<10) return "0"+num;
else return ""+num;
}
}
I can achieve this by using java 2d? is there a method to rotate a string again vertically so i have not this problem thanks..
Use scale(x, y) which multiplies the x and y coordinates.
g2d.scale(1.0, -1.0);
g2.drawString(....);
g2d.scale(1.0, -1.0); // Undo
This does a transformation where the y axis is reversed.
You could also use shear for a paralellogram look.
A g2d.scale(-1.0, 1.0); would draw the string backwards. Can be used in combination with the rotation.
It allt depends on the usage of any rotation and the order, how to scale. Without rotation: scale y by -1:
good
ƃooq
Actually i found the answer based n your answers thanks all:
It is and irony but the next day after the question i had a lesson at university about that...
Info about scaling:
g2d.scale(1,-1); /*scale by y axes(Flipping vertical
|
flip here (scale(-1,1) ) | here it was
_ _ _ _ _|_ _ _ _ _
|
flip here (scale(-1,-1) ) | fliped here( scale(1,-1) )
|
*/
g2d.drawString(timeNow(),10,-27);
I also added some more effect so the clock be more realistic like:
g2d.setPaint(new GradientPaint(0,-15,color,0,-50,Color.BLACK));
Your link shows a clock face AND its reflection. If that's what you want to do then this is the way.
Draw the clock face into an Image, instead of direct to the Component. Then you render the resulting image into the component twice using drawImage - once the normal way, and once transformed so it looks reflected.
This uses slightly more memory, but only temporarily, and it saves you having to do the paint twice.
If you only want to draw the reflected clock face, then set the image transformation properties in the Graphics to get the reflection.
I'll leave the details as an exercise to the reader.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
In JAVA I am trying to programmatically tell if 2 images are equal when displayed on the screen (AKA same image even though they have different color spaces. Is there a piece of code that will return a boolean when presented 2 images?
One of the examples I have is a RGB PNG that I converted to a greyscale PNG. Both images look the same and I would like to prove this programmatically. Another example is two images where they display the exact same color pixels to the screen but the color used for 100% transparent pixels has changed.
I looked at all of the solutions and determined that they could tell you how different the images were or worked for some types of images, but not all of them. Here is the solution I came up with...
package image.utils;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.PixelGrabber;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import javax.swing.ImageIcon;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Utility methods used to interact with images.
*/
public class ImageUtils {
private final static Logger logger = LoggerFactory.getLogger(ImageUtils.class);
private static final boolean equals(final int[] data1, final int[] data2) {
final int length = data1.length;
if (length != data2.length) {
logger.debug("File lengths are different.");
return false;
}
for(int i = 0; i < length; i++) {
if(data1[i] != data2[i]) {
//If the alpha is 0 for both that means that the pixels are 100%
//transparent and the color does not matter. Return false if
//only 1 is 100% transparent.
if((((data1[i] >> 24) & 0xff) == 0) && (((data2[i] >> 24) & 0xff) == 0)) {
logger.debug("Both pixles at spot {} are different but 100% transparent.", Integer.valueOf(i));
} else {
logger.debug("The pixel {} is different.", Integer.valueOf(i));
return false;
}
}
}
logger.debug("Both groups of pixels are the same.");
return true;
}
private static final int[] getPixels(final BufferedImage img, final File file) {
final int width = img.getWidth();
final int height = img.getHeight();
int[] pixelData = new int[width * height];
final Image pixelImg;
if (img.getColorModel().getColorSpace() == ColorSpace.getInstance(ColorSpace.CS_sRGB)) {
pixelImg = img;
} else {
pixelImg = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_sRGB), null).filter(img, null);
}
final PixelGrabber pg = new PixelGrabber(pixelImg, 0, 0, width, height, pixelData, 0, width);
try {
if(!pg.grabPixels()) {
throw new RuntimeException();
}
} catch (final InterruptedException ie) {
throw new RuntimeException(file.getPath(), ie);
}
return pixelData;
}
/**
* Gets the {#link BufferedImage} from the passed in {#link File}.
*
* #param file The <code>File</code> to use.
* #return The resulting <code>BufferedImage</code>
*/
#SuppressWarnings("unused")
final static BufferedImage getBufferedImage(final File file) {
Image image;
try (final FileInputStream inputStream = new FileInputStream(file)) {
// ImageIO.read(file) is broken for some images so I went this
// route
image = Toolkit.getDefaultToolkit().createImage(file.getCanonicalPath());
//forces the image to be rendered
new ImageIcon(image);
} catch(final Exception e2) {
throw new RuntimeException(file.getPath(), e2);
}
final BufferedImage converted = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB);
final Graphics2D g2d = converted.createGraphics();
g2d.drawImage(image, 0, 0, null);
g2d.dispose();
return converted;
}
/**
* Compares file1 to file2 to see if they are the same based on a visual
* pixel by pixel comparison. This has issues with marking images different
* when they are not. Works perfectly for all images.
*
* #param file1 First file to compare
* #param file2 Second image to compare
* #return <code>true</code> if they are equal, otherwise
* <code>false</code>.
*/
private final static boolean visuallyCompareJava(final File file1, final File file2) {
return equals(getPixels(getBufferedImage(file1), file1), getPixels(getBufferedImage(file2), file2));
}
/**
* Compares file1 to file2 to see if they are the same based on a visual
* pixel by pixel comparison. This has issues with marking images different
* when they are not. Works perfectly for all images.
*
* #param file1 Image 1 to compare
* #param file2 Image 2 to compare
* #return <code>true</code> if both images are visually the same.
*/
public final static boolean visuallyCompare(final File file1, final File file2) {
logger.debug("Start comparing \"{}\" and \"{}\".", file1.getPath(), file2.getPath());
if(file1 == file2) {
return true;
}
boolean answer = visuallyCompareJava(file1, file2);
if(!answer) {
logger.info("The files \"{}\" and \"{}\" are not pixel by pixel the same image. Manual comparison required.", file1.getPath(), file2.getPath());
}
logger.debug("Finish comparing \"{}\" and \"{}\".", file1.getPath(), file2.getPath());
return answer;
}
/**
* #param file The image to check
* #return <code>true</code> if the image contains one or more pixels with
* some percentage of transparency (Alpha)
*/
public final static boolean containsAlphaTransparency(final File file) {
logger.debug("Start Alpha pixel check for {}.", file.getPath());
boolean answer = false;
for(final int pixel : getPixels(getBufferedImage(file), file)) {
//If the alpha is 0 for both that means that the pixels are 100%
//transparent and the color does not matter. Return false if
//only 1 is 100% transparent.
if(((pixel >> 24) & 0xff) != 255) {
logger.debug("The image contains Aplha Transparency.");
return true;
}
}
logger.debug("The image does not contain Aplha Transparency.");
logger.debug("End Alpha pixel check for {}.", file.getPath());
return answer;
}
}
For grayscale images I've used Mean Square Error as a measure of how different two images are before. Just plug the corresponding pixels from each image into the formula.
Not only can this tell you if they are exactly the same, but also it can tell you how different two images are, albeit in a rather crude manner.
https://en.wikipedia.org/wiki/Mean_squared_error
EDIT:
Note: This is C# code not Java (apologies but that's what I wrote it in originally), however it should be easily transferable.
//Calculates the MSE between two images
private double MSE(Bitmap original, Bitmap enhanced)
{
Size imgSize = original.Size;
double total = 0;
for (int y = 0; y < imgSize.Height; y++)
{
for (int x = 0; x < imgSize.Width; x++)
{
total += System.Math.Pow(original.GetPixel(x, y).R - enhanced.GetPixel(x, y).R, 2);
}
}
return (total / (imgSize.Width * imgSize.Height));
}
You can try this
Example
Wayback Machine to the rescue here
They explain how to compare two images
If you mean exactly the same, compare each pixel.
If you mean compare a RGB image and a greyscale image, you need to convert the RGB to greyscale first, for doing this, you need to know how you did RGB->Greyscale before, there're different ways of doing this and you could get different results.
Edit, if the method it used in RGB->Greyscale is liner, you could work out a,b,c in the formula grey = a*R + b*G + c*B by comparing 3 pixels.
One of the easiest approach I tried is getting the pixel array of both images and comparing them with Arrays.equals method.
Code sample :
package image_processing;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import javax.imageio.ImageIO;
public class CheckPixels {
public static void main(String args[]) throws IOException {
File pic1 = new File("D:\\ani\\img1.png");
File pic2 = new File("D:\\ani\\img2.png");
if (Arrays.equals(returnPixelVal(pic1), returnPixelVal(pic2))) {
System.out.println("Match");
} else {
System.out.println("No match");
}
}
public static byte[] returnPixelVal(File in) {
BufferedImage img = null;
File f = null;
byte[] pixels = null;
// read image
try {
f = in;
img = ImageIO.read(f);
pixels = ((DataBufferByte) img.getRaster().getDataBuffer()).getData();
} catch (IOException e) {
System.out.println(e);
}
return pixels;
}
}
I have an application where I want to draw an image that grows in width over time. Specifically, the application listens to the microphone and computes a spectrogram every 6 milliseconds, and I want to draw the updated spectrogram when it comes in. I've been using java.awt.image.BufferedImage to draw the spectrograms, but only for pre-recorded files, so I have a fixed width for the image. What's the best way to do this for a streaming application, where I don't know a priori the width of the image?
One possibility is to just create a new BufferedImage with one extra pixel on the right and copy the data over, but that seems inefficient to do hundreds of times per second. Or I could start with a relatively large width and keep the right side blank until it fills up, and double the width when it does, similar to how an ArrayList amortizes its size - I would only have to copy the data a few times per second, or once every few seconds, or so. Is there a better option?
I would use a combination of what you suggest and an overriding component that only paints a subimage of the total image and returns an appropriate preferred size.
Here is a demo code which shows what I mean:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class TestRecording {
public static class MyPanel extends JPanel {
private BufferedImage buffer = new BufferedImage(3000, 100, BufferedImage.TYPE_INT_RGB);
private int width = 0;
private int lastY = 50;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (width > 0) {
BufferedImage sub = buffer.getSubimage(0, 0, width, buffer.getHeight());
g.drawImage(sub, 0, Math.max(0, (getHeight() - buffer.getHeight()) / 2), this);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(width, 100);
}
protected void drawSomething() {
// Here need to handle growing image
Graphics g = buffer.getGraphics();
g.setColor(Color.GREEN);
int y = new Random().nextInt(buffer.getHeight());
g.drawLine(width, lastY, width + 1, y);
lastY = y;
width += 1;
Rectangle r = new Rectangle();
r.x = getWidth();
// Lame hack to auto-scroll to the end
scrollRectToVisible(r);
revalidate();
repaint();
}
}
protected void initUI() {
JFrame frame = new JFrame(TestRecording.class.getSimpleName());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final MyPanel p = new MyPanel();
JScrollPane scrollpane = new JScrollPane(p);
frame.add(scrollpane);
frame.setSize(400, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Timer t = new Timer(20, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
p.drawSomething();
}
});
t.start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new TestRecording().initUI();
}
});
}
}
And here is the result:
May be just scale the original image to get desired size.
Image has getScaledInstance(int width, int height, int hints) method
Do you have 1) gui where you draw it, or 2) do you need to realy output image file (or stream)?
if 1)
Draw only what is seen. Extend JComponent, I usually use JPanel and override paintComponent and paint what is visible.
To make it more efficient, create "tiles" - list of eg. BufferedImage of constant width and create them from incoming data and draw to gui only them.
2) Something similar, but you can use one image with relatively low width and draw new data to it. When full, "append" it to so far created "left" image (initially empty). This way you frequently modify small image and big not so frequently.
If end comes before filling whole right image, join only filled part with left.
You could try to gradually increase size of right image (*X, eg *1.5 or *2) to reduce number of joining images at cost of using more memory.
You could store those "images" as byte(or int) array (1D array representing 2D, but store it by columns, not by rows for more efficient modifications), this way you can store it bit more efficiently if you know that you need some unusual ammount of bits per pixels, because some colors will never be in result image.
If image gets too big, save it to disk and clear your left image and later join them together or use them separately.