I am trying to serialize a Canvas instance (using the Serializable interface) on which I have painted some pixels like the following code suggests:
Canvas board = new Canvas();
Graphics g = board.getGraphics();
g.setColor(Color.BLACK);
g.drawString("txt", 10, 20);
g.dispose();
Then when I serialize board it doesn't save the pixels I've painted. I'm guessing this is because by using getGraphics() I am not saving those pixels to any instance, so I thought that perhaps I should instead paint from within the Canvas's paint() method. Would serializing the Canvas then save the modified pixels too? If not, what are my options to save/serialize a Canvas with the pixels I've modified? I am guessing I would have to serialize the Graphics object instead of the Canvas? I am new to Java graphics, any help will be greatly appreciated.
To be more clear, what I'm trying to do is have the pixels I've put on a Canvas instance saved to a file using serialization. Then later I need to reload this Canvas instance from the serialized file I saved earlier, so that when I use it on the screen I see the exact same pixels I modified just before I serialized the Canvas. I know how to serialize objects and all that. I am just unclear where all the pixels are stored.
Update1:
The way the user draws something on the screen is by left-clicking on the Canvas area. Then MouseListener calls the following method, passing along the Point object specifying the mouse xy:
private void drawAt(Point p)
{
Graphics g = board.getGraphics();
g.setColor(brushColor);
g.setFont(brushFont);
g.drawString(brushText, p.x, p.y);
g.dispose();
}
Don't serialize Canvas or any other GUI components as you'd be serializing the "View" portion of your program, a risky thing to do (high risk for serialization exceptions due to attempting to serialize and unserialize unserializable sub components) and an inefficient thing to do -- serializing large amounts of data which are built automatically by the JVM and thus don't need serialization.
Instead you will want to serialize the "Model" portion of your data, that portion which holds the logical data of your program. So if your GUI is drawn using data held by an ArrayList, or a collection of ArrayLists, or whatever data it takes, then serialize that data. Then be sure to create your GUI so that can be built using the serialized data.
Or if you need to store an image, then store an image, probably best as a loss-less png file.
Also, I suggest that you draw into a BufferedImage, that you then display that BufferedImage within the paintComponent method override of a JPanel, and that you then save and restore the image. For more on how to draw and save, please have a look at these links. The first two contain my code, the third is that of MadProgrammer's:
Save image from JPanel after draw,
Convert a Graphics2D to an Image or BufferedImage and
Paint BufferedImage on JFrame and write to File.
Related
I've read that JPanel has a double buffering system, but I've also seen people manually create their own back buffer using BufferedImage, which allows the user to add to the image before actually rendering.
How does the JPanel double buffering work, and why would someone create their own back buffer if JPanel already has double buffering? What is an example of a time where BufferedImage as your buffer would be needed/recommended?
From what I've seen it's usually because:
They are already loading an image which serves as a background image and wish to draw on top of that (they probably could just draw the image, leaving it to be hardware accelerated for future renders while drawing everything else using the same Graphics object used to call drawImage)
Because they wish to have a simple way to scale their graphics as their panel resizes with drawImage(Image, 0, 0, panelWidth, panelHeight, ImageObserver) and don't wish to do the extra work on calculating dynamic drawing coordinates for the graphics based on the panel's current dimensions (although this leads to not so good looking graphics, and if the scaled image is not cached per resize there could be performance issues as well).
Because it's old code in the days before Swing was double buffered, or people following code from old books.
The graphics of what you draw in the double buffered painting methods (like paintComponent(Graphics)) will be visible all at once when all of the relevant painting methods are complete. That being the case there's no reason to use a BufferedImage as a way to manually ensure all the Graphics get shown at once.
In what instance would I want to use ImageIcon to represent a picture file rather than an Image object? I've been searching and I've seen people say that you would use an ImageIcon object when dealing with images that will be part of the GUI, but I still don't understand the implications of this. In other words, what is the actual difference between the two object types and what situations are they each suited for?
Image is an object that represents a bitmap: an array of pixels of different colors.
Icon is an object that can draw a rectangular piece of graphics. Since it is an interface (and a simple one too), you can imagine many different types of icons: drawing predefined vector graphics, generating images on the fly etc. Therefore it is a useful abstraction and is used by Swing components (buttons, labels).
ImageIcon is an object that IS an Icon, but HAS-A Image. That is - it draws graphics based on a specific image.
When you say "why should I be using an ImageIcon instead of Image" you miss the point: in fact you are using an Image either way.
An Image is an object representing the data model of a picture. An ImageIcon is a Swing component that draws an Image on the screen, and you have to provide it with the appropriate Image to draw (either by passing in an existing Image or by giving it enough information to find and load the image).
The relationship is similar to that between a String and a JTextField; one is the representation of the data, and the other is the graphical component that draws it on the screen.
The implementation is to not hold up the Swing thread.
Images that are created from a URL, filename or byte array are preloaded using MediaTracker to monitor the loaded state of the image.
Basically, then you can set an ImageIcon for a button without actually forcing it to be loaded beforehand.
This can be seen by having a very large icon and setting the Frame's icon to this image. Once set visible, it may take a few seconds to actually appear.
Is there any possible way to put all the drawn objects into an array? This is just for a drawing game so it is possible to save all objects and load them back from this way.
Thanks if this is possible!
Take a look at Picture class - http://developer.android.com/reference/android/graphics/Picture.html
After it's being attached to the canvas, it records all drawing operations and stores it.
After you can either draw all of them on another canvas, or store/transfer the Picture to make it on another device or later.
UPD: something like this
Picture picture = new Picture();
Canvas canvas = picture.beginRecording(300, 300);
canvas.drawRect(new Rect(5, 5, 10, 10), new Paint()); // configure paint here
picture.endRecording();
picture.writeToStream(new FileOutputStream("stored_drawing.pict"));
Now you'll be able to restore this rectangle from file and draw it on any another canvas.
So generally you can wrap you user's drawing through this class and it wil store all user drawing operations.
Good luck
I`m building an android App, and i got stuck with a simple thing: How do i draw (or "add") a Canvas object, to another Canvas object, like "merging" them?
If that`s not possible, what is the best solution for doing that?
Thanks!
This depends entirely on your implementation.
If each Canvas draws objects directly from an array (of shapes, etc.) each frame, you could simply append one array to the other. This way, your Canvas does not need to be drastically altered, it only has to add one array to another (possibly an ArrayList would be the way to go here).
If the above is not the case, you may have to make some more drastic changes. When I encountered a similar problem, I created a new method called commitChanges(), which added a series of changes to an existing Canvas (adding lines on top, etc.).
I first invalidated the affected area, then created a Bitmap with the size of the Canvas: Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.RGBA_8888);.
Next, I created a canvas from that Bitmap: Canvas workingDrawing = new Canvas(bmp);.
Then, I drew everything I needed onto that new Canvas. In this case, that would be the data from one of your Canvases.
Now, in your other Canvas, you have to get the Bitmap you just drew, then draw it onto this Canvas. Like so: canvas.drawBitmap(yourDrawnBitmap, 0.0f, 0.0f, null);.
I think the difficulty you'll face is transferring the data from one Canvas to another. But, regardless of your implementation, one of the above methods should work effectively for you.
(Java)
I have a canvas that represents an animation. I want to copy the contents of the canvas to a BufferedImage so I can save the snapshot to file. Every tutorial I found on the internet said to use paint() to copy the contents; unfortunately, this would produce new, different contents in my canvas the way I have it set up. There are randomly drawn lines, for instance, which would be recalculated if I called paint(). Is there any way to save the contents of a canvas to a BufferedImage without calling paint()?
..save the contents of a canvas to a BufferedImage without calling paint()?
Draw the content to a BufferedImage prior to drawing the image to the Canvas. When it comes time to save, simply use the cached image.
And think about joining us in the 3rd millennium and using Swing components. Use JPanel & paintComponent(Graphics) instead of the Canvas & paint(Graphics).