Win a copy of Murach's Python Programming this week in the Jython/Python forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic

suggestion regarding the maintainability of undo-redo states in image editing  RSS feed

 
Tarun Bolla
Ranch Hand
Posts: 89
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi,
I am developing an image editing app in java, which of-course will need undo-redo functionality.
What have i done....
Have created a State class which will contain a bufferedimage, ref to prev state, ref to next state. Then formed a linked list of states, traversing back and forth with clicks of undo and redo buttons.
So what do i want....
I have observed that bufferedimage occupies way too much memory...say 4 MB for just a medium (desktop) size image. Can you people suggest a better approach???

Thank you!!
 
Rob Spoor
Sheriff
Posts: 20893
81
Chrome Eclipse IDE Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Usually you need to store what action was taken, and how to undo that action. For instance, if the action is "fill part X with colour Y", then you need to store:
- that part X should get colour Y for redoing.
- that part X should get its original colour for undoing.

Likewise for other actions. You definitely do not need to store the old (for undoing) and new (for redoing) images, only the steps you need to move from one to the other.

As for implementing all of this yourself, you can perhaps take a look at the javax.swing.undo package. That's an existing framework you may be able to extend (by implementing your own UndoableEdit classes, probably by extending AbstractUndoableEdit).
 
Darryl Burke
Bartender
Posts: 5167
11
Java Netbeans IDE Opera
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
if the action is "fill part X with colour Y", then you need to store:
- that part X should get colour Y for redoing.
- that part X should get its original colour for undoing.


I sense some "gotcha's" when using this approach in editing all but the simplest images. Some actions (think ConvolveOp, scaling) just aren't reversible.

What I would probably do is set a limit on the number of undo-s, cache the actions and the BufferedImage as it was at the start of the undo stack.

Let's say I decided to support 20 undo-s. Then my cached image would be the image as it was 20 steps earlier. When I perform a new action, I would pop the earliest action from the stack and apply it to the cached image, and push the latest action on the stack.

To undo the last action, I would paint the cached image to the 'live' one and apply all but the last action.
 
Tarun Bolla
Ranch Hand
Posts: 89
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Darryl Burke wrote:
Let's say I decided to support 20 undo-s. Then my cached image would be the image as it was 20 steps earlier. When I perform a new action, I would pop the earliest action from the stack and apply it to the cached image, and push the latest action on the stack.

To undo the last action, I would paint the cached image to the 'live' one and apply all but the last action.

Thats exactly what i did, but its throwing heap space errors..So there isnt any efficient method other than this???

Rob Spoor wrote:
Usually you need to store what action was taken, and how to undo that action. For instance, if the action is "fill part X with colour Y", then you need to store:
- that part X should get colour Y for redoing.
- that part X should get its original colour for undoing.

So here is a scenario....I have drawn a rectangle on an image...how do i undo the rectangle??
 
Rob Spoor
Sheriff
Posts: 20893
81
Chrome Eclipse IDE Java Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hadn't thought about that... For some operations (like scaling), the only way to undo it is to go back to a previous version completely. Perhaps your approach is the best way overall.

If you're having heap space problems, you can try to use the -Xmx JVM flag. For instance, to be able to use up to 1.5GB of memory, you use -Xmx1536m. With a 32-bit JVM on Windows, that's about as much as the OS will give you. (A little experimenting has shown that my Java 6 update 26 gives me at most 1582 MB.)
 
Darryl Burke
Bartender
Posts: 5167
11
Java Netbeans IDE Opera
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Tarun Bolla wrote:
Darryl Burke wrote:
Let's say I decided to support 20 undo-s. Then my cached image would be the image as it was 20 steps earlier. When I perform a new action, I would pop the earliest action from the stack and apply it to the cached image, and push the latest action on the stack.

To undo the last action, I would paint the cached image to the 'live' one and apply all but the last action.

Thats exactly what i did, but its throwing heap space errors.


I don't think you understood my suggestion. You only need to keep two images in memory, and a List of actions. For the simplified case* of adding drawn/filled Shapes I would create a class something likeThen the editor class would hold an ArrayList<EditAction> and two images, liveImage and baseImage. Any addition of a shape would first check the list size and if 20 (or whatever) would paint the first EditAction in the List to baseImage and remove it from the list. Then the current EditAction would be painted to liveImage and added to the list.

An undo would cause the baseImage to be painted to the liveImage, followed by painting 19 (all but the last) EditAction. An index would record the present position in the list, permitting a redo.

And new action after one or more undo actions would remove the undone actions from the list.

Is my suggestion clearer now or am I still unable to express it clearly enough?

* For a more complex case which might allow e.g. loading and layering other images, scaling etc I would probably set up an enum of the various types of EditActions and an 'apply' rather than a 'paint(g2)' method. And there would have to be some logic to determine whether the action is to be performed on the baseImage or the liveImage.
 
Tarun Bolla
Ranch Hand
Posts: 89
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Darryl Burke wrote:And new action after one or more undo actions would remove the undone actions from the list

Yeah! Bruke...thats a good suggestion...so you want me to store the actions like
State1 = draw a rectangle x=30, y=40, height = 300, width = 400
State1 = draw a circle x=300, y=40, radius = 100

Darryl Burke wrote: An undo would cause the baseImage to be painted to the liveImage, followed by painting 19 (all but the last) EditAction. An index would record the present position in the list, permitting a redo.

Isn't it a lot of work for the CPU??? Take your best shot...because i am going to start the above approach right after you next reply.....Thank you
 
Tarun Bolla
Ranch Hand
Posts: 89
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Rob Spoor wrote:
If you're having heap space problems, you can try to use the -Xmx JVM flag. For instance, to be able to use up to 1.5GB of memory, you use -Xmx1536m. With a 32-bit JVM on Windows, that's about as much as the OS will give you. (A little experimenting has shown that my Java 6 update 26 gives me at most 1582 MB.)

Hi Rob,
Increasing the heap size is one way...but i want a pretty app... increasing heap size would make it a hog...that is why i am asking for workarounds...I have never seen mspaint occupying so much memory....I have seen my app consuming 100MB for just two snapshots and two to three line draws on a sheet consisting of full screen snapshot(taken help of Robot class). Any more suggestions?
 
Tarun Bolla
Ranch Hand
Posts: 89
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Bruke...I just realized that drawing 19 shapes isnt much of a work for CPU...I am starting work....
 
It is sorta covered in the JavaRanch Style Guide.
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!