001: /*
002: * Javu WingS - Lightweight Java Component Set
003: * Copyright (c) 2005-2007 Krzysztof A. Sadlocha
004: * e-mail: ksadlocha@programics.com
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or (at your option) any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: */
020:
021: package com.javujavu.javux.wings;
022:
023: import java.awt.Graphics;
024: import java.awt.Image;
025: import java.awt.Insets;
026: import java.awt.Label;
027: import java.awt.MediaTracker;
028: import java.awt.Rectangle;
029: import java.awt.Toolkit;
030: import java.awt.image.ImageObserver;
031: import java.net.URL;
032:
033: /**
034: * This class extends functionality of <code>java.awt.Image</code>.
035: * <code>WingImage</code> contains <code>java.awt.Image</code> object as
036: * source image and following parameters describing how the image is rendered.
037: * <ul>
038: * <li>source rectangle - describing used area of source image,
039: * <li>optional stretch insets - describing stretch margin,
040: * <li>optional tile mode - telling if the image is stretched or tiled,
041: * <li>optional alpha - making the image transparent as a whole
042: * </ul>
043: * <br>
044: * <b>This is one of the core WingS classes required by all the components</b><br>
045: * <br>
046: * <b>This class is thread safe.</b>
047: **/
048: public class WingImage {
049: /** no tile, the image is stretched along X and Y axis */
050: public static final int NO_TILE = 0;
051: /** the image is tiled along X and Y axis starting from the northwest corner*/
052: public static final int TILE_NW = 1;
053: /** the image is stretched along X axis and tiled along Y axis starting from the north border*/
054: public static final int TILE_N = 2;
055: /** the image is tiled along X and Y axis starting from the northeast corner*/
056: public static final int TILE_NE = 3;
057: /** the image is stretched along Y axis and tiled along X axis starting from the east border*/
058: public static final int TILE_E = 4;
059: /** the image is tiled along X and Y axis starting from the southeast corner*/
060: public static final int TILE_SE = 5;
061: /** the image is stretched along X axis and tiled along Y axis starting from the south border*/
062: public static final int TILE_S = 6;
063: /** the image is tiled along X and Y axis starting from the south-west corner*/
064: public static final int TILE_SW = 7;
065: /** the image is stretched along Y axis and tiled along X axis starting from the west border*/
066: public static final int TILE_W = 8;
067:
068: protected/*final*/Image image;
069: protected/*final*/Rectangle src;
070: protected Insets stretch;
071: protected int tile;
072: protected int alpha;
073: protected Image stretchBuffer;
074:
075: /**
076: * Creates a new <code>WingImage</code>
077: * calculating source rectangle in the following way:<br>
078: * area of the source image is threat as a grid with the specified
079: * cell size, the source rectangle is an area covering specified
080: * cell of the grid counting from the top left corner<br>
081: * All other properties are derived from the source image
082: * @param image source image
083: * @param part grid cell number
084: * @param width grid cell width
085: * @param height grid cell height
086: */
087: public WingImage(WingImage image, int part, int width, int height) {
088: this (
089: image,
090: (width > 0 && image.src.width >= width) ? (width * (part % (image.src.width / width)))
091: : 0,
092: (width > 0 && image.src.width >= width) ? (height * (part / (image.src.width / width)))
093: : 0, width, height);
094: }
095:
096: /**
097: * Creates a new <code>WingImage</code> using the whole area of the source image<br>
098: * All other properties are derived from the source image
099: * @param image source image
100: */
101: public WingImage(WingImage image) {
102: this (image, 0, 0, image.src.width, image.src.height);
103: }
104:
105: /**
106: * Creates a new <code>WingImage</code> using specified area of the source image<br>
107: * All other properties are derived from the source image
108: * @param image source image
109: * @param x x coordinate
110: * @param y y coordinate
111: * @param width width
112: * @param height height
113: */
114: public WingImage(WingImage image, int x, int y, int width,
115: int height) {
116: this (image.image, image.src.x + x, image.src.y + y, width,
117: height);
118: setStretch(image.stretch);
119: this .tile = image.tile;
120: this .alpha = image.alpha;
121: }
122:
123: /**
124: * Creates a new <code>WingImage</code> using the whole area of the source image<br>
125: * @param image source image
126: */
127: public WingImage(Image image) {
128: this (image, 0, 0, image.getWidth(null), image.getHeight(null));
129: }
130:
131: /**
132: * Creates a new <code>WingImage</code> using specified area of the source image<br>
133: * @param image source image
134: * @param x x coordinate
135: * @param y y coordinate
136: * @param width width
137: * @param height height
138: */
139: public WingImage(Image image, int x, int y, int width, int height) {
140: this .image = image;
141: this .src = new Rectangle();
142:
143: if (x < 0 || y < 0 || width <= 0 || height <= 0
144: || x + width > image.getWidth(null)
145: || y + height > image.getHeight(null))
146: return;
147:
148: src.setBounds(x, y, width, height);
149: }
150:
151: /**
152: * Returns the source rectangle
153: * @return used source rectangle
154: */
155: public Rectangle getSourceRect() {
156: return src;
157: }
158:
159: /**
160: * Returns the stretch margin
161: * @return the stretch margin
162: */
163: public Insets getStretch() {
164: return stretch;
165: }
166:
167: /**
168: * Returns the tile mode
169: * @return the tile mode
170: */
171: public int getTile() {
172: return tile;
173: }
174:
175: /**
176: * Sets the stretch margin
177: * @param stretch new stretch margin
178: */
179: public void setStretch(Insets stretch) {
180: if (stretch == null) {
181: this .stretch = stretch;
182: } else {
183: //TODO move to draw stretch
184: if (src.width == 0 || src.height == 0 || stretch.left < 0
185: || stretch.right < 0 || stretch.top < 0
186: || stretch.bottom < 0
187: || stretch.left + stretch.right > src.width
188: || stretch.top + stretch.bottom > src.height)
189: return;
190: this .stretch = stretch;
191: }
192: }
193:
194: /**
195: * Sets the tile mode
196: * @param tile new tile mode
197: */
198: public void setTile(int tile) {
199: this .tile = tile;
200: }
201:
202: /**
203: * Returns value of the alpha property
204: * @return alpha value
205: */
206: public int getAlpha() {
207: return alpha;
208: }
209:
210: /**
211: * Sets the alpha property
212: * @param alpha a new alpha value in the range 0-255
213: */
214: public void setAlpha(int alpha) {
215: this .alpha = alpha;
216: }
217:
218: /**
219: * Returns width of the source rectangle
220: * @return width of the source rectangle
221: */
222: public int getWidth() {
223: return src.width;
224: }
225:
226: /**
227: * Returns height of the source rectangle
228: * @return height of the source rectangle
229: */
230: public int getHeight() {
231: return src.height;
232: }
233:
234: /**
235: * Returns source image
236: * @return source image
237: */
238: public Image getImage() {
239: return image;
240: }
241:
242: /**
243: * Draws the image.
244: * @param g destination graphics
245: * @param x the x coordinate.
246: * @param y the y coordinate.
247: * @param o object to be notified as more of the image is available.
248: * @return <code>false</code> if the image pixels are still changing;
249: * <code>true</code> otherwise.
250: */
251: public boolean drawImage(Graphics g, int x, int y, ImageObserver o) {
252: Object prevAlpha = WingToolkit.the().mulComposite(g, alpha);
253: boolean r = g.drawImage(image, x, y, x + src.width, y
254: + src.height, src.x, src.y, src.x + src.width, src.y
255: + src.height, o);
256: WingToolkit.the().clrComposite(g, prevAlpha);
257: return r;
258: }
259:
260: /**
261: * Draws the image scaling if necessary
262: * using its stretch margin and tile mode.
263: * @param g destination graphics
264: * @param x the x coordinate.
265: * @param y the y coordinate.
266: * @param w the width of the rectangle.
267: * @param h the height of the rectangle.
268: * @param o object to be notified as more of the image is available.
269: * @return <code>false</code> if the image pixels are still changing;
270: * <code>true</code> otherwise.
271: */
272: public boolean drawImage(Graphics g, int x, int y, int w, int h,
273: ImageObserver o) {
274: Insets stretch = this .stretch;
275: boolean r;
276: Object prevAlpha = WingToolkit.the().mulComposite(g, alpha);
277:
278: if (stretch == null) {
279: r = drawTileImage(g, image, x, y, x + w, y + h, src.x,
280: src.y, src.x + src.width, src.y + src.height, tile,
281: o);
282: } else {
283: r = drawStretchImage(g, image, x, y, w, h, src.x, src.y,
284: src.width, src.height, stretch, tile, o);
285: }
286: WingToolkit.the().clrComposite(g, prevAlpha);
287: return r;
288: }
289:
290: public boolean drawSmoothImage(Graphics g, int x, int y, int w,
291: int h, ImageObserver o) {
292: if (w <= 0 || h <= 0)
293: return true;
294: Insets stretch = this .stretch;
295: int tile = this .tile;
296: boolean r;
297: Object prevAlpha = WingToolkit.the().mulComposite(g, alpha);
298: if (stretch == null) {
299: if (tile == NO_TILE) {
300: r = WingToolkit.the().drawSmoothImage(g, this , x, y, w,
301: h, o);
302: } else {
303: r = drawTileImage(g, image, x, y, x + w, y + h, src.x,
304: src.y, src.x + src.width, src.y + src.height,
305: tile, o);
306: }
307: } else {
308: r = drawStretchImage(g, image, x, y, w, h, src.x, src.y,
309: src.width, src.height, stretch, tile, o);
310: }
311: WingToolkit.the().clrComposite(g, prevAlpha);
312: return r;
313: }
314:
315: private static boolean drawStretchImage(Graphics g, Image src,
316: int x, int y, int width, int height, int srcX, int srcY,
317: int srcWidth, int srcHeight, Insets stretch, int title,
318: ImageObserver o) {
319: if (width <= 0 || height <= 0)
320: return true;
321:
322: int left = stretch.left;
323: int right = stretch.right;
324: int top = stretch.top;
325: int bottom = stretch.bottom;
326: if (left + right > width) {
327: left = ((left * width * 10) / (left + right)) / 10;
328: right = width - left;
329: }
330: if (top + bottom > height) {
331: top = ((top * height * 10) / (top + bottom)) / 10;
332: bottom = height - top;
333: }
334:
335: boolean done = true;
336:
337: // ##
338: // #
339: if (left > 0 && top > 0) {
340: done &= g.drawImage(src, x, y, x + left, y + top, srcX,
341: srcY, srcX + left, srcY + top, o);
342: }
343: // #
344: // ##
345: if (left > 0 && bottom > 0) {
346: done &= g.drawImage(src, x, y + height - bottom, x + left,
347: y + height, srcX, srcY + srcHeight - bottom, srcX
348: + left, srcY + srcHeight, o);
349: }
350: // ##
351: // #
352: if (right > 0 && top > 0) {
353: done &= g.drawImage(src, x + width - right, y, x + width, y
354: + top, srcX + srcWidth - right, srcY, srcX
355: + srcWidth, srcY + top, o);
356: }
357: // #
358: // ##
359: if (right > 0 && bottom > 0) {
360: done &= g.drawImage(src, x + width - right, y + height
361: - bottom, x + width, y + height, srcX + srcWidth
362: - right, srcY + srcHeight - bottom,
363: srcX + srcWidth, srcY + srcHeight, o);
364: }
365: // #
366: // #
367: if (left > 0) {
368: done &= drawTileImage(g, src, x + 0, y + top, x + left, y
369: + height - bottom, srcX, srcY + top, srcX + left,
370: srcY + srcHeight - bottom, title, o);
371: }
372: // #
373: // #
374: if (right > 0) {
375: done &= drawTileImage(g, src, x + width - right, y + top, x
376: + width, y + height - bottom, srcX + srcWidth
377: - right, srcY + top, srcX + srcWidth, srcY
378: + srcHeight - bottom, title, o);
379: }
380: // ##
381: //
382: if (top > 0) {
383: done &= drawTileImage(g, src, x + left, y + 0, x + width
384: - right, y + top, srcX + left, srcY, srcX
385: + srcWidth - right, srcY + top, title, o);
386: }
387: //
388: // ##
389: if (bottom > 0) {
390: done &= drawTileImage(g, src, x + left,
391: y + height - bottom, x + width - right, y + height,
392: srcX + left, srcY + srcHeight - bottom, srcX
393: + srcWidth - right, srcY + srcHeight,
394: title, o);
395: }
396:
397: if (stretch.left + stretch.right < width
398: && stretch.top + stretch.bottom < height) {
399: done &= drawTileImage(g, src, x + left, y + top, x + width
400: - right, y + height - bottom, srcX + left, srcY
401: + top, srcX + srcWidth - right, srcY + srcHeight
402: - bottom, title, o);
403: }
404: return done;
405: }
406:
407: /**
408: * sxe= sxo+width without -1 !
409: */
410: private static boolean drawTileImage(Graphics g, Image src,
411: int destXo, int destYo, int destXe, int destYe, int srcXo,
412: int srcYo, int srcXe, int srcYe, int tile, ImageObserver o) {
413: if (tile == NO_TILE) {
414: return g.drawImage(src, destXo, destYo, destXe, destYe,
415: srcXo, srcYo, srcXe, srcYe, o);
416: }
417:
418: int tileWidth, tileHeight, destWidth, destHeight, nx, ny1, clipXe, clipYe, remWidth, remHeight, row, col, x, y, srcYo2, srcYe2, h, clipXo, clipYo;
419: boolean remRight = false, remLeft = false, remBottom = false, remTop = false;
420: tileWidth = srcXe - srcXo;
421: tileHeight = srcYe - srcYo;
422: destWidth = destXe - destXo;
423: destHeight = destYe - destYo;
424: if (tile == TILE_N || tile == TILE_S)
425: tileWidth = destWidth;
426: if (tile == TILE_E || tile == TILE_W)
427: tileHeight = destHeight;
428: if (tileWidth == 0 || tileHeight == 0)
429: return true;
430: nx = destWidth / tileWidth;
431: ny1 = (destHeight + tileHeight - 1) / tileHeight;
432: remWidth = destWidth % tileWidth;
433: remHeight = destHeight % tileHeight;
434:
435: if (remWidth > 0) {
436: if (tile == TILE_NE || tile == TILE_SE || tile == TILE_E)
437: remLeft = true;
438: else
439: remRight = true;
440: }
441: if (remHeight > 0) {
442: if (tile == TILE_SE || tile == TILE_SW || tile == TILE_S)
443: remTop = true;
444: else
445: remBottom = true;
446: }
447:
448: Rectangle cb = g.getClipBounds();
449: if (cb != null) {
450: clipXe = cb.x + cb.width;
451: clipYe = cb.y + cb.height;
452: clipXo = cb.x;
453: clipYo = cb.y;
454: } else {
455: clipXe = destXe;
456: clipYe = destYe;
457: clipXo = clipYo = 0;
458: }
459:
460: boolean done = true;
461:
462: for (row = 0, y = destYo; row < ny1 && y <= clipYe; row++, y += h) {
463: srcYo2 = srcYo;
464: h = tileHeight;
465: srcYe2 = srcYe;
466:
467: if (row == 0 && remTop) {
468: srcYo2 = srcYo + tileHeight - remHeight;
469: h = remHeight;
470: } else if (row == ny1 - 1 && remBottom) {
471: srcYe2 = srcYo + remHeight;
472: h = remHeight;
473: }
474:
475: if (y + h > clipYo) {
476: x = destXo;
477: if (remLeft) {
478: done &= g.drawImage(src, x, y, x + remWidth, y + h,
479: srcXo + tileWidth - remWidth, srcYo2,
480: srcXe, srcYe2, o);
481: x += remWidth;
482: }
483: for (col = 0; col < nx && x <= clipXe; col++) {
484: if (x + tileWidth > clipXo) {
485: done &= g.drawImage(src, x, y, x + tileWidth, y
486: + h, srcXo, srcYo2, srcXe, srcYe2, o);
487: }
488: x += tileWidth;
489: }
490: if (remRight) {
491: done &= g.drawImage(src, x, y, x + remWidth, y + h,
492: srcXo, srcYo2, srcXo + remWidth, srcYe2, o);
493: }
494: }
495: }
496: return done;
497: }
498:
499: //////////////////////////////////////////////////////////////
500: // Static Image Tracker Functions
501:
502: private static MediaTracker tracker = new MediaTracker(new Label());
503: private static int trackerId = 0;
504:
505: public static Image loadImage(String filePath) {
506: try // SecurityException or IOExcepion on jview
507: {
508: return loadImage(Toolkit.getDefaultToolkit().getImage(
509: filePath));
510: } catch (Exception e) {
511: return null;
512: }
513: }
514:
515: public static Image loadImage(URL location) {
516: try // SecurityException or IOExcepion on jview
517: {
518: return loadImage(Toolkit.getDefaultToolkit().getImage(
519: location));
520: } catch (Exception e) {
521: return null;
522: }
523: }
524:
525: public static Image loadImage(String file, Class ref) {
526: URL u = ref.getResource(file);
527: if (u != null)
528: return loadImage(u);
529: return null;
530: }
531:
532: public static Image loadImage(byte[] data) {
533: return loadImage(Toolkit.getDefaultToolkit().createImage(data));
534: }
535:
536: public static Image loadImage(Image img) {
537: if (img == null)
538: return null;
539: synchronized (tracker) {
540: int id = trackerId++;
541: tracker.addImage(img, id);
542: Image r = null;
543: try {
544: tracker.waitForID(id);
545: if (!tracker.isErrorID(id))
546: r = img;
547: } catch (InterruptedException e) {
548: }
549: tracker.removeImage(img, id);
550: return r;
551: }
552: }
553: }
|