Adding a Background Image to MapView

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Adding a Background Image to MapView

theworldbright
Hello again. Dimitry has posted here what features should come next, and I thought I would attempt the easiest – the addition of background images. Currently, I am poking around the source code to see how the a image is rendered on a node and how the solid background color is rendered, as I believe the adding of background images involves the combination of these two processes.

How an Image is Rendered on a Node

1. Right-clicking a node > Add Image… triggers the AddExternalImageAction
2. The AddExternalImageAction calls a ImagePreview, which is a popup in which the user can select a file.
3. A reference to the selected file is stored as a ExternalResource.

I am somewhat lost in figuring out how the selected file reference is actually stored in the NodeModel and how the image is actually rendered on a node.

Additional Questions

1. MenuBuilder.java – lines 345 ~ 357 consist of two methods createMenu(final String name) and createMenuItem(final String name) that don’t seemed to be called by anything (according to Eclipse’s call hierarchy). What is the purpose of these two methods?
2. What is the difference between Edit > Node Core > Image by choice or link and right-click a node > Add Image....? I see how the former is called by SetImageByFileChooserAction and the latter is called by AddExternalImageAction – both classes are subclasses of AFreeplaneAction. Furthermore, the latter uses ImagePreview which essentially is a BitmapImagePreview but overrides one method – updateView(final File file). What is the purpose of having these two similar functions?

Once I get my head around the questions I have above, I will outline the general approach I plan to take to add this feature.

For future reference here are my notes on how the solid background colour is rendered:

1. The menu_action node with the action attribute referencing MapBackgroundColorAction, a subclass of AFreeplaneAction, in mindmapmodemenu.xml tells the MenuBuilder to instantiate a JMenuItem that will call that action on click.
2. Calling the action generates a JColorChooserDialog where the user can select a solid background color.
3. The selected color gets passed to a MapStyle instance, which changes the background color in the MapStyleModel through an IActor implementation.
4. The MapView retrieves the value of the background color in the MapStyleModel and renders it to its content pane through its setBackground method.
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Adding a Background Image to MapView

Dimitry Polivaev
Administrator
> Currently, I am poking around the source code to see how the a image is rendered on a node
> and how the solid background color is rendered, as I believe the adding of background images
> involves the combination of these two processes.
>
> How an Image is Rendered on a Node
>
> 1. Right-clicking a node > Add Image… triggers the AddExternalImageAction
> 2. The AddExternalImageAction calls a ImagePreview, which is a popup in which the user can select a
> file.
> 3. A reference to the selected file is stored as a ExternalResource.
>
> /I am somewhat lost in figuring out how the selected file reference is actually stored in the
> NodeModel and how the image is actually rendered on a node./

For selecting, storing and painting map background image we need an action which displays "edit
background image" dialog. In this dialog it should be possible to select the image file.

For storing and accessing the path to the image file I suggest to use

org.freeplane.features.styles.MapStyle.setProperty(MapModel, String, String)
org.freeplane.features.styles.MapStyle.getProperty(MapModel, String)

The first method triggers the undo chain automatically.

The image should be painted from method MapView.paintComponent(java.awt.Graphics) overriding the
correspondent JComponent method.

Its center should always be at the center point of the component obtained by call
getRoot().getMainView() and representing the core part of the root node.

> Additional Questions
>
> 1. MenuBuilder.java – lines 345 ~ 357 consist of two methods createMenu(final String name) and
> createMenuItem(final String name) that don’t seemed to be called by anything (according to Eclipse’s
> call hierarchy). What is the purpose of these two methods?

No idea, may be they are not needed any more

> 2. What is the difference between Edit > Node Core > Image by choice or link and right-click a node
>  > Add Image....? I see how the former is called by SetImageByFileChooserAction and the latter is
> called by AddExternalImageAction – both classes are subclasses of AFreeplaneAction. Furthermore, the
> latter uses ImagePreview which essentially is a BitmapImagePreview but overrides one method –
> updateView(final File file). What is the purpose of having these two similar functions?

Node core image creates a html element image inside the node core. It currently has no SVG support.
External image is painted below the node core and its size can be changed using mouse.

> Once I get my head around the questions I have above, I will outline the general approach I plan to
> take to add this feature.
>
> For future reference here are my notes on how the solid background colour is rendered:
>
> 1. The menu_action node with the action attribute referencing MapBackgroundColorAction, a subclass
> of AFreeplaneAction, in mindmapmodemenu.xml tells the MenuBuilder to instantiate a JMenuItem that
> will call that action on click.
> 2. Calling the action generates a JColorChooserDialog where the user can select a solid background
> color.
> 3. The selected color gets passed to a MapStyle instance, which changes the background color in the
> MapStyleModel through an IActor implementation.
> 4. The MapView retrieves the value of the background color in the MapStyleModel and renders it to
> its content pane through its setBackground method.

It seems to be right. However I am going to switch to ribbons soon, there we become another xml file
for menu structure definition.

Regards, Dimitry
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Adding a Background Image to MapView

theworldbright
In reply to this post by theworldbright
Thank you for your help, Dimitry.

I am still confused how an image is rendered on a node. According to the comments the method paste(final URI uri, final NodeModel node) attaches an image URI to a node; however, where in the code is that image URI rendered? I cannot seem to find a method such as Graphics.drawImage() that renders the image onto the JComponent.

Otherwise here is my plan:

1) Create a new menu item under Map Background as follows:

Menu Layout

2) Create a new class called MapBackgroundImageAction which extends AFreeplaneAction. Clicking the Map Background > Image will call this new action.
3) The MapBackgroundImageAction will open up a JFileChooser with a ImagePreviewer object set as an accessory. If a background image was already previously set, the ImagePreviewer will show that as the default. There will be three buttons on the bottom: cancel, clear, and ok.
4) Retrieve an absolute URI, pointing to the new background image.
5) The MapBackgroundImageAction will set the backgroundImageURI property to the new image URI value.
6) Override JComponent’s paintComponent method in MapView. Retrieve the backgroundImageURI property and then read it using ImageIO.read().
7) Retrieve the MainView’s X and Y positions and use it to render the background image using drawImage() in the centre.

Concerns/Things to Do

1) I assume Ribbons will somehow affect step 1: I still haven’t checked what exactly Ribbons is.
2) Figure out how the exporting of files work so that the background image can be included.
3) I am still getting my head around how scripting works. If I add an additional property such as backgroundImageURI, do I have to create additional methods so that users can manipulate this property using scripts?
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Adding a Background Image to MapView

Dimitry Polivaev
Administrator
> I am still confused how an image is rendered on a node. According to the comments the method
> paste(final URI uri, final NodeModel node) attaches an image URI to a node; however, where in the
> code is that image URI rendered? I cannot seem to find a method such as Graphics.drawImage() that
> renders the image onto the JComponent.

It is there, it's java.awt.Graphics.drawImage combined with javax.imageio.ImageIO.read

Dimitry
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Adding a Background Image to MapView

theworldbright
In reply to this post by theworldbright
I got it working but I still need to do some adjustments such as adding an icon to the menu item and making changes to the image preview (as I am currently just directly reusing the ImagePreview class).

Map Background

I still don't understand how to centre the image using getRoot().getMainView(). Currently, I am just using g.drawImage(image, (getWidth() - image.getWidth())/2, (getHeight() - image.getHeight())/2, null); to draw the image, but I can see how its probably a bad idea since the image gets redrawn so that its centre is aligned with the currently selected node. However, the no combination of the following seemed to centre the image (mainView = this.getRoot().getMainView()):

                System.out.println("Main View Width: " + mainView.getWidth());
                System.out.println("Main View X: " + mainView.getX());
                System.out.println("Root View X: " + this.getRoot().getX());
                System.out.println("Root View Delta X: " +  this.getRoot().getDeltaX());
                System.out.println("Root View Width: " +  this.getRoot().getWidth());
                System.out.println("Anchor Center X: " +  getAnchorCenterPoint().x);
                System.out.println("------------------");
                System.out.println("Main View Height: " + mainView.getWidth());
                System.out.println("Main View Y: " + mainView.getY());
                System.out.println("Root View Y: " + this.getRoot().getY());
                System.out.println("Root View Delta y: " +  this.getRoot().getDeltaY());
                System.out.println("Root View Height: " +  this.getRoot().getWidth());
                System.out.println("Anchor Center Y: " +  getAnchorCenterPoint().y);

In the end, I did not need to know how an image on a node was rendered, but it would still be nice to know. I agree that it should just be a simple search but I can’t seem to find any matches that look like what I am searching for. Here are the search results for “drawImage”:

- com.thebuzzmedia.imgscalr.Scalr.java (These are scaling operations)
        - Line 1640
        - Line 1754
        - Line 1804
org.freeplane.core.ui.components.BitmapViewerComponent.java (This is a pop up, so I’m sure its not this)
        - Line 194
org.freeplane.features.clipboard.mindmapmode.MClipboardController.java (I thought it was here but it didn’t print anything to the log files when I put a out.println() statement right above the line).
        - Line 395
org.freeplane.features.print.Preview.java (This is also a pop up for the print preview)
        - Line 105
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Adding a Background Image to MapView

theworldbright
In reply to this post by theworldbright
Dimitry has answered all my questions above via Skype. I have sent in a pull request for this feature through git hub. There is a slight modification from the original plan: instead of adding a clear button in the JFileChooser, I have added a separate "clear" action to the menu bar. Hence, the MapBackgroundImageAction menu item is now nested in an additional submenu. A potential problem is that the file must be saved in order for the background image to appear.
Loading...