001: /*
002: * ImageBuffer.java
003: *
004: * Copyright (C) 2000-2002 Peter Graves
005: * $Id: ImageBuffer.java,v 1.2 2002/10/11 01:42:37 piso Exp $
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: */
021:
022: package org.armedbear.j;
023:
024: import java.awt.Color;
025: import java.awt.Cursor;
026: import java.awt.Image;
027: import java.awt.MediaTracker;
028:
029: public class ImageBuffer extends Buffer implements Constants {
030: private static Color backgrounds[];
031:
032: static {
033: backgrounds = new Color[3];
034: backgrounds[0] = new Color(153, 153, 153);
035: backgrounds[1] = Color.black;
036: backgrounds[2] = Color.white;
037: }
038:
039: private int backgroundIndex;
040: private Image currentImage;
041: private Image originalImage;
042: private int originalWidth;
043: private int originalHeight;
044: private int currentWidth;
045: private int currentHeight;
046: private ImageLoader loader;
047:
048: private ImageBuffer(File file, File cache, String listing) {
049: super ();
050: mode = Editor.getModeList().getMode(IMAGE_MODE);
051: setFile(file);
052: supportsUndo = false;
053: readOnly = true;
054: autosaveEnabled = false;
055: type = TYPE_IMAGE;
056: setCache(cache);
057: setListing(listing);
058: setInitialized(true);
059: }
060:
061: public static ImageBuffer createImageBuffer(File file, File cache,
062: String listing) {
063: // Load the image before creating the buffer, so we don't have to
064: // unlink the buffer if we can't load the image.
065: File toBeLoaded = cache != null ? cache : file;
066: ImageLoader loader = new ImageLoader(toBeLoaded);
067: Image img = loader.loadImage();
068: if (img != null) {
069: // The image was loaded successfully. Now create the buffer.
070: ImageBuffer ib = new ImageBuffer(file, cache, listing);
071: ib.loader = loader;
072: ib.currentImage = ib.originalImage = img;
073: ib.currentWidth = ib.originalWidth = img.getWidth(null);
074: ib.currentHeight = ib.originalHeight = img.getHeight(null);
075: ib.setLastModified(toBeLoaded.lastModified());
076: ib.setLoaded(true);
077: return ib;
078: } else
079: return null;
080: }
081:
082: public final Position getInitialDotPos() {
083: return null;
084: }
085:
086: public final boolean needsParsing() {
087: return false;
088: }
089:
090: public final Image getImage() {
091: return currentImage;
092: }
093:
094: public final int getDisplayHeight() {
095: if (getModeId() == IMAGE_MODE)
096: return currentImage.getHeight(null)
097: + Display.getImageBorderHeight() * 2;
098: else
099: return super .getDisplayHeight();
100: }
101:
102: public final int getDisplayWidth() {
103: if (getModeId() == IMAGE_MODE)
104: return currentImage.getWidth(null)
105: + Display.getImageBorderWidth() * 2;
106: else
107: return super .getDisplayWidth();
108: }
109:
110: public int load() {
111: if (!isLoaded()) {
112: Debug.assertTrue(loader == null);
113: final File toBeLoaded = getCache() != null ? getCache()
114: : getFile();
115: loader = new ImageLoader(toBeLoaded);
116: Image img = loader.loadImage();
117: if (img != null) {
118: currentImage = originalImage = img;
119: currentWidth = originalWidth = img.getWidth(null);
120: currentHeight = originalHeight = img.getHeight(null);
121: } else
122: MessageDialog.showMessageDialog("Error loading image",
123: "Error");
124: setLastModified(toBeLoaded.lastModified());
125: setLoaded(true);
126: }
127: return LOAD_COMPLETED;
128: }
129:
130: public void reload() {
131: switch (getModeId()) {
132: case BINARY_MODE:
133: if (loader != null) {
134: loader.dispose();
135: loader = null;
136: }
137: currentImage = null;
138: originalImage = null;
139: super .reload();
140: return;
141: case IMAGE_MODE:
142: if (getFile().isLocal())
143: reloadLocal();
144: else
145: reloadRemote();
146: return;
147: default:
148: Debug.bug();
149: }
150: }
151:
152: private void reloadLocal() {
153: empty();
154: if (loader != null) {
155: loader.dispose();
156: loader = null;
157: }
158: currentImage = null;
159: originalImage = null;
160: load();
161: for (EditorIterator it = new EditorIterator(); it.hasNext();) {
162: Editor ed = it.nextEditor();
163: if (ed.getBuffer() == ImageBuffer.this ) {
164: ed.getDisplay().repaint();
165: ed.updateDisplay();
166: }
167: }
168: }
169:
170: private void reloadRemote() {
171: final File file = getFile();
172: LoadProcess p = null;
173: if (file instanceof FtpFile) {
174: FtpSession session = FtpSession.getSession((FtpFile) file);
175: p = new FtpLoadProcess(this , (FtpFile) file, session);
176: } else if (file instanceof HttpFile) {
177: p = new HttpLoadProcess(this , (HttpFile) file);
178: } else {
179: Debug.bug();
180: return;
181: }
182: final LoadProcess loadProcess = p;
183: Runnable successRunnable = new Runnable() {
184: public void run() {
185: final File cache = getCache();
186: if (cache != null && cache.isFile())
187: cache.delete();
188: setCache(loadProcess.getCache());
189: reloadLocal();
190: setBusy(false);
191: }
192: };
193: ErrorRunnable errorRunnable = new ErrorRunnable("Reload failed");
194: loadProcess.setProgressNotifier(new StatusBarProgressNotifier(
195: this ));
196: loadProcess.setSuccessRunnable(successRunnable);
197: loadProcess.setErrorRunnable(errorRunnable);
198: loadProcess.start();
199: }
200:
201: public final Color getBackgroundColor() {
202: return getBackground(backgroundIndex);
203: }
204:
205: public static final Color getDefaultBackgroundColor() {
206: return getBackground(0);
207: }
208:
209: public final int getImageWidth() {
210: return originalWidth;
211: }
212:
213: public final int getImageHeight() {
214: return originalHeight;
215: }
216:
217: public final void cycleBackground() {
218: if (++backgroundIndex >= getBackgroundCount())
219: backgroundIndex = 0;
220: }
221:
222: private static final int getBackgroundCount() {
223: return backgrounds.length;
224: }
225:
226: private static Color getBackground(int index) {
227: if (index >= 0 && index < backgrounds.length)
228: return backgrounds[index];
229: else
230: return backgrounds[0];
231: }
232:
233: public void zoomIn() {
234: int w = currentWidth * 2;
235: int h = currentHeight * 2;
236: if (w > 0 && h > 0)
237: resize(w, h);
238: }
239:
240: public void zoomOut() {
241: int w = currentWidth / 2;
242: int h = currentHeight / 2;
243: if (w > 0 && h > 0)
244: resize(w, h);
245: }
246:
247: public void fit() {
248: if (originalWidth == 0 || originalHeight == 0)
249: return;
250: Editor editor = Editor.currentEditor();
251: Display display = editor.getDisplay();
252: int displayWidth = display.getWidth()
253: - Display.getImageBorderWidth() * 2;
254: int displayHeight = display.getHeight()
255: - Display.getImageBorderHeight() * 2;
256: float factor = (float) displayWidth / (float) originalWidth;
257: if (factor * originalHeight > displayHeight)
258: factor = (float) displayHeight / (float) originalHeight;
259: int w = (int) (originalWidth * factor);
260: int h = (int) (originalHeight * factor);
261: resize(w, h);
262: }
263:
264: public void restore() {
265: resize(originalWidth, originalHeight);
266: }
267:
268: private void resize(int w, int h) {
269: Editor editor = Editor.currentEditor();
270: editor.setWaitCursor();
271: Image img = null;
272: MediaTracker mt = null;
273:
274: try {
275: long pixels = w * h;
276: if (pixels > originalWidth * originalHeight
277: && pixels > 2592000) {
278: // 1800x1440 (an arbitrary limit)
279: editor.status("Too many pixels!");
280: return;
281: }
282: long bytesRequired = pixels * 4; // 4 bytes (32 bits) per pixel
283: Runtime runtime = Runtime.getRuntime();
284: long bytesFree = runtime.freeMemory();
285: if (bytesRequired > bytesFree) {
286: runtime.gc();
287: bytesFree = runtime.freeMemory();
288: if (bytesRequired > bytesFree) {
289: editor.status("Not enough memory");
290: return;
291: }
292: }
293: img = originalImage.getScaledInstance(w, h,
294: Image.SCALE_DEFAULT);
295: mt = new MediaTracker(editor);
296: mt.addImage(img, 0);
297: mt.waitForID(0);
298: } catch (Exception e) {
299: Log.error(e);
300: } finally {
301: editor.setDefaultCursor();
302: }
303:
304: if (mt == null || mt.isErrorAny())
305: img = null;
306:
307: if (img != null) {
308: if (currentImage != originalImage)
309: currentImage.flush();
310: currentImage = img;
311: currentWidth = img.getWidth(null);
312: currentHeight = img.getHeight(null);
313: for (EditorIterator it = new EditorIterator(); it.hasNext();) {
314: Editor ed = it.nextEditor();
315: if (ed.getBuffer() == this ) {
316: ed.getDisplay().repaint();
317: status(ed);
318: }
319: }
320: }
321: }
322:
323: public boolean reactivate() {
324: final File file = getFile();
325: if (file == null || file.isRemote() || !file.isFile())
326: return false;
327: if (isLoaded() && file.lastModified() != getLastModified()) {
328: reload();
329: for (EditorIterator it = new EditorIterator(); it.hasNext();) {
330: Editor ed = it.nextEditor();
331: if (ed.getBuffer() == this ) {
332: ed.getDisplay().repaint();
333: status(ed);
334: }
335: }
336: return true;
337: }
338: return false;
339: }
340:
341: private void status(Editor editor) {
342: int percent = (int) ((float) currentWidth * 100
343: / (float) originalWidth + 0.5);
344: editor.status(String.valueOf(percent) + '%');
345: }
346:
347: public void dispose() {
348: if (loader != null)
349: loader.dispose();
350: super .dispose();
351: }
352:
353: public Cursor getDefaultCursor() {
354: return Cursor.getDefaultCursor();
355: }
356:
357: public Cursor getDefaultCursor(Position pos) {
358: return Cursor.getDefaultCursor();
359: }
360:
361: public void saveView(Editor editor) {
362: // Nothing to do.
363: }
364:
365: public String getStatusText(Editor editor) {
366: FastStringBuffer sb = new FastStringBuffer(String
367: .valueOf(getImageWidth()));
368: sb.append('x');
369: sb.append(String.valueOf(getImageHeight()));
370: sb.append(" pixels");
371: return sb.toString();
372: }
373: }
|