source: main/trunk/greenstone3/src/java/org/greenstone/applet/GsdlCollageApplet/DisplayImages.java@ 38881

Last change on this file since 38881 was 38881, checked in by anupama, 2 months ago

It was hard to solve why GsdlCollageApplet didn't work as well when run as an application. There were two issues. 1. The order of creating the applet/application matters (it needs a size). This mattered for bypassing createImage returning null in DisplayImages.java at the start. 2. Once the application finally appeared, no longer bogged down by a null pointer exception since before it finished initialising, the display_thread and download_thread were null. It was very basic. The main() method added to run the applet as an application was never calling the start() method. Only init() got called. An applet init(), then start() are automatically called by the browser/appletviewer, and I presume when the user quits the applet's browser window, that an actual applet stop() and destroy() are called. However, as the Phind applet only had init() and no start() or stop(), I had blindly imitated its main() and custom application constructor, which only ever called init(). So once I called start(), the download_thread and display_thread were both instantiated and the applet started working when run as an application at last! I also now call stop() on WindowClosing to do the cleanup. So this is proof of concept. Applet mode of GsdlCollageApplet run through the appletviewer would display the applet window and present an infinite Downloading... message, but be unable to download images due to security exceptions. The application run through the commandline is able to now download the images. So no security exception, oddly enough. Is the difference because appletviewer has sandbox/security restrictions? Webswing running GsdlCollageApplet is still stuck with the original null pointer exception: the window does not display early enough for the size to be set and displayimages to start. Maybe there's an OnShow event handler where I can instantiate the displayImages thread. But fingers crossed, I may be able to get Webswing to run the GsdlCollageApplet as an application. That will be the next step. Further problems remain: GS2 never gave the applet the URL to the Image browsing classifier CL2.3, but to the actual Collage classifier (CL3.1). I have to give it the CL2.3 classifier, because GS2's image directory is straighforwardly located. So more thinking is required on that, among other outstanding issues.

File size: 14.5 KB
Line 
1package org.greenstone.applet.GsdlCollageApplet;
2
3import java.applet.*;
4import java.awt.*;
5import java.awt.image.*;
6import java.awt.geom.*;
7import java.util.*;
8
9/**
10 * @author Katrina Edgar
11 * @author David Bainbridge
12 *
13 * Retrieves images from the download thread, determines an appropriate position
14 * for thes images onscreen ensuring maximum whitespace coverage and minimal overlap
15 * when possible. Draws images using advanced image processing techniques when applicable,
16 * such as fading the edges of an image and discolouring backgrounds. Also re-uses images
17 * from those that have previously been displayed, or are aging onscreen, in order to
18 * to create movement when no new images have been downloaded. */
19public class DisplayImages extends Thread {
20
21
22 /** Will fire a removal operation when 4 images in the collage overlap a single area */
23 static final int NO_IMAGES_OF_OVERLAP = 4;
24
25 /** To determine if there are several images overlapped, can remove the
26 * layers underneath to save time in repainting */
27 boolean overlap = false;
28
29 /** Refers to download thread */
30 DownloadImages download_images_ = null;
31
32 /** Refers to applet */
33 GsdlCollageApplet app_ = null;
34
35 /** Applets width on screen */
36 public static int app_x_dim_ = 0;
37
38 /** Applets height on screen */
39 public static int app_y_dim_ = 0;
40
41 /** Background colour of the applet screen */
42 protected Color bgcolor_ = null;
43
44 /** Indicates whether java2 functionality should be used <br>
45 * If true will allow advanced image processing techniques to occur,
46 * such as fading and colouring using pixel manipulation <br>
47 * If false, images will maintain an alpha value of 1 (appear solid),
48 * newer images will simply be pasted on top of existing images <br> */
49 protected boolean is_java2_ = false;
50
51
52 /** Holds images currently on display in the applet */
53 protected Vector inuse_ = null;
54
55 /** Holds images ready to be used */
56 protected Vector inuse_ready_ = null;
57
58 /** Holds previously displayed images for re-use */
59 protected Vector notinuse_ = null;
60
61 protected Image screen_buffer_ = null;
62 protected Graphics screen_graphic_ = null;
63 protected Image finished_buffer_ = null;
64 protected Graphics finished_graphic_ = null;
65
66 Thread next_frame_ ;
67
68 String dots[] = new String[]{" ",".","..","...","....",".....","......"};
69 int dots_nums=0;
70 boolean start_paint = false;
71 /** Used to determine where to place new images on the applet to optimize
72 * whitespace coverage <br>
73 * A co-ordinate in the applet has a value of zero if it is whitespace,
74 * one if it is covered by one image, two if it is covered by two images,
75 * and so on. New images will be placed such that they cover the largest
76 * area of whitespace (zero valued co-ordinates) */
77 public static int [] [] used_space = null;
78
79
80 /**
81 * Starts the display images thread. Initialises variables using parameters and
82 * static values. Creates the blank applet screen, initialises the used space
83 * 2D array to indicate that there are no images onscreen
84 *
85 * @param app the applet to display the images on
86 * @param download_images thread from which to retrieve downloaded images
87 * @param is_java2 whether advanced image processing techniques should be used
88 * @param bgcolor the background colour of the applet screen */
89 public DisplayImages(GsdlCollageApplet app, DownloadImages download_images,
90 boolean is_java2, Color bgcolor)
91 {
92 super("DisplayImages");
93
94 final int xDim_fallback = 600;
95 final int yDim_fallback = 300;
96
97 // parameters saved locally
98 app_ = app;
99 is_java2_ = is_java2;
100 bgcolor_ = bgcolor;
101
102 inuse_ = new Vector();
103 notinuse_ = new Vector();
104 inuse_ready_ = new Vector();
105 download_images_ = download_images;
106 // sets width and height
107 if (is_java2_)
108 {
109 //app_x_dim_ = (app_.getWidth() == 0) ? xDim_fallback : app_.getWidth();
110 //app_y_dim_ = (app_.getHeight() == 0) ? yDim_fallback : app_.getHeight();
111 app_x_dim_ = app_.getWidth();
112 app_y_dim_ = app.getHeight();
113
114 System.err.println("@@@ xDim: " + app_x_dim_);
115 System.err.println("@@@ yDim: " + app_y_dim_);
116 }
117 else
118 {
119 app_x_dim_ = xDim_fallback;
120 app_y_dim_ = yDim_fallback;
121 }
122
123 // creates initial screen
124 screen_buffer_ = app_.createImage(app_x_dim_, app_y_dim_);
125 if(screen_buffer_ == null) {
126 System.err.println("### why is screen_buffer_ null?");
127 }
128 screen_graphic_ = screen_buffer_.getGraphics();
129 screen_graphic_.setColor(bgcolor_);
130 screen_graphic_.fillRect(0,0,app_x_dim_,app_y_dim_);
131
132 finished_buffer_ = app_.createImage(app_x_dim_, app_y_dim_);
133 finished_graphic_ = finished_buffer_.getGraphics();
134
135 // initialises used space array to indicate an empty screen
136 used_space = new int [app_x_dim_][app_y_dim_];
137 for (int n=0; n < app_x_dim_; n++)
138 for (int m=0; m < app_y_dim_; m++)
139 used_space[n][m] = 0;
140
141 next_frame_ = new Thread(new Runnable(){
142 public void run() {
143
144 Thread curr_thread = Thread.currentThread();
145
146 while (curr_thread == next_frame_) {
147 try {
148 Runtime rt = Runtime.getRuntime();
149 //System.out.println("total: "+rt.totalMemory());
150 //System.out.println("free: "+rt.freeMemory());
151 rt.gc();
152 //System.out.println("**************next frame...");
153 next_frame();
154 Thread.sleep(app_. refreshDelay_);
155
156 curr_thread = Thread.currentThread();
157 } catch (Exception e) {
158 e.printStackTrace();
159 break;
160 }
161 }
162
163
164 }
165
166
167 });
168
169 next_frame_.start();
170
171
172 }
173
174 /** Determines what the user has clicked on in the applet, either an image or whitespace
175 * @param x the x co-ordinate of the mouse
176 * @param y the y co-ordinate of the mouse
177 * @return the image that the user has clicked on or null if the user has clicked whitespace */
178 public CollageImage clickedOnImage(int x, int y)
179 {
180 if (app_.verbosity() > 1)
181 {
182 System.err.print("Checking for clicked on image: ("+x+","+y+")");
183 }
184
185
186 // checks from last image down, as last images place will be at the top of the collage
187 for (int i= inuse_.size() - 1; i >= 0; i--)
188 {
189 CollageImage collage_image = (CollageImage)inuse_.elementAt(i);
190 if (collage_image.inside(x,y))
191 {
192 return collage_image;
193 }
194 }
195 // no image at these co-ordinates, just whitespace
196 return null;
197 }
198
199 /** Generates the images onscreen.
200 * Loops through the vector of currently displayed images and draws each one in turn.
201 * If the image is being drawn for the first time, its position will be determined
202 * and its alpha channel set as solid prior to drawing. <br>
203 * Drawing of the image will depend on whether or not java2 is enabled. If so then
204 * the image will be processed so that fading occurs with age, so that the edges
205 * fade faster than the rest of the image and so that white images are slightly
206 * discoloured to allow distinction. If java2 is not enabled, new images will simply
207 * be pasted on top of existing images without any special effects occuring<br>
208 * This function also deletes old images. If java2 is enabled then images are deleted
209 * once they have faded to a suitably low alpha value. If java2 is not enabled then
210 * images will be removed once there are greater than 25 images onscreen, to ensure
211 * the applet cannot be overloaded. */
212 public void display_collage()
213 {
214
215 // if there is nothing new to add
216 if (inuse_.size()==0) return;
217
218 // otherwise need to re-generate images
219 if (app_.verbosity() >= 2)
220 {
221 //system.err.println("Regenerating images");
222 }
223
224 // get each image currently onscreen inturn
225 for (int i=0; i<inuse_.size();)
226 {
227 CollageImage collage_image = (CollageImage)inuse_.elementAt(i);
228
229 if (!collage_image.isValid()){
230 continue;
231 }
232
233 int[] pixels = null;
234 // the first time the image is painted, determine its position and size
235 if (collage_image.fresh == true)
236 {
237 collage_image.process();
238 }
239
240 // advanced image processing may be used
241 if (is_java2_)
242 {
243 // conducts fading and colouring of image
244 pixels = collage_image.handlepixels(inuse_.size()-i);
245 }
246
247 if (collage_image.fresh) {
248 collage_image.fresh = false;
249 }
250
251
252 // if we remove when images have faded too much
253 if (is_java2_) {
254 if (collage_image.checkFaded(pixels)|| overlap)
255 {
256 overlap = false;
257
258 CollageImage removed_image = (CollageImage)inuse_.elementAt(i);
259 //System.out.println(removed_image.name_ + "is removed");
260 inuse_.remove(i);
261 // indicates space for this image is no longer used
262 for (int n = removed_image.xl_; n < (removed_image.xl_ + removed_image.image_x_dim_); n++)
263 for (int m = removed_image.yt_; m < (removed_image.yt_ + removed_image.image_y_dim_); m++)
264 if(used_space[n][m] != 0) {
265 used_space[n][m]--;
266 if (used_space[n][m] > NO_IMAGES_OF_OVERLAP)
267 overlap = true;
268 }
269
270 // sets the image as fresh and adds it to the vector of images previously seen
271 removed_image.fresh = true;
272 notinuse_.addElement(removed_image);
273 }
274 else{
275 i++;
276 }
277 }
278 else
279 if (inuse_.size() > 25 || overlap) {
280 overlap = false;
281
282 CollageImage removed_image = (CollageImage)inuse_.elementAt(i);
283 inuse_.remove(i);
284
285 // indicates space for this image is no longer used
286 for (int n = removed_image.xl_; n < (removed_image.xl_ + removed_image.image_x_dim_); n++)
287 for (int m = removed_image.yt_; m < (removed_image.yt_ + removed_image.image_y_dim_); m++)
288 if(used_space[n][m] != 0) {
289 used_space[n][m]--;
290 if (used_space[n][m] > NO_IMAGES_OF_OVERLAP)
291 overlap = true;
292 }
293
294 // sets the image as fresh and adds it to the vector of images previously seen
295 removed_image.fresh = true;
296 notinuse_.addElement(removed_image);
297 }
298 else{
299 i++;
300 }
301
302 }
303 }
304
305
306 /** Alters the images currently on display in the applet <br>
307 * Changes are prioritised in the following way:
308 * 1. If there are images that have been downloaded and are yet to be displayed
309 * they will be added to the list of images in use. <br>
310 * 2. Otherwise if there are images that have previously been displayed but
311 * are not currently on the applet screen, re-use one of these images. <br>
312 * 3. Otherwise if there are any images on screen at all, take the oldest and
313 * repaint it as the newest. <br>
314 * Then the collage is asked to display and repaint with the new image set. */
315
316 public void next_frame()
317 {
318 double random = Math.random();
319
320
321 if (inuse_ready_.size() > 0){
322 int pos = (int) ((inuse_ready_.size() - 1) * random);
323 CollageImage collage_image = (CollageImage) inuse_ready_.remove(pos);
324 inuse_.addElement(collage_image);
325 }
326 else if (notinuse_.size()>0)
327 {
328 int position = (int) ((notinuse_.size() - 1) * random);
329
330 CollageImage collage_image = (CollageImage)notinuse_.elementAt(position);
331 notinuse_.remove(position);
332 inuse_.addElement(collage_image);
333
334 if (app_.verbosity()>3)
335 {
336 System.err.println("Re-using an image not on screen");
337 }
338 }
339 else{
340 if (app_.verbosity()>=4)
341 System.err.println("No images in download area");
342 }
343
344 display_collage();
345
346 }
347
348
349
350 /** Paints the applet on the screen */
351 public void paint(Graphics g)
352 {
353
354 screen_graphic_.setColor(bgcolor_);
355 screen_graphic_.fillRect(0,0,app_x_dim_,app_y_dim_);
356
357 // get each image currently onscreen inturn
358
359 for (int i=0; i < inuse_.size(); i++)
360 {
361
362 CollageImage collage_image =null;
363 try{
364 collage_image = (CollageImage)inuse_.elementAt(i);
365 start_paint = true;
366 }
367 catch(Exception e){
368 System.out.println("exception in paint");
369 break;
370 }
371 // don't paint new images yet
372 if (collage_image.fresh) {
373 if (app_.verbosity()>=1) {
374 System.err.println("doing nothing... "+ collage_image.name_ +" is fresh.");
375 }
376 }
377
378 // advanced image processing may be used
379 else if (is_java2_) {
380
381 //the alphacomposite controls the blending of these two images.
382 Graphics2D sg2d = (Graphics2D)screen_graphic_;
383 sg2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
384 sg2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
385 RenderingHints.VALUE_ANTIALIAS_ON);
386 collage_image.expand();
387 sg2d.drawImage(collage_image.image_, collage_image.af_, app_);
388 }
389 // simple image collage
390 else
391 { // add the image to the collage
392
393 screen_graphic_.drawImage(collage_image.image_,
394 collage_image.xl_, collage_image.yt_,
395 collage_image.xr_, collage_image.yb_,
396 0,0,collage_image.image_x_dim_-1,
397 collage_image.image_y_dim_-1, app_);
398 }
399
400 }
401
402
403 finished_graphic_.drawImage(screen_buffer_,0,0,app_);
404
405
406 if (finished_buffer_ != null)
407 {
408 g.drawImage(finished_buffer_, 0, 0, app_);
409 if (!start_paint){
410 g.setColor(Color.white);
411 g.setFont(new Font("font",Font.PLAIN+Font.BOLD,30));
412 g.drawString("Downloading" + dots[(dots_nums++)%dots.length],app_x_dim_/3-20,app_y_dim_/2-2);
413 }
414 }
415
416
417 }
418
419 /** Runs display thread by repeatedly calling the next frame,
420 * waiting for a specified delay period between calls */
421 public void run() {
422 try {
423
424 Thread curr_thread = Thread.currentThread();
425
426 while (curr_thread == this) {
427 if (inuse_ready_.size() >= 1){
428 Thread.sleep(1000);
429 continue;
430 }
431 CollageImage collage_image = download_images_.getCollageImage();
432
433 if (collage_image !=null){
434 inuse_ready_.addElement(collage_image);
435 }
436 curr_thread = Thread.currentThread();
437 }
438
439 } catch (Exception e) {
440 e.printStackTrace();
441 System.out.println("Display images thread is interrupted");
442 }
443
444 System.out.println("Display images thread stoped");
445
446 }
447
448}
Note: See TracBrowser for help on using the repository browser.