View | Details | Raw Unified | Return to bug 43125
Collapse All | Expand All

(-)src/java/org/apache/poi/hssf/usermodel/HSSFPictureData.java (-2 / +3 lines)
Lines 18-23 Link Here
18
package org.apache.poi.hssf.usermodel;
18
package org.apache.poi.hssf.usermodel;
19
19
20
import org.apache.poi.ddf.EscherBitmapBlip;
20
import org.apache.poi.ddf.EscherBitmapBlip;
21
import org.apache.poi.ddf.EscherBlipRecord;
21
22
22
/**
23
/**
23
 * Represents binary data stored in the file.  Eg. A GIF, JPEG etc...
24
 * Represents binary data stored in the file.  Eg. A GIF, JPEG etc...
Lines 39-52 Link Here
39
    /**
40
    /**
40
     * Underlying escher blip record containing the bitmap data.
41
     * Underlying escher blip record containing the bitmap data.
41
     */
42
     */
42
    private EscherBitmapBlip blip;
43
    private EscherBlipRecord blip;
43
44
44
    /**
45
    /**
45
     * Constructs a picture object.
46
     * Constructs a picture object.
46
     *
47
     *
47
     * @param blip the underlying blip record containing the bitmap data.
48
     * @param blip the underlying blip record containing the bitmap data.
48
     */
49
     */
49
    HSSFPictureData( EscherBitmapBlip blip )
50
    HSSFPictureData( EscherBlipRecord blip )
50
    {
51
    {
51
        this.blip = blip;
52
        this.blip = blip;
52
    }
53
    }
(-)src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java (-2 / +2 lines)
Lines 1361-1370 Link Here
1361
                if (escherRecord instanceof EscherBSERecord)
1361
                if (escherRecord instanceof EscherBSERecord)
1362
                {
1362
                {
1363
                    EscherBlipRecord blip = ((EscherBSERecord) escherRecord).getBlipRecord();
1363
                    EscherBlipRecord blip = ((EscherBSERecord) escherRecord).getBlipRecord();
1364
                    if (blip instanceof EscherBitmapBlip)
1364
                    if (blip != null)
1365
                    {
1365
                    {
1366
                        // TODO: Some kind of structure.
1366
                        // TODO: Some kind of structure.
1367
                        pictures.add(new HSSFPictureData((EscherBitmapBlip) blip));
1367
                        pictures.add(new HSSFPictureData(blip));
1368
                    }
1368
                    }
1369
                }
1369
                }
1370
1370
(-)src/java/org/apache/poi/ddf/DefaultEscherRecordFactory.java (+6 lines)
Lines 81-86 Link Here
81
            {
81
            {
82
                r = new EscherBitmapBlip();
82
                r = new EscherBitmapBlip();
83
            }
83
            }
84
            else if (header.getRecordId() == EscherMetafileBlip.RECORD_ID_EMF ||
85
                    header.getRecordId() == EscherMetafileBlip.RECORD_ID_WMF ||
86
                    header.getRecordId() == EscherMetafileBlip.RECORD_ID_PICT)
87
            {
88
                r = new EscherMetafileBlip();
89
            }
84
            else
90
            else
85
            {
91
            {
86
                r = new EscherBlipRecord();
92
                r = new EscherBlipRecord();
(-)src/java/org/apache/poi/ddf/EscherBitmapBlip.java (-10 lines)
Lines 119-134 Link Here
119
        this.field_2_marker = field_2_marker;
119
        this.field_2_marker = field_2_marker;
120
    }
120
    }
121
121
122
    public byte[] getPicturedata()
123
    {
124
        return field_pictureData;
125
    }
126
127
    public void setPictureData(byte[] pictureData)
128
    {
129
        field_pictureData = pictureData;
130
    }
131
132
    public String toString()
122
    public String toString()
133
    {
123
    {
134
        String nl = System.getProperty( "line.separator" );
124
        String nl = System.getProperty( "line.separator" );
(-)src/java/org/apache/poi/ddf/EscherBlipRecord.java (+10 lines)
Lines 103-108 Link Here
103
        return "Blip";
103
        return "Blip";
104
    }
104
    }
105
105
106
    public byte[] getPicturedata()
107
    {
108
        return field_pictureData;
109
    }
110
111
    public void setPictureData(byte[] pictureData)
112
    {
113
        field_pictureData = pictureData;
114
    }
115
106
    public String toString()
116
    public String toString()
107
    {
117
    {
108
        String nl = System.getProperty( "line.separator" );
118
        String nl = System.getProperty( "line.separator" );
(-)src/java/org/apache/poi/ddf/EscherMetafileBlip.java (+277 lines)
Line 0 Link Here
1
/*
2
* Licensed to the Apache Software Foundation (ASF) under one or more
3
* contributor license agreements.  See the NOTICE file distributed with
4
* this work for additional information regarding copyright ownership.
5
* The ASF licenses this file to You under the Apache License, Version 2.0
6
* (the "License"); you may not use this file except in compliance with
7
* the License.  You may obtain a copy of the License at
8
*
9
*     http://www.apache.org/licenses/LICENSE-2.0
10
*
11
* Unless required by applicable law or agreed to in writing, software
12
* distributed under the License is distributed on an "AS IS" BASIS,
13
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
* See the License for the specific language governing permissions and
15
* limitations under the License.
16
*/
17
package org.apache.poi.ddf;
18
19
import org.apache.poi.util.HexDump;
20
import org.apache.poi.util.LittleEndian;
21
import org.apache.poi.util.POILogFactory;
22
import org.apache.poi.util.POILogger;
23
24
import java.awt.Dimension;
25
import java.awt.Rectangle;
26
import java.io.ByteArrayInputStream;
27
import java.io.ByteArrayOutputStream;
28
import java.io.IOException;
29
import java.util.zip.InflaterInputStream;
30
31
/**
32
 * @author Daniel Noll
33
 * @version $Id$
34
 */
35
public class EscherMetafileBlip
36
        extends EscherBlipRecord
37
{
38
    private static final POILogger log = POILogFactory.getLogger(EscherMetafileBlip.class);
39
40
    // TODO: What are the other two types?
41
    public static final short RECORD_ID_EMF = (short) 0xF018 + 2;
42
    public static final short RECORD_ID_WMF = (short) 0xF018 + 2;
43
    public static final short RECORD_ID_PICT = (short) 0xF018 + 2;
44
45
    private static final int HEADER_SIZE = 8;
46
47
    private byte[] field_1_UID;
48
    private int field_2_cb;
49
    private int field_3_rcBounds_x1;
50
    private int field_3_rcBounds_y1;
51
    private int field_3_rcBounds_x2;
52
    private int field_3_rcBounds_y2;
53
    private int field_4_ptSize_w;
54
    private int field_4_ptSize_h;
55
    private int field_5_cbSave;
56
    private byte field_6_fCompression;
57
    private byte field_7_fFilter;
58
59
    private byte[] raw_pictureData;
60
61
    /**
62
     * This method deserializes the record from a byte array.
63
     *
64
     * @param data          The byte array containing the escher record information
65
     * @param offset        The starting offset into <code>data</code>.
66
     * @param recordFactory May be null since this is not a container record.
67
     * @return The number of bytes read from the byte array.
68
     */
69
    public int fillFields( byte[] data, int offset, EscherRecordFactory recordFactory )
70
    {
71
        int bytesAfterHeader = readHeader( data, offset );
72
        int pos = offset + HEADER_SIZE;
73
74
        field_1_UID = new byte[16];
75
        System.arraycopy( data, pos, field_1_UID, 0, 16 ); pos += 16;
76
        field_2_cb = LittleEndian.getInt( data, pos ); pos += 4;
77
        field_3_rcBounds_x1 = LittleEndian.getInt( data, pos ); pos += 4;
78
        field_3_rcBounds_y1 = LittleEndian.getInt( data, pos ); pos += 4;
79
        field_3_rcBounds_x2 = LittleEndian.getInt( data, pos ); pos += 4;
80
        field_3_rcBounds_y2 = LittleEndian.getInt( data, pos ); pos += 4;
81
        field_4_ptSize_w = LittleEndian.getInt( data, pos ); pos += 4;
82
        field_4_ptSize_h = LittleEndian.getInt( data, pos ); pos += 4;
83
        field_5_cbSave = LittleEndian.getInt( data, pos ); pos += 4;
84
        field_6_fCompression = data[pos]; pos++;
85
        field_7_fFilter = data[pos]; pos++;
86
87
        raw_pictureData = new byte[field_5_cbSave];
88
        System.arraycopy( data, pos, raw_pictureData, 0, field_5_cbSave );
89
90
        // 0 means DEFLATE compression
91
        // 0xFE means no compression
92
        if (field_6_fCompression == 0)
93
        {
94
            field_pictureData = inflatePictureData(raw_pictureData);
95
        }
96
        else
97
        {
98
            field_pictureData = raw_pictureData;
99
        }
100
101
        return bytesAfterHeader + HEADER_SIZE;
102
    }
103
104
    /**
105
     * Serializes the record to an existing byte array.
106
     *
107
     * @param offset    the offset within the byte array
108
     * @param data      the data array to serialize to
109
     * @param listener  a listener for begin and end serialization events.  This
110
     *                  is useful because the serialization is
111
     *                  hierarchical/recursive and sometimes you need to be able
112
     *                  break into that.
113
     * @return the number of bytes written.
114
     */
115
    public int serialize( int offset, byte[] data, EscherSerializationListener listener )
116
    {
117
        listener.beforeRecordSerialize(offset, getRecordId(), this);
118
119
        int pos = offset;
120
        LittleEndian.putShort( data, pos, getOptions() ); pos += 2;
121
        LittleEndian.putShort( data, pos, getRecordId() ); pos += 2;
122
        LittleEndian.putInt( data, getRecordSize() - HEADER_SIZE ); pos += 4;
123
124
        System.arraycopy( field_1_UID, 0, data, pos, 16 ); pos += 16;
125
        LittleEndian.putInt( data, pos, field_2_cb ); pos += 4;
126
        LittleEndian.putInt( data, pos, field_3_rcBounds_x1 ); pos += 4;
127
        LittleEndian.putInt( data, pos, field_3_rcBounds_y1 ); pos += 4;
128
        LittleEndian.putInt( data, pos, field_3_rcBounds_x2 ); pos += 4;
129
        LittleEndian.putInt( data, pos, field_3_rcBounds_y2 ); pos += 4;
130
        LittleEndian.putInt( data, pos, field_4_ptSize_w ); pos += 4;
131
        LittleEndian.putInt( data, pos, field_4_ptSize_h ); pos += 4;
132
        LittleEndian.putInt( data, pos, field_5_cbSave ); pos += 4;
133
        data[pos] = field_6_fCompression; pos++;
134
        data[pos] = field_7_fFilter; pos++;
135
136
        System.arraycopy( raw_pictureData, 0, data, pos, raw_pictureData.length );
137
138
        listener.afterRecordSerialize(offset + getRecordSize(), getRecordId(), getRecordSize(), this);
139
        return HEADER_SIZE + 16 + 1 + raw_pictureData.length;
140
    }
141
142
    /**
143
     * Decompresses the provided data, returning the inflated result.
144
     *
145
     * @param data the deflated picture data.
146
     * @return the inflated picture data.
147
     */
148
    private static byte[] inflatePictureData(byte[] data)
149
    {
150
        try
151
        {
152
            InflaterInputStream in = new InflaterInputStream(
153
                new ByteArrayInputStream( data ) );
154
            ByteArrayOutputStream out = new ByteArrayOutputStream();
155
            byte[] buf = new byte[4096];
156
            int readBytes;
157
            while ((readBytes = in.read(buf)) > 0)
158
            {
159
                out.write(buf, 0, readBytes);
160
            }
161
            return out.toByteArray();
162
        }
163
        catch ( IOException e )
164
        {
165
            log.log(POILogger.INFO, "Possibly corrupt compression or non-compressed data", e);
166
            return data;
167
        }
168
    }
169
170
    /**
171
     * Returns the number of bytes that are required to serialize this record.
172
     *
173
     * @return Number of bytes
174
     */
175
    public int getRecordSize()
176
    {
177
        return 8 + 50 + raw_pictureData.length;
178
    }
179
180
    public byte[] getUID()
181
    {
182
        return field_1_UID;
183
    }
184
185
    public void setUID( byte[] field_1_UID )
186
    {
187
        this.field_1_UID = field_1_UID;
188
    }
189
190
    public int getUncompressedSize()
191
    {
192
        return field_2_cb;
193
    }
194
195
    public void setUncompressedSize(int uncompressedSize)
196
    {
197
        field_2_cb = uncompressedSize;
198
    }
199
200
    public Rectangle getBounds()
201
    {
202
        return new Rectangle(field_3_rcBounds_x1,
203
                             field_3_rcBounds_y1,
204
                             field_3_rcBounds_x2 - field_3_rcBounds_x1,
205
                             field_3_rcBounds_y2 - field_3_rcBounds_y1);
206
    }
207
208
    public void setBounds(Rectangle bounds)
209
    {
210
        field_3_rcBounds_x1 = bounds.x;
211
        field_3_rcBounds_y1 = bounds.y;
212
        field_3_rcBounds_x2 = bounds.x + bounds.width;
213
        field_3_rcBounds_y2 = bounds.y + bounds.height;
214
    }
215
216
    public Dimension getSizeEMU()
217
    {
218
        return new Dimension(field_4_ptSize_w, field_4_ptSize_h);
219
    }
220
221
    public void setSizeEMU(Dimension sizeEMU)
222
    {
223
        field_4_ptSize_w = sizeEMU.width;
224
        field_4_ptSize_h = sizeEMU.height;
225
    }
226
227
    public int getCompressedSize()
228
    {
229
        return field_5_cbSave;
230
    }
231
232
    public void setCompressedSize(int compressedSize)
233
    {
234
        field_5_cbSave = compressedSize;
235
    }
236
237
    public boolean isCompressed()
238
    {
239
        return (field_6_fCompression == 0);
240
    }
241
242
    public void setCompressed(boolean compressed)
243
    {
244
        field_6_fCompression = compressed ? 0 : (byte)0xFE;
245
    }
246
247
    // filtering is always 254 according to available docs, so no point giving it a setter method.
248
249
    public String toString()
250
    {
251
        String nl = System.getProperty( "line.separator" );
252
253
        String extraData;
254
        ByteArrayOutputStream b = new ByteArrayOutputStream();
255
        try
256
        {
257
            HexDump.dump( this.field_pictureData, 0, b, 0 );
258
            extraData = b.toString();
259
        }
260
        catch ( Exception e )
261
        {
262
            extraData = e.toString();
263
        }
264
        return getClass().getName() + ":" + nl +
265
                "  RecordId: 0x" + HexDump.toHex( getRecordId() ) + nl +
266
                "  Options: 0x" + HexDump.toHex( getOptions() ) + nl +
267
                "  UID: 0x" + HexDump.toHex( field_1_UID ) + nl +
268
                "  Uncompressed Size: " + HexDump.toHex( field_2_cb ) + nl +
269
                "  Bounds: " + getBounds() + nl +
270
                "  Size in EMU: " + getSizeEMU() + nl +
271
                "  Compressed Size: " + HexDump.toHex( field_5_cbSave ) + nl +
272
                "  Compression: " + HexDump.toHex( field_6_fCompression ) + nl +
273
                "  Filter: " + HexDump.toHex( field_7_fFilter ) + nl +
274
                "  Extra Data:" + nl + extraData;
275
    }
276
277
}

Return to bug 43125