1 /*
2 Copyright 2008 Brad Hards <bradh@frogmouth.net>
3 Copyright 2009 Inge Wallin <inge@lysator.liu.se>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "EmfRecords.h"
20
21 #include "EmfEnums.h"
22 #include "EmfObjects.h"
23 #include "Bitmap.h"
24
25 #include <VectorImageDebug.h>
26
27 namespace Libemf
28 {
29
30
31 /*****************************************************************************/
32
33
BitBltRecord(QDataStream & stream,quint32 recordSize)34 BitBltRecord::BitBltRecord( QDataStream &stream, quint32 recordSize )
35 : m_bitmap(0)
36 {
37 //debugVectorImage << "stream position at the start: " << stream.device()->pos();
38 //debugVectorImage << "record size: " << recordSize;
39
40 stream >> m_bounds;
41
42 stream >> m_xDest; // x, y of upper left corner of the destination.
43 stream >> m_yDest;
44 stream >> m_cxDest; // width, height of the rectangle in logical coords.
45 stream >> m_cyDest;
46 //debugVectorImage << "Destination" << m_xDest << m_yDest << m_cxDest << m_cyDest;
47
48 stream >> m_BitBltRasterOperation;
49 //debugVectorImage << "bitblt raster operation:" << hex << m_BitBltRasterOperation << dec;
50
51 stream >> m_xSrc; // x, y of the source
52 stream >> m_ySrc;
53 //debugVectorImage << "Source" << m_xSrc << m_ySrc;
54
55 //debugVectorImage << "position before the matrix: " << stream.device()->pos();
56 stream.setFloatingPointPrecision(QDataStream::SinglePrecision);
57 float M11, M12, M21, M22, Dx, Dy;
58 stream >> M11; // Transformation matrix
59 stream >> M12;
60 stream >> M21;
61 stream >> M22;
62 stream >> Dx;
63 stream >> Dy;
64 m_XFormSrc = QTransform( M11, M12, M21, M22, Dx, Dy );
65 //debugVectorImage << "Matrix" << m_XFormSrc;
66 //debugVectorImage << "position after the matrix: " << stream.device()->pos();
67
68 stream >> m_red >> m_green >> m_blue >> m_reserved;
69 //debugVectorImage << "Background color" << m_red << m_green << m_blue << m_reserved;
70 //debugVectorImage << "position after background color: " << stream.device()->pos();
71
72 stream >> m_UsageSrc;
73 //debugVectorImage << "Color table interpretation" << m_UsageSrc;
74
75 stream >> m_offBmiSrc; // Offset to start of bitmap header from start of record
76 stream >> m_cbBmiSrc; // Size of source bitmap header
77 stream >> m_offBitsSrc; // Offset to source bitmap from start of record
78 stream >> m_cbBitsSrc; // Size of source bitmap
79 #if 0
80 debugVectorImage << "header offset:" << m_offBmiSrc;
81 debugVectorImage << "header size: " << m_cbBmiSrc;
82 debugVectorImage << "bitmap offset:" << m_offBitsSrc;
83 debugVectorImage << "bitmap size: " << m_cbBitsSrc;
84 #endif
85
86 //debugVectorImage << "stream position before the image: " << stream.device()->pos();
87 if (m_cbBmiSrc > 0) {
88 m_bitmap = new Bitmap( stream, recordSize, 8 + 23 * 4, // header + 23 ints
89 m_offBmiSrc, m_cbBmiSrc,
90 m_offBitsSrc, m_cbBitsSrc );
91 }
92
93 //debugVectorImage << "stream position at the end: " << stream.device()->pos();
94 }
95
~BitBltRecord()96 BitBltRecord::~BitBltRecord()
97 {
98 delete m_bitmap;
99 }
100
hasImage() const101 bool BitBltRecord::hasImage() const
102 {
103 return m_bitmap && m_bitmap->hasImage();
104 //return ( ( m_cbBmiSrc != 0 ) && ( m_cbBitsSrc != 0 ) );
105 }
106
image()107 QImage BitBltRecord::image()
108 {
109 return m_bitmap->image();
110 #if 0
111 if ( ! hasImage() ) {
112 return 0;
113 }
114
115 if ( m_image != 0 ) {
116 return m_image;
117 }
118
119 QImage::Format format = QImage::Format_Invalid;
120 if ( m_BmiSrc->bitCount() == BI_BITCOUNT_4 ) {
121 if ( m_BmiSrc->compression() == 0x00 ) {
122 format = QImage::Format_RGB555;
123 } else {
124 debugVectorImage << "Unexpected compression format for BI_BITCOUNT_4:"
125 << m_BmiSrc->compression();
126 Q_ASSERT( 0 );
127 }
128 } else if ( m_BmiSrc->bitCount() == BI_BITCOUNT_5 ) {
129 format = QImage::Format_RGB888;
130 } else {
131 debugVectorImage << "Unexpected format:" << m_BmiSrc->bitCount();
132 Q_ASSERT( 0 );
133 }
134 m_image = new QImage( (const uchar*)m_imageData.constData(),
135 m_BmiSrc->width(), m_BmiSrc->height(), format );
136
137 return m_image;
138 #endif
139 }
140
141 /*****************************************************************************/
StretchDiBitsRecord(QDataStream & stream,quint32 recordSize)142 StretchDiBitsRecord::StretchDiBitsRecord( QDataStream &stream, quint32 recordSize )
143 : m_bitmap(0)
144 {
145 //debugVectorImage << "stream position at the start: " << stream.device()->pos();
146 //debugVectorImage << "recordSize =" << recordSize;
147
148 stream >> m_Bounds;
149 stream >> m_xDest;
150 stream >> m_yDest;
151 stream >> m_xSrc;
152 stream >> m_ySrc;
153 stream >> m_cxSrc;
154 stream >> m_cySrc;
155
156 stream >> m_offBmiSrc;
157 stream >> m_cbBmiSrc;
158 stream >> m_offBitsSrc;
159 stream >> m_cbBitsSrc;
160
161 stream >> m_UsageSrc; // How to interpret color table values.
162 stream >> m_BitBltRasterOperation;
163 stream >> m_cxDest;
164 stream >> m_cyDest;
165 #if 0
166 debugVectorImage << "bounds:" << m_Bounds;
167 debugVectorImage << "destination:" << QPoint(m_xDest, m_yDest) << QSize(m_cxDest, m_cyDest);
168 debugVectorImage << "source:" << QPoint(m_xSrc, m_ySrc) << QSize(m_cxSrc, m_cySrc);
169 debugVectorImage << "header offset:" << m_offBmiSrc;
170 debugVectorImage << "header size: " << m_cbBmiSrc;
171 debugVectorImage << "bitmap offset:" << m_offBitsSrc;
172 debugVectorImage << "bitmap size: " << m_cbBitsSrc;
173
174 debugVectorImage << "m_BitBltRasterOperation =" << hex << m_BitBltRasterOperation << dec;
175 #endif
176
177 //debugVectorImage << "stream position before the image: " << stream.device()->pos();
178 if (m_cbBmiSrc > 0) {
179 m_bitmap = new Bitmap( stream, recordSize, 8 + 18 * 4, // header + 18 ints
180 m_offBmiSrc, m_cbBmiSrc,
181 m_offBitsSrc, m_cbBitsSrc );
182 }
183
184 //debugVectorImage << "stream position at the end: " << stream.device()->pos();
185 #if 0
186 // Read away those bytes that preceed the header. These are undefined
187 // according to the spec. 80 is the size of the record above.
188 qint32 dummy;
189 int padding = 0;
190 while (m_offBmiSrc - padding > 80) {
191 stream >> dummy;
192 padding += 4;
193 }
194 m_BmiSrc = new BitmapHeader( stream, m_cbBmiSrc );
195
196 // 40 is the size of the header record.
197 while (m_offBitsSrc - padding > 80 + 40) {
198 stream >> dummy;
199 padding += 4;
200 }
201 m_imageData.resize( m_cbBitsSrc );
202 stream.readRawData( m_imageData.data(), m_cbBitsSrc );
203 #endif
204 }
205
~StretchDiBitsRecord()206 StretchDiBitsRecord::~StretchDiBitsRecord()
207 {
208 delete m_bitmap;
209 }
210
bounds() const211 QRect StretchDiBitsRecord::bounds() const
212 {
213 return m_Bounds;
214 }
215
hasImage() const216 bool StretchDiBitsRecord::hasImage() const
217 {
218 return m_bitmap && m_bitmap->hasImage();
219 }
220
image()221 QImage StretchDiBitsRecord::image()
222 {
223 return m_bitmap->image();
224 #if 0
225 if ( m_image != 0 ) {
226 return m_image;
227 }
228
229 QImage::Format format = QImage::Format_Invalid;
230
231 // Start by determining which QImage format we are going to use.
232 if (m_BmiSrc->bitCount() == BI_BITCOUNT_1) {
233 format = QImage::Format_Mono;
234 } else if ( m_BmiSrc->bitCount() == BI_BITCOUNT_4 ) {
235 if ( m_BmiSrc->compression() == BI_RGB ) {
236 format = QImage::Format_RGB555;
237 } else {
238 debugVectorImage << "Unexpected compression format for BI_BITCOUNT_4:"
239 << m_BmiSrc->compression();
240 Q_ASSERT( 0 );
241 }
242 } else if ( m_BmiSrc->bitCount() == BI_BITCOUNT_5 ) {
243 format = QImage::Format_RGB888;
244 } else {
245 debugVectorImage << "Unexpected format:" << m_BmiSrc->bitCount();
246 //Q_ASSERT(0);
247 }
248
249 // According to MS-WMF 2.2.2.3, the sign of the height decides if
250 // this is a compressed bitmap or not.
251 if (m_BmiSrc->height() > 0) {
252 // This bitmap is a top-down bitmap without compression.
253 m_image = new QImage( (const uchar*)m_imageData.constData(),
254 m_BmiSrc->width(), m_BmiSrc->height(), format );
255
256 // The WMF images are in the BGR color order.
257 if (format == QImage::Format_RGB888)
258 *m_image = m_image->rgbSwapped();
259
260 // We have to mirror this bitmap in the X axis since WMF images are stored bottom-up.
261 *m_image = m_image->mirrored(false, true);
262 } else {
263 // This bitmap is a bottom-up bitmap which uses compression.
264 switch (m_BmiSrc->compression()) {
265 case BI_RGB:
266 m_image = new QImage( (const uchar*)m_imageData.constData(),
267 m_BmiSrc->width(), -m_BmiSrc->height(), format );
268 // The WMF images are in the BGR color order.
269 *m_image = m_image->rgbSwapped();
270 break;
271
272 // These compressions are not yet supported, so return an empty image.
273 case BI_RLE8:
274 case BI_RLE4:
275 case BI_BITFIELDS:
276 case BI_JPEG:
277 case BI_PNG:
278 case BI_CMYK:
279 case BI_CMYKRLE8:
280 case BI_CMYKRLE4:
281 default:
282 m_image = new QImage(m_BmiSrc->width(), m_BmiSrc->height(), format);
283 break;
284 }
285 }
286
287 return m_image;
288 #endif
289 }
290
291 /*****************************************************************************/
ExtCreateFontIndirectWRecord(QDataStream & stream,quint32 size)292 ExtCreateFontIndirectWRecord::ExtCreateFontIndirectWRecord( QDataStream &stream, quint32 size )
293 {
294 stream >> m_ihFonts;
295 size -= 12;
296
297 // TODO: Check size, we might need to do a LogFontExDv parse
298 stream >> m_height;
299 stream >> m_width;
300 size -= 8;
301
302 stream >> m_escapement;
303 size -= 4;
304
305 stream >> m_orientation;
306 size -= 4;
307
308 stream >> m_weight;
309 size -= 4;
310
311 stream >> m_italic;
312 stream >> m_underline;
313 stream >> m_strikeout;
314 stream >> m_charSet;
315 size -= 4;
316
317 stream >> m_outPrecision;
318 stream >> m_clipPrecision;
319 stream >> m_quality;
320 stream >> m_pitchAndFamily;
321 size -= 4;
322
323 QChar myChar[64];
324 for ( int i = 0; i < 32; ++i ) {
325 stream >> myChar[i];
326 }
327 size -= 64;
328
329 for ( int i = 0; i < 32; ++i ) {
330 if ( ! myChar[i].isNull() ) {
331 m_facename.append( myChar[i] );
332 }
333 }
334
335 #if 0
336 for ( int i = 0; i < 64; ++i ) {
337 stream >> myChar[i];
338 }
339 size -= 128;
340
341 for ( int i = 0; i < 64; ++i ) {
342 if ( ! myChar[i].isNull() ) {
343 m_fullName.append( myChar[i] );
344 }
345 }
346 debugVectorImage << "fullName:" << m_fullName;
347
348 for ( int i = 0; i < 32; ++i ) {
349 stream >> myChar[i];
350 }
351 size -= 64;
352 for ( int i = 0; i < 32; ++i ) {
353 if ( ! myChar[i].isNull() ) {
354 m_style.append( myChar[i] );
355 }
356 }
357 debugVectorImage << "style:" << m_style;
358
359 for ( int i = 0; i < 32; ++i ) {
360 stream >> myChar[i];
361 }
362 size -= 64;
363 for ( int i = 0; i < 32; ++i ) {
364 if ( ! myChar[i].isNull() ) {
365 m_script.append( myChar[i] );
366 }
367 }
368 debugVectorImage << "script:" << m_script;
369 #endif
370 soakBytes( stream, size ); // rest of the record.
371 }
372
~ExtCreateFontIndirectWRecord()373 ExtCreateFontIndirectWRecord::~ExtCreateFontIndirectWRecord()
374 {
375 }
376
soakBytes(QDataStream & stream,int numBytes)377 void ExtCreateFontIndirectWRecord::soakBytes( QDataStream &stream, int numBytes )
378 {
379 quint8 scratch;
380 for ( int i = 0; i < numBytes; ++i ) {
381 stream >> scratch;
382 }
383 }
384
385 }
386