001: /*
002: * $Id: JPEGBitmap.java,v 1.5 2002/02/25 19:07:04 ptalbot Exp $
003: *
004: * ==========================================================================
005: *
006: * The JGenerator Software License, Version 1.0
007: *
008: * Copyright (c) 2000 Dmitry Skavish (skavish@usa.net). All rights reserved.
009: *
010: * Redistribution and use in source and binary forms, with or without
011: * modification, are permitted provided that the following conditions are met:
012: *
013: * 1. Redistributions of source code must retain the above copyright
014: * notice, this list of conditions and the following disclaimer.
015: *
016: * 2. Redistributions in binary form must reproduce the above copyright
017: * notice, this list of conditions and the following disclaimer in
018: * the documentation and/or other materials provided with the
019: * distribution.
020: *
021: * 3. The end-user documentation included with the redistribution, if
022: * any, must include the following acknowlegement:
023: * "This product includes software developed by Dmitry Skavish
024: * (skavish@usa.net, http://www.flashgap.com/)."
025: * Alternately, this acknowlegement may appear in the software itself,
026: * if and wherever such third-party acknowlegements normally appear.
027: *
028: * 4. The name "The JGenerator" must not be used to endorse or promote
029: * products derived from this software without prior written permission.
030: * For written permission, please contact skavish@usa.net.
031: *
032: * 5. Products derived from this software may not be called "The JGenerator"
033: * nor may "The JGenerator" appear in their names without prior written
034: * permission of Dmitry Skavish.
035: *
036: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
037: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
038: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
039: * DISCLAIMED. IN NO EVENT SHALL DMITRY SKAVISH OR THE OTHER
040: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
041: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
042: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
043: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
044: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
045: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
046: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
047: * SUCH DAMAGE.
048: *
049: */
050:
051: package org.openlaszlo.iv.flash.api.image;
052:
053: import java.io.*;
054: import java.awt.color.ColorSpace;
055: import java.awt.image.ColorConvertOp;
056: import java.awt.image.BufferedImage;
057: import java.awt.image.Raster;
058: import java.awt.geom.*;
059: import org.openlaszlo.iv.flash.url.*;
060: import org.openlaszlo.iv.flash.util.*;
061: import org.openlaszlo.iv.flash.parser.*;
062: import org.openlaszlo.iv.flash.api.*;
063:
064: import com.sun.image.codec.jpeg.*;
065:
066: public class JPEGBitmap extends Bitmap {
067:
068: private static final String jpegTablesName = "%JPEGTABLES$JPEGTABLES%";
069: private DataMarker data;
070: private FlashItem jpegTables;
071: private Rectangle2D bounds;
072: private JPEGInfo info;
073:
074: /** true - ready to be generated, false - not ready, has to be converted */
075: private boolean readyToGen;
076:
077: public JPEGBitmap() {
078: }
079:
080: public void setData(DataMarker data) {
081: this .data = data;
082: this .bounds = null;
083: this .readyToGen = false;
084: }
085:
086: public static Bitmap parse(Parser p) {
087: JPEGBitmap o = new JPEGBitmap();
088: o.setID(p.getUWord());
089: o.data = new DataMarker(p.getBuf(), p.getPos(), p
090: .getTagEndPos());
091: o.readyToGen = true;
092: o.tagCode = p.getTagCode();
093: if (o.tagCode == Tag.DEFINEBITS) {
094: o.jpegTables = p.getDefFromLibrary(jpegTablesName);
095: }
096: return o;
097: }
098:
099: public static void parseJPegTables(Parser p) {
100: JPEGTables tables = new JPEGTables();
101: tables.setData(new DataMarker(p.getBuf(), p.getPos(), p
102: .getTagEndPos())); // 02/09/01 by sd
103: tables.setName(jpegTablesName);
104: p.addDefToLibrary(jpegTablesName, tables);
105: }
106:
107: public int getSize() {
108: return data.buffer.length;
109: }
110:
111: public Rectangle2D getBounds() {
112: if (bounds != null)
113: return bounds;
114: parseData();
115: return bounds;
116: }
117:
118: public void collectDeps(DepsCollector dc) {
119:
120: /* LASZLO we never output JPEGTABLES tags
121: if( jpegTables != null ) {
122: dc.addDep(jpegTables);
123: }
124: */
125: }
126:
127: public static JPEGBitmap newJPEGBitmap(String fileName)
128: throws IVException, IOException {
129: return newJPEGBitmap(IVUrl.newUrl(fileName));
130: }
131:
132: public static JPEGBitmap newJPEGBitmap(IVUrl url)
133: throws IVException, IOException {
134: return newJPEGBitmap(Util.readUrl(url));
135: }
136:
137: public static JPEGBitmap newJPEGBitmap(FlashBuffer fob)
138: throws IVException {
139: JPEGBitmap bitmap = new JPEGBitmap();
140: bitmap.setTag(Tag.DEFINEBITSJPEG2);
141: DataMarker data = new DataMarker(fob.getBuf(), 0, fob.getSize());
142: bitmap.setData(data);
143: //bitmap.parseData();
144: return bitmap;
145: }
146:
147: private void parseData() {
148: info = JPEGHelper.getInfo(data.buffer, data.start, data.end);
149: bounds = GeomHelper.newRectangle(0, 0, info.width, info.height);
150:
151: // check if it's not progressive jpeg or gray
152: if (info.type == 0 && info.num_comps == 3) {
153: readyToGen = true;
154: } else {
155: readyToGen = false;
156: }
157: }
158:
159: /**
160: * Reencode the image with specified quality
161: * <P>
162: * As a side effect this method converts from progressive jpeg
163: * (if any) to regular
164: *
165: * @param quality quality of new jpeg: 0..1, with 1 being highest quality
166: */
167: public void processImage(float quality) {
168: try {
169: Log.logRB(Resource.REENCODINGJPEG,
170: new Object[] { new Float(quality) });
171: int size = data.end - data.start;
172: InputStream is = data.getInputStream();
173: JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(is);
174: BufferedImage image = decoder.decodeAsBufferedImage();
175:
176: info = JPEGHelper
177: .getInfo(data.buffer, data.start, data.end);
178: // Need to color convert from greyscale to RGB
179: if (info.num_comps != 3) {
180: ColorConvertOp op = new ColorConvertOp(image
181: .getColorModel().getColorSpace(), ColorSpace
182: .getInstance(ColorSpace.CS_LINEAR_RGB), null);
183: image = op.filter(image, null);
184: }
185:
186: bounds = GeomHelper.newRectangle(0, 0, image.getWidth(),
187: image.getHeight());
188:
189: FlashBuffer fob = new FlashBuffer(size);
190: OutputStream os = fob.getOutputStream();
191:
192: JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(os);
193: JPEGEncodeParam params = encoder
194: .getDefaultJPEGEncodeParam(image);
195: params.setQuality(quality, true);
196: encoder.encode(image, params);
197:
198: data.buffer = fob.getBuf();
199: data.end = fob.getSize();
200: data.start = 0;
201: readyToGen = true;
202: } catch (IOException e) {
203: Log.log(e);
204: }
205: }
206:
207: /**
208: * Rescales this image with specified width, height and quality
209: *
210: * @param width new width
211: * @param height new height
212: * @param quality new quality
213: */
214: public void rescale(int width, int height, float quality) {
215: try {
216: Log.logRB(Resource.RESCALINGJPEG, new Object[] {
217: new Integer(width), new Integer(height),
218: new Float(quality) });
219: int size = data.end - data.start;
220: InputStream is = data.getInputStream();
221: JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(is);
222: BufferedImage image = decoder.decodeAsBufferedImage();
223: image = (BufferedImage) image.getScaledInstance(width,
224: height, java.awt.Image.SCALE_SMOOTH);
225:
226: bounds = GeomHelper.newRectangle(0, 0, image.getWidth(),
227: image.getHeight());
228:
229: FlashBuffer fob = new FlashBuffer(size);
230: OutputStream os = fob.getOutputStream();
231:
232: JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(os);
233: JPEGEncodeParam params = encoder
234: .getDefaultJPEGEncodeParam(image);
235: params.setQuality(quality, true);
236: encoder.encode(image, params);
237:
238: data.buffer = fob.getBuf();
239: data.end = fob.getSize();
240: data.start = 0;
241: readyToGen = true;
242: } catch (IOException e) {
243: Log.log(e);
244: }
245: }
246:
247: /* private GraphicsConfiguration gr_config = null;
248: private static GraphicsConfiguration getGraphicsConfiguration() {
249: if( gr_config == null ) {
250: GraphicsEnvironment gr_env = GraphicsEnvironment.getLocalGraphicsEnvironment();
251: GraphicsDevice gr_device = gr_env.getDefaultScreenDevice();
252: gr_config = gr_device.getDefaultConfiguration();
253: }
254: return gr_config;
255: }
256: */
257: public void write(FlashOutput fob) {
258: if (!readyToGen) {
259: processImage(.75f);
260: }
261: // LASZLO, turn DEFINEBITS into DEFINTEBITSJPEG2
262: if (tagCode == Tag.DEFINEBITS) {
263: JPEGTables tables = (JPEGTables) jpegTables;
264: fob.writeTag(Tag.DEFINEBITSJPEG2, 2 + data.length()
265: + tables.getDataLength());
266: fob.writeDefID(this );
267: tables.writeData(fob);
268: } else {
269: fob.writeTag(tagCode, 2 + data.length());
270: fob.writeDefID(this );
271: }
272: data.write(fob);
273: }
274:
275: public void printContent(PrintStream out, String indent) {
276: out.println(indent + "JPEGBitmap(" + Tag.tagNames[tagCode]
277: + "): id=" + getID() + " size=" + data.length()
278: + " name='" + getName() + "'");
279: }
280:
281: protected FlashItem copyInto(FlashItem item, ScriptCopier copier) {
282: super .copyInto(item, copier);
283: ((JPEGBitmap) item).data = (DataMarker) data.getCopy();
284: ((JPEGBitmap) item).jpegTables = jpegTables;
285: ((JPEGBitmap) item).bounds = (Rectangle2D) bounds.clone();
286: ((JPEGBitmap) item).readyToGen = readyToGen;
287: ((JPEGBitmap) item).info = info != null ? info.getCopy() : null;
288: return item;
289: }
290:
291: public FlashItem getCopy(ScriptCopier copier) {
292: return copyInto(new JPEGBitmap(), copier);
293: }
294:
295: public static class JPEGInfo {
296: public int type; // 0 - regular, 1 - progressive
297: public int width;
298: public int height;
299: public int num_comps;
300: public int precision;
301:
302: public JPEGInfo getCopy() {
303: JPEGInfo info = new JPEGInfo();
304: info.type = type;
305: info.width = width;
306: info.height = height;
307: info.num_comps = num_comps;
308: info.precision = precision;
309: return info;
310: }
311: }
312:
313: private static class JPEGTables extends FlashDef {
314: DataMarker data;
315:
316: public JPEGTables() {
317: }
318:
319: public int getTag() {
320: return Tag.JPEGTABLES;
321: }
322:
323: public void setData(DataMarker data) {
324: this .data = data;
325: }
326:
327: public void write(FlashOutput fob) {
328: fob.writeTag(Tag.JPEGTABLES, data.length());
329: data.write(fob);
330: }
331:
332: public void writeData(FlashOutput fob) {
333: data.write(fob);
334: }
335:
336: public int getDataLength() {
337: return data.length();
338: }
339: }
340:
341: }
|