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

Last change on this file since 38937 was 38937, checked in by anupama, 8 weeks ago

Cleaning up the code somewhat.

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