I'm trying to stitch some images together using java. I have a bunch of images I'd like to stitch together and they are all the same dimensions so it's really just a question of lining them up next to each other I suppose. I have it working but it's very slow and probably very memory intensive. I'm wondering if there's an easier way:
public static void main(String[] args) throws IOException
{
int dim = 256;
BufferedImage merged = null;
for(int y = 0; y<10;y++)
{
for(int x = 0; x<10;x++)
{
URL url = new URL(someURL);
BufferedImage nextImage = ImageIO.read(url);
if(merged==null)
merged=nextImage;
else
{
BufferedImage tempMerged;
tempMerged = new BufferedImage(10*dim,10*dim,merged.getType());
//Write first image
for(int xx=0;xx<merged.getWidth();xx++)
for(int yy=0;yy<merged.getHeight();yy++)
tempMerged.setRGB(xx,yy,merged.getRGB(xx,yy));
//Write img2
for(int xx=0;xx<dim;xx++)
{
for(int yy=0;yy<dim;yy++)
{
int destX = (x*dim)+xx;
int destY = (y*dim)+yy;
tempMerged.setRGB(destX,destY,nextImage.getRGB(xx,yy));
}
}
merged=tempMerged;
}
System.out.println("Stitched image at "+x+","+y);
}
}
ImageIO.write(merged, "png", new File("merged.png"));
}
#Thomas: You'd have to create a new image of twice the size of the source images (e.g. for 2x 512x512 the new image should be 512x1024 or 1024x512). Then you'd render the source images to the respective area/rectangle of the target image
E.G. TiledImageWrite.java
import java.awt.image.BufferedImage;
import java.awt.*;
import javax.swing.*;
import java.net.URL;
import java.io.File;
import javax.imageio.ImageIO;
class TiledImageWrite {
public static void main(String[] args) throws Exception {
URL dayStromloUrl = new URL("https://i.stack.imgur.com/OVOg3.jpg");
URL nightStromloUrl = new URL("https://i.stack.imgur.com/lxthA.jpg");
final BufferedImage dayStromloImage = ImageIO.read(dayStromloUrl);
final BufferedImage nightStromloImage = ImageIO.read(nightStromloUrl);
final int width = dayStromloImage.getWidth();
final int height = dayStromloImage.getHeight();;
final BufferedImage columnImage =
new BufferedImage(width,2*height,BufferedImage.TYPE_INT_RGB);
final BufferedImage rowImage =
new BufferedImage(2*width,height,BufferedImage.TYPE_INT_RGB);
SwingUtilities.invokeLater( new Runnable() {
public void run() {
JPanel gui = new JPanel(new BorderLayout(3,3));
Graphics2D g2dColumn = columnImage.createGraphics();
g2dColumn.drawImage(dayStromloImage,0,0, null);
// start this one at 'height' down the final image
g2dColumn.drawImage(nightStromloImage,0,height, null);
Graphics2D g2dRow = rowImage.createGraphics();
g2dRow.drawImage(dayStromloImage,0,0, null);
// start this one at 'width' across the final image
g2dRow.drawImage(nightStromloImage,width,0, null);
gui.add(new JLabel(new ImageIcon(columnImage)),BorderLayout.CENTER);
gui.add(new JLabel(new ImageIcon(rowImage)),BorderLayout.SOUTH);
JOptionPane.showMessageDialog(null, gui);
}
} );
ImageIO.write(columnImage, "png", new File("column.png"));
ImageIO.write(rowImage, "png", new File("row.png"));
}
}
column.png
AFAIK what you're doing here is to write layers to a image. However, the png format doesn't support this.
You'd have to create a new image of twice the size of the source images (e.g. for 2x 512x512 the new image should be 512x1024 or 1024x512). Then you'd render the source images to the respective area/rectangle of the target image.
I figured out why it was going slow. In reality, I didn't want to merge images together, but rather stitch together a bunch of images. What I was doing was rewriting the original image everything when all I really want to do is add to it. Much faster now!
Related
I am using the following code to merge an mp3 and an image
IplImage ipl = cvLoadImage(path2ImageFile);
int height = ipl.height();
int width = ipl.width();
if(height%2!=0) height = height+1;
if(width%2!=0) width = width+1;
OpenCVFrameConverter.ToIplImage grabberConverter = new OpenCVFrameConverter.ToIplImage();
FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(path2OutputFile,width,height);
FrameGrabber audioFileGrabber = new FFmpegFrameGrabber(path2AudioFile);
try
{
audioFileGrabber.start();
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264 );//AV_CODEC_ID_VORBIS
recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);//AV_CODEC_ID_MP3 //AV_CODEC_ID_AAC
recorder.setFormat("mp4");
recorder.setAudioChannels(2);
recorder.start();
Frame frame = null;
//audioFileGrabber.getFrameNumber()
while ((frame = audioFileGrabber.grabFrame())!=null)
{ recorder.record(grabberConverter.convert(ipl));
recorder.record(frame);
}
recorder.stop();
audioFileGrabber.stop();
}
This produces an mp4, but it is about 1 and a half minutes longer.
Why does this happen?
Is there any way I can fix this?
Was a nice issue to solve. IMO, The issues seems to be because of two reasons
The frame rate of video in this case needs to be same as that of Audio, so that is there is no time increase
The audio frames while being written should be written at the same timestamp
Below is final code which works for me
import org.bytedeco.ffmpeg.global.*;
import org.bytedeco.javacv.*;
public class AudioExample {
public static void main(String[] args) {
String path2ImageFile = "WhatsApp Image 2018-12-29 at 21.54.58.jpeg";
String path2OutputFile = "test.mp4";
String path2AudioFile = "GMV_M_Brice_English_Greeting-Menus.mp3";
FFmpegFrameGrabber imageFileGrabber = new FFmpegFrameGrabber(path2ImageFile);
FFmpegFrameGrabber audioFileGrabber = new FFmpegFrameGrabber(path2AudioFile);
try {
audioFileGrabber.start();
imageFileGrabber.start();
FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(path2OutputFile,
imageFileGrabber.getImageWidth(), imageFileGrabber.getImageHeight());
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);//AV_CODEC_ID_VORBIS
recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);//AV_CODEC_ID_MP3 //AV_CODEC_ID_AAC
recorder.setSampleRate(audioFileGrabber.getSampleRate());
recorder.setFrameRate(audioFileGrabber.getAudioFrameRate());
recorder.setVideoQuality(1);
recorder.setFormat("mp4");
recorder.setAudioChannels(2);
recorder.start();
Frame frame = null;
Frame imageFrame = imageFileGrabber.grab();
while ((frame = audioFileGrabber.grab()) != null) {
recorder.setTimestamp(frame.timestamp);
recorder.record(imageFrame);
recorder.record(frame);
}
recorder.stop();
audioFileGrabber.stop();
imageFileGrabber.stop();
} catch (FrameRecorder.Exception | FrameGrabber.Exception e) {
e.printStackTrace();
}
}
}
I removed the opencv for image, since we can use another framegrabber to get the image as a frame also. Also you can see the audio generated is of same size as the mp3
Attempt #2
Since the first attempt was using same framerate for Video and Audio, which was causing some issue, I thought of fixing the framerate and then interleaving the audio on top
import org.bytedeco.ffmpeg.global.*;
import org.bytedeco.javacv.*;
public class AudioExample {
public static void main(String[] args) {
String path2ImageFile = "/Users/tarunlalwani/Downloads/WhatsApp Image 2018-12-29 at 21.54.58.jpeg";
String path2OutputFile = "/Users/tarunlalwani/Downloads/test.mp4";
String path2AudioFile = "/Users/tarunlalwani/Downloads/GMV_M_Brice_English_Greeting-Menus.mp3";
FFmpegFrameGrabber imageFileGrabber = new FFmpegFrameGrabber(path2ImageFile);
FFmpegFrameGrabber audioFileGrabber = new FFmpegFrameGrabber(path2AudioFile);
try {
audioFileGrabber.start();
imageFileGrabber.start();
FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(path2OutputFile,
imageFileGrabber.getImageWidth(), imageFileGrabber.getImageHeight());
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);//AV_CODEC_ID_VORBIS
recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);//AV_CODEC_ID_MP3 //AV_CODEC_ID_AAC
recorder.setSampleRate(audioFileGrabber.getSampleRate());
int frameRate = 30;
recorder.setFrameRate(frameRate);
recorder.setFormat("mp4");
recorder.setAudioChannels(2);
recorder.start();
Frame frame = null;
Frame imageFrame = imageFileGrabber.grab();
int frames = (int)((audioFileGrabber.getLengthInTime() / 1000000f) * frameRate) + 1;
int i = 0;
//create video using fixed images and framerate
while (i ++ <frames) {
recorder.record(imageFrame);
}
// Add audio to given timestamps
while ((frame = audioFileGrabber.grabFrame()) != null) {
recorder.setTimestamp(frame.timestamp);
recorder.record(frame);
}
recorder.stop();
audioFileGrabber.stop();
imageFileGrabber.stop();
} catch (FrameRecorder.Exception | FrameGrabber.Exception e) {
e.printStackTrace();
}
}
}
I want to package images in an executable .jar file in Eclipse, but even after storing them and linking to them, they do not seem to show up. I am trying to follow this guide as it seems to be the closest to what I am trying to do.
From my understanding, I need to read each of the 4 image files as a BufferredImage from an InputStream, but then need to change them back to regular Images so they work properly within JavaFX. I have tried many variations, but this one which should seem to work best is giving me a java.lang.reflect.InvocationTargetException, so it does not even work in Eclipse properly. I know there are similar questions but none seem to answer my problem specifically (most deal with ImageIcons and JFrames) or I can't piece them together properly.
public class CardPane extends Pane
{
private static Image[] images;
private static BufferedImage img1;
private static BufferedImage img2;
private static BufferedImage img3;
private static BufferedImage img4;
private static Image image1;
private static Image image2;
private static Image image3;
private static Image image4;
static
{
try {
img1 = ImageIO.read(ResourceLoader.getImage("green-club-100.png"));
img2 = ImageIO.read(ResourceLoader.getImage("pink-heart-100.png"));
img3 = ImageIO.read(ResourceLoader.getImage("black-spade-100.png"));
img4 = ImageIO.read(ResourceLoader.getImage("blue-diamond-100.png"));
}
catch (IOException e) {
e.printStackTrace();
}
image1 = SwingFXUtils.toFXImage(img1,null);
image2 = SwingFXUtils.toFXImage(img2,null);
image3 = SwingFXUtils.toFXImage(img3,null);
image4 = SwingFXUtils.toFXImage(img4,null);
images[0] = image1;
images[1] = image2;
images[2] = image3;
images[3] = image4;
}
}
final public class ResourceLoader {
public static InputStream getImage(String path) {
InputStream input = ResourceLoader.class.getResourceAsStream(path);
if (input == null)
input = ResourceLoader.class.getResourceAsStream("/" + path);
return input;
}
}
Here is what it looks like on the file explorer. I configured the build path to have the res folder marked as the source folder, which I believe is what I am supposed to do.
Is there a quick fix to get rid of the invocation error, or am I going about this whole thing entirely wrong? Sorry if the question is confusing or seems stupid, I'm pretty new to coding and to this site. Any help would be greatly appreciated, and if any more code needs to be seen, I will be glad to share! Thanks!
Edit: I have tried to different ways with the advice in mind, but neither seem to work. They run in Eclipse fine and on my computer, but the images will not show up when the jar is opened on other devices.
Here is the first with the resource loader
private static Image[] images = new Image[4];
private static Image image1 = new Image(ResourceLoader.getImage("green-club-100.png"));
private static Image image2 = new Image(ResourceLoader.getImage("pink-heart-100.png"));
private static Image image3 = new Image(ResourceLoader.getImage("black-spade-100.png"));
private static Image image4 = new Image(ResourceLoader.getImage("blue-diamond-100.png"));
static
{
images[0] = image1;
images[1] = image2;
images[2] = image3;
images[3] = image4;
}
And the second without, using URLs as in example 2
public static URL url1 = CardGridPaneTest.class.getResource("green-club-100.png");
public static URL url2 = CardGridPaneTest.class.getResource("pink-heart-100.png");
public static URL url3 = CardGridPaneTest.class.getResource("black-spade-100.png");
public static URL url4 = CardGridPaneTest.class.getResource("blue-diamond-100.png");
public static Image image1 = new Image(url1.toString());
public static Image image2 = new Image(url2.toString());
public static Image image3 = new Image(url3.toString());
public static Image image4 = new Image(url4.toString());
public static Image[] images = new Image[4];
static {
images[0] = image1;
images[1] = image2;
images[2] = image3;
images[3] = image4;
}
The code is fine. You are getting that exception because you didn't initialize the images array. Define images as;
Image[] images = new Image[4].
I'm creating a program that displays animated gifs. Because some animated gif files only store the pixels that changed from the previous frame, before each frame is displayed, it's being drawn to a master BufferedImage object, named master, then that BufferedImage is being drawn. The problem is that drawing the frames (stored as BufferedImage objects themselves) to the master reduces their quality.
I know it's not a problem with the frames themselves, if I just draw the frames individually without drawing them to master then they look fine. It's also not a problem with the fact that there's lots of frames being layered on top of each other, even the first frame shows quality reduction. I've tried setting every RenderingHint to every possible value, but it changes nothing.
Below is my code, with unnecessary parts for solving this problem omitted:
import java.awt.image.BufferedImage;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import javax.activation.MimetypesFileTypeMap;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.stream.FileImageInputStream;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
#SuppressWarnings("serial")
class A extends javax.swing.JPanel{
public static final String PATH = "C:/Users/Owner/Desktop/test.gif";
public B i;
public A() throws java.io.IOException{
i = new B(new java.io.File(PATH));
i.registerComponent(this);
}
#Override
public java.awt.Dimension preferredSize(){
return i.getSize();
}
#Override
public void paintComponent(java.awt.Graphics g){
i.draw(g);
}
public static void main(String[] args){
javax.swing.SwingUtilities.invokeLater(new Runnable(){
public void run(){
javax.swing.JFrame f = new javax.swing.JFrame();
f.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
try{
f.add(new A());
}catch(Exception e){
}
f.pack();
f.setVisible(true);
}
});
}
}
class B{
private final static String META_FORMAT = "javax_imageio_gif_image_1.0";
// instance variables
private final BufferedImage[] frames;
private BufferedImage master;// Because Gif images can store only the changing
// pixels, the first frame is drawn to this image, then the next one *on top of it*, etc.
private final short[] frameDurations; // in 100ths of a second
private final short[] xOffsets;
private final short[] yOffsets;
private int frame = 0;
private final Dimension size;// the size of the gif (calculated in findSize)
private final Timer animationTimer;
// constructor from a File (checked to be a gif)
public B(File src) throws IOException{
if (!(new MimetypesFileTypeMap().getContentType(src.getPath()).equals("image/gif"))){
throw new IOException("File is not a gif. It's Mime Type is: " +
new MimetypesFileTypeMap().getContentType(src.getAbsolutePath()));
}
FileImageInputStream stream = new FileImageInputStream(src);
Iterator<ImageReader> readers = ImageIO.getImageReaders(stream);
ImageReader reader = null;
// loop through the availible ImageReaders, find one for .gif
while (readers.hasNext()){
reader = readers.next();
String metaFormat = reader.getOriginatingProvider().getNativeImageMetadataFormatName();
// if it's a gif
if ("gif".equalsIgnoreCase(reader.getFormatName()) && META_FORMAT.equals(metaFormat)){
break;
}else{
reader = null;
continue;
}
}// while (readers.hasNext())
// if no reader for gifs was found
if (reader == null){
throw new IOException("File could not be read as a gif");
}
reader.setInput(stream, false, false);
// Lists to be converted to arrays and set as the instance variables
ArrayList<BufferedImage> listFrames = new ArrayList<BufferedImage>();
ArrayList<Short> listFrameDurs = new ArrayList<Short>();
ArrayList<Short> listXs = new ArrayList<Short>();
ArrayList<Short> listYs = new ArrayList<Short>();
boolean unknownMeta = false;// asume that the metadata can be read until proven otherwise
// loop until there are no more frames (since that isn't known, break needs to be used)
for (int i = 0;true;i++){// equivalent of while(true) with a counter
IIOImage frame = null;
try{
frame = reader.readAll(i, null);
}catch(IndexOutOfBoundsException e){
break;// this means theres no more frames
}
listFrames.add((BufferedImage)frame.getRenderedImage());
if (unknownMeta){// if the metadata has already proven to be unreadable
continue;
}
IIOMetadata metadata = frame.getMetadata();
IIOMetadataNode rootNode = null;
try{
rootNode = (IIOMetadataNode) metadata.getAsTree(META_FORMAT);
}catch(IllegalArgumentException e){
// means that the metadata can't be read, it's in an unknown format
unknownMeta = true;
continue;
}
// get the duration of the current frame
IIOMetadataNode graphicControlExt = (IIOMetadataNode)rootNode.getElementsByTagName("GraphicControlExtension").item(0);
listFrameDurs.add(Short.parseShort(graphicControlExt.getAttribute("delayTime")));
// get the x and y offsets
try{
IIOMetadataNode imageDescrip = (IIOMetadataNode)rootNode.getElementsByTagName("ImageDescriptor").item(0);
listXs.add(Short.parseShort(imageDescrip.getAttribute("imageLeftPosition")));
listYs.add(Short.parseShort(imageDescrip.getAttribute("imageTopPosition")));
}catch(IndexOutOfBoundsException e){
e.printStackTrace();
listXs.add((short) 0);
listYs.add((short) 0);
}
}// for loop
reader.dispose();
// put the values in the lists into the instance variable arrays
frames = listFrames.toArray(new BufferedImage[0]);
// looping must be used because the ArrayList can't contian primitives
frameDurations = new short[listFrameDurs.size()];
for (int i = 0;i < frameDurations.length;i++){
frameDurations[i] = (short)(listFrameDurs.get(i) * 10);
}
xOffsets = new short[listXs.size()];
for (int i = 0;i < xOffsets.length;i++){
xOffsets[i] = listXs.get(i);
}
yOffsets = new short[listYs.size()];
for (int i = 0;i < yOffsets.length;i++){
yOffsets[i] = listYs.get(i);
}
size = findSize();
animationTimer = new Timer(frameDurations[0], null);
clearLayers();
}
// finds the size of the image in constructors
private final Dimension findSize(){
int greatestX = -1;
int greatestY = -1;
// loop through the frames and offsets, finding the greatest combination of the two
for (int i = 0;i < frames.length;i++){
if (greatestX < frames[i].getWidth() + xOffsets[i]){
greatestX = frames[i].getWidth() + xOffsets[i];
}
if (greatestY < frames[i].getHeight() + yOffsets[i]){
greatestY = frames[i].getHeight() + yOffsets[i];
}
}// loop
return new Dimension(greatestX, greatestY);
}// findSize
private BufferedImage getFrame(){
/* returning frames[frame] gives a perfect rendering of each frame (but only changed
* pixels), but when master is returned, even the first frame shows quality reduction
* (seen by slowing down the framerate). The issue is with drawing images to master
*/
Graphics2D g2d = master.createGraphics();
g2d.drawImage(frames[frame], xOffsets[frame], yOffsets[frame], null);
g2d.dispose();
return master;
}
public Dimension getSize(){
return size;
}
// adds a FrameChangeListener associated with a component to the Timer
public void registerComponent(Component c){
FrameChangeListener l = new FrameChangeListener(c);
animationTimer.addActionListener(l);
if (!animationTimer.isRunning()){
animationTimer.start();
}
}
// draws the image to the given Graphics context (registerComponent must be used for the image
// to animate properly)
public void draw(Graphics g){
g.drawImage(getFrame(), 0, 0, null);
}
// resets master
private void clearLayers(){
master = new BufferedImage((int)size.getWidth(), (int)size.getHeight(), frames[0].getType());
}
// class that listens for the Swing Timer.
private class FrameChangeListener implements ActionListener{
private final Component repaintComponent;
// the Components repaint method will be invoked whenever the animation changes frame
protected FrameChangeListener(Component c){
repaintComponent = c;
}
public void actionPerformed(ActionEvent e){
frame++;
int delay;
try{
delay = frameDurations[frame] * 10;
}catch(ArrayIndexOutOfBoundsException x){
frame = 0;
clearLayers();
delay = frameDurations[frame] * 10;
}
animationTimer.setDelay(delay);
repaintComponent.repaint();
}// actionPerformed
}// FrameChangeListener
}
And here is the image file I've been using to test:
And here is how it displays:
It would be much appreciated if anyone could help me solve this issue
The problem is this line from the clearLayers() method:
master = new BufferedImage((int)size.getWidth(), (int)size.getHeight(), frames[0].getType());
As the GIF uses a palette, the BufferedImage type will be TYPE_BYTE_INDEXED. However, if you pass this parameter to the BufferedImage constructor, it will use a default IndexColorModel (a built-in, fixed 256 color palette), not the palette from your GIF. Thus, the frames from the GIF will have to be dithered into the destination, as the colors doesn't match.
Instead, use TYPE_INT_RGB/TYPE_INT_ARGB for type, or use the constructor that also takes an IndexColorModel parameter and pass the IndexColorModel from the frames of the GIF.
In code:
master = new BufferedImage((int)size.getWidth(), (int)size.getHeight(), BufferedImage.TYPE_INT_ARGB);
Alternatively, the following should also work if all frames of the GIF uses the same palette (not necessarily the case):
master = new BufferedImage((int)size.getWidth(), (int)size.getHeight(), frames[0].getType(), (IndexColorModel) frames[0].getColorModel());
However, as the OP reports back the latter option doesn't work for him, the first option is probably safer. :-)
I am unable to display the image as there's problem in the main method and i am not sure whether did i write the image correctly. Sorry, I am really new to Java.
public class Display extends JPanel
{
String path = "C:/Users/asus/workspace/Code/src/7horses.jpg";
File file = new File(path);
static BufferedImage img;
img = ImageIO.read(new File(file));
public static BufferedImage CopyImage (File file)
{
BufferedImage cImg = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics g = cImg.createGraphics();
g.drawImage(img, 0, 0, null);
g.dispose();
File saveImage = new File("C:/Users/asus/workspace/Code/src", saveAs);
ImageIO.write(cImg, "png", saveImage);
return cImg;
}
public static void main(String[] args)
{
JFrame f = new JFrame("Show Image");
LoadImage panel = new BufferedImage CopyImage(file);//
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(panel);
f.pack();
f.setLocation(200,200);
f.setVisible(true);
}
}
After duplicate the image, i am not sure how to display the duplicate copy. Below was the code which i initially use for loading and displaying.
public class LoadImage extends JPanel
{
BufferedImage img;
String path = "C:/Users/asus/workspace/MP/src/7horses.jpg";
File file = new File(path);
public void paint(Graphics g)
{
g.drawImage(img, 0, 0, null);
}
public LoadImage()
{
try
{
img = ImageIO.read(file);
}
catch (IOException e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
JFrame f = new JFrame("Show Image");
LoadImage panel = new LoadImage();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(panel);
f.pack();
f.setLocation(200,200);
f.setVisible(true);
}
}
There's a few things wrong with this code..
path and file cannot be accessed by main() because they are not static and main is. Meaning when main() is ran, neither of path or file exist.
LoadImage panel = new BufferedImage CopyImage(file) is not valid Java - I'm not sure what you were trying to do but I guess you want to remove the new BufferedImage part
img = ImageIO.read(new File(file)); - you can't run this statement outside a method or static block as it requires handling of an IOException
ImageIO.read(new File(file)); - file is already of type File and you are passing it to a type File, not necessary. ImageIO.read(file); would do
saveAs hasn't been defined anywhere.
ImageIO.write(cImg, "png", saveImage); can throw an IOException so you need to add a try-catch around it like in the LoadImage() constructor or append throws IOException to your method signature like so public static BufferedImage CopyImage (File file) throws IOException
You are referencing LoadImage which looks like it's trying to do exactly what Display does in a slightly different way. I'm not sure what to advise here because I don't understand the intention but I think perhaps replace LoadImage in the Display code with Display
Maybe:
Use ImageIO to retrieve a BufferedImage from your file.
Using an ImagePanel that can use a Buffered Image to display on
your JFrame
It would be something more like that:
public class Display extends JPanel {
private static final long serialVersionUID = 1L;
private static final String path = "C:/Users/asus/workspace/Code/src/7horses.jpg";
private static final File file = new File(path);
public static void main(String[] args) throws IOException {
JFrame f = new JFrame("Show Image");
BufferedImage image = ImageIO.read(file);
ImagePanel panel = new ImagePanel(image);//
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(panel);
f.pack();
f.setLocation(200, 200);
f.setVisible(true);
}
public static class ImagePanel extends JPanel {
private static final long serialVersionUID = 1L;
private BufferedImage image;
public ImagePanel(BufferedImage image) {
this.image = image;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, null); // see javadoc for more info on the parameters
}
}
}
What is a LoadImage? Unless it's both a BufferedImage AND a Container your code won't even compile.
And as a class can't be both a Container and a BufferedImage at the same time (given that both are classes, not interfaces, and multiple inheritance at class level doesn't exist in Java) your code can't work.
You're going to have to figure out how to correctly initialise your LoadImage instance, and only the documentation (and possibly source) of that class is going to help you.
i am trying to load image from specified path, and list of files are stored inside List<>.
at first time when i initialize image it display but when i am trying to display next image from List instance which contain list of files, it doesn't repaint the image.
what's wrong going is i am initializing image in constructor first time that overwrite
the new image, now where to initialize image first time outside constructor i don't know.
my code :
public void nextImage(int cnt)
{
System.out.println(cnt);
if (cnt < imageFiles.size())
{
System.out.println(imageFiles.size());
try
{
bg = ImageIO.read(new File((imageFiles.get(cnt)).toString()));
scaled = getScaledInstanceToFit(bg, new Dimension(600, 600));
setBackground(Color.BLACK);
}
catch(Exception e)
{
e.printStackTrace();
}
}
MouseHandler handler = new MouseHandler();
addMouseListener(handler);
addMouseMotionListener(handler);
System.out.println(cnt);
System.out.println(imageFiles.get(cnt).toString());
}
menu item click code :
JMenuItem mntmRestoreImage = new JMenuItem("Next Image");
final ImagePane st = new ImagePane();
mntmRestoreImage.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent arg0)
{
st.nextImage(k);
k++;
}
});
mnEdit.add(mntmRestoreImage);
class code & constructor :
private BufferedImage bg;
private BufferedImage scaled;
java.util.List<Path> imageFiles= getFilesFromDirectory(FileSystems.getDefault().getPath("D:\\New folder"));
public ImagePane()
{
try
{
bg = ImageIO.read(getClass().getResource("/images/src11.jpg"));
scaled = getScaledInstanceToFit(bg, new Dimension(600, 600));
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
counter also increments, now the code inside ImagePane() constructor
overwrites the image of nextImage() function, so idea what happen out
in this code ??
any suggestion ?
I think I have the perfect solution for you! I wrote a little program for you so it is easier to understand.
First I have a method for you to check if the file is a picture:
public Stack<File> getFilesInFolder(String startPath) {
File startFolder = new File(startPath);
Stack<File> picturestack = new Stack<File>();
String extension;
int dotindex;
// Go through the folder
for (File file : startFolder.listFiles()) {
extension = "";
dotindex = file.getName().lastIndexOf('.'); // Get the index of the dot in the filename
if (dotindex > 0) {
extension = file.getName().substring(dotindex + 1);
// Iterate all valid file types and check it
for (String filetype : validpicturetypes) {
if (extension.equals(filetype)) {
picturestack.add(file);
}
}
}
}
return picturestack;
}
Very easy! Take the folder and iterate his files. Take the extension of the file and check if it is a valid file type. Define the file types in a array at the begining of your code.
String[] validpicturetypes = {"png", "jpg", "jpeg", "gif"};
At the end I push every file into a stack. Remember to fill the stack into a variable, do not read the files more than once because than you get the same problem as before:
Stack<File> pictures = getFilesInFolder("C:\\Users\\Admin\\Desktop");
After that use a Action for your JMenuItem! In my example I do not have much, you have to put your methods in!
Action nextpictureaction = new AbstractAction("Next Picture") {
private static final long serialVersionUID = 2421742449531785343L;
#Override
public void actionPerformed(ActionEvent e) {
if (!pictures.isEmpty()) {
System.out.println(pictures.pop().getName());
}
}
};
Add the Action at your JMenu and set the properties of your Frame.
/*
* Add Components to Frame
*/
setJMenuBar(menubar);
menubar.add(toolsmenu);
toolsmenu.add(nextpictureaction);
/*
* Frame Properties
*/
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationByPlatform(true);
setSize(1000, 700);
setTitle("PictureEditor");
setVisible(true);
At the end execute your program with the invokeLater method!
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
new PictureEditor();
}
});
}
Summary
Basically you need a somthing to iterate through because values like integer are not saved the way you like. In my example I used a Stack and save at the beginning all pictures in it. Important is that, if you used or finished with the picture, you have to remove it (use stack.pop() for a Stack). I do not found a method where you check if the file is a picture (if it is the ImageIO catch it is bad). I wrote a method for that if you want you could use it.
This is not an answer, but I cannot paste that much code into a comment.
I would change your code to something along the lines of this piece of code. This seperates the image loading from the gui updating logic (like adding mousehandlers and the like, I pasted only image loading code).
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Arrays;
import java.util.Iterator;
import javax.imageio.ImageIO;
public class ImageLoader
{
public static class ImageContainer
{
BufferedImage bg = null;
BufferedImage scaled;
}
Iterator<File> imageFiles = Arrays.asList(
new File("D:\\New folder").listFiles()).iterator();
public ImageContainer nextImage(Dimension dimensionToFit) throws Exception
{
ImageContainer c = new ImageContainer();
if (imageFiles.hasNext())
{
File file = imageFiles.next();
//you might not need this, if only images are in this directory
if(file.isDirectory())
return null;
c.bg = ImageIO.read(file);
c.scaled = getScaledInstanceToFit(c.bg, dimensionToFit);
return c;
}
else
return null;
}
private BufferedImage getScaledInstanceToFit(BufferedImage bg,
Dimension dimensionToFit)
{
//do the risizing
}
}
This is not yet optimized though.