001: /* ====================================================================
002: Licensed to the Apache Software Foundation (ASF) under one or more
003: contributor license agreements. See the NOTICE file distributed with
004: this work for additional information regarding copyright ownership.
005: The ASF licenses this file to You under the Apache License, Version 2.0
006: (the "License"); you may not use this file except in compliance with
007: the License. You may obtain a copy of the License at
008:
009: http://www.apache.org/licenses/LICENSE-2.0
010:
011: Unless required by applicable law or agreed to in writing, software
012: distributed under the License is distributed on an "AS IS" BASIS,
013: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: See the License for the specific language governing permissions and
015: limitations under the License.
016: ==================================================================== */
017: package org.apache.poi.hslf.usermodel;
018:
019: import org.apache.poi.util.LittleEndian;
020: import org.apache.poi.hslf.model.Picture;
021: import org.apache.poi.hslf.blip.*;
022: import org.apache.poi.hslf.exceptions.HSLFException;
023:
024: import java.io.OutputStream;
025: import java.io.IOException;
026: import java.security.MessageDigest;
027: import java.security.NoSuchAlgorithmException;
028:
029: /**
030: * A class that represents image data contained in a slide show.
031: *
032: * @author Yegor Kozlov
033: */
034: public abstract class PictureData {
035:
036: /**
037: * Size of the image checksum calculated using MD5 algorithm.
038: */
039: protected static final int CHECKSUM_SIZE = 16;
040:
041: /**
042: * Binary data of the picture
043: */
044: private byte[] rawdata;
045: /**
046: * The offset to the picture in the stream
047: */
048: protected int offset;
049:
050: /**
051: * Returns type of this picture.
052: * Must be one of the static constants defined in the <code>Picture<code> class.
053: *
054: * @return type of this picture.
055: */
056: public abstract int getType();
057:
058: /**
059: * Returns the binary data of this Picture
060: * @return picture data
061: */
062: public abstract byte[] getData();
063:
064: /**
065: * Set picture data
066: */
067: public abstract void setData(byte[] data) throws IOException;
068:
069: /**
070: * Blip signature.
071: */
072: protected abstract int getSignature();
073:
074: /**
075: * Returns the raw binary data of this Picture excluding the first 8 bytes
076: * which hold image signature and size of the image data.
077: *
078: * @return picture data
079: */
080: public byte[] getRawData() {
081: return rawdata;
082: }
083:
084: public void setRawData(byte[] data) {
085: rawdata = data;
086: }
087:
088: /**
089: * File offset in the 'Pictures' stream
090: *
091: * @return offset in the 'Pictures' stream
092: */
093: public int getOffset() {
094: return offset;
095: }
096:
097: /**
098: * Set offset of this picture in the 'Pictures' stream.
099: * We need to set it when a new picture is created.
100: *
101: * @param offset in the 'Pictures' stream
102: */
103: public void setOffset(int offset) {
104: this .offset = offset;
105: }
106:
107: /**
108: * Returns 16-byte checksum of this picture
109: */
110: public byte[] getUID() {
111: byte[] uid = new byte[16];
112: System.arraycopy(rawdata, 0, uid, 0, uid.length);
113: return uid;
114: }
115:
116: /**
117: * Compute 16-byte checksum of this picture using MD5 algorithm.
118: */
119: public static byte[] getChecksum(byte[] data) {
120: MessageDigest sha;
121: try {
122: sha = MessageDigest.getInstance("MD5");
123: } catch (NoSuchAlgorithmException e) {
124: throw new HSLFException(e.getMessage());
125: }
126: sha.update(data);
127: return sha.digest();
128: }
129:
130: /**
131: * Write this picture into <code>OutputStream</code>
132: */
133: public void write(OutputStream out) throws IOException {
134: byte[] data;
135:
136: data = new byte[LittleEndian.SHORT_SIZE];
137: LittleEndian.putUShort(data, 0, getSignature());
138: out.write(data);
139:
140: data = new byte[LittleEndian.SHORT_SIZE];
141: LittleEndian.putUShort(data, 0, getType() + 0xF018);
142: out.write(data);
143:
144: byte[] rawdata = getRawData();
145:
146: data = new byte[LittleEndian.INT_SIZE];
147: LittleEndian.putInt(data, 0, rawdata.length);
148: out.write(data);
149:
150: out.write(rawdata);
151: }
152:
153: /**
154: * Create an instance of <code>PictureData</code> by type.
155: *
156: * @param type type of the picture data.
157: * Must be one of the static constants defined in the <code>Picture<code> class.
158: * @return concrete instance of <code>PictureData</code>
159: */
160: public static PictureData create(int type) {
161: PictureData pict;
162: switch (type) {
163: case Picture.EMF:
164: pict = new EMF();
165: break;
166: case Picture.WMF:
167: pict = new WMF();
168: break;
169: case Picture.PICT:
170: pict = new PICT();
171: break;
172: case Picture.JPEG:
173: pict = new JPEG();
174: break;
175: case Picture.PNG:
176: pict = new PNG();
177: break;
178: case Picture.DIB:
179: pict = new DIB();
180: break;
181: default:
182: throw new IllegalArgumentException(
183: "Unsupported picture type: " + type);
184: }
185: return pict;
186: }
187:
188: /**
189: * Return 24 byte header which preceeds the actual picture data.
190: * <p>
191: * The header consists of 2-byte signature, 2-byte type,
192: * 4-byte image size and 16-byte checksum of the image data.
193: * </p>
194: *
195: * @return the 24 byte header which preceeds the actual picture data.
196: */
197: public byte[] getHeader() {
198: byte[] header = new byte[16 + 8];
199: LittleEndian.putInt(header, 0, getSignature());
200: LittleEndian.putInt(header, 4, getRawData().length);
201: System.arraycopy(rawdata, 0, header, 8, 16);
202: return header;
203: }
204:
205: /**
206: * Return image size in bytes
207: *
208: * @return the size of the picture in bytes
209: * @deprecated Use <code>getData().length</code> instead.
210: */
211: public int getSize() {
212: return getData().length;
213: }
214:
215: }
|