2
Copyright 2008 Brad Hards <bradh@frogmouth.net>
3
Copyright 2009 Inge Wallin <inge@lysator.liu.se>
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.
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.
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/>.
20
#include "EmfRecords.h"
27
/*****************************************************************************/
29
BitmapInfoHeader::BitmapInfoHeader( QDataStream &stream )
31
stream >> m_headerSize;
33
//kDebug(31000) << "Width:" << m_width;
35
//kDebug(31000) << "Height:" << m_height;
37
// kDebug(33100) << "planes:" << m_planes;
39
// kDebug(33100) << "BitCount:" << m_bitCount;
40
stream >> m_compression;
41
//kDebug(31000) << "Compression:" << m_compression;
42
stream >> m_imageSize;
43
// kDebug(33100) << "ImageSize:" << m_imageSize;
44
stream >> m_xPelsPerMeter;
45
stream >> m_yPelsPerMeter;
46
stream >> m_colorUsed;
47
stream >> m_colorImportant;
50
BitmapInfoHeader::~BitmapInfoHeader()
55
/*****************************************************************************/
56
BitBltRecord::BitBltRecord( QDataStream &stream )
59
qint32 x, y, width, height;
60
stream >> x >> y >> width >> height;
61
kDebug(31000) << "Bounds" << x << y << width << height;
62
m_Bounds = QRect( QPoint(x, y), QSize(width, height));
70
//kDebug(31000) << "Destination" << m_xDest << m_yDest << m_cxDest << m_cyDest;
72
stream >> m_BitBltRasterOperation;
73
//kDebug(31000) << "bitblt raster operation:" << m_BitBltRasterOperation;
76
//kDebug(31000) << "Sourcd" << m_xSrc << m_ySrc;
78
float M11, M12, M21, M22, Dx, Dy;
85
m_XFormSrc = QMatrix( M11, M12, M21, M22, Dx, Dy );
86
//kDebug(31000) << m_XFormSrc;
88
stream >> m_red >> m_green >> m_blue >> m_reserved;
90
stream >> m_offBmiSrc;
92
stream >> m_offBitsSrc;
93
stream >> m_cbBitsSrc;
94
if ( ( m_cbBmiSrc == 0 ) && ( m_cbBmiSrc == 0 ) ) {
97
if ( m_cbBmiSrc == 40 ) {
98
m_BmiSrc = new BitmapInfoHeader( stream );
100
//kDebug(31000) << "m_cbBmiSrc:" << m_cbBmiSrc;
104
m_imageData.resize( m_cbBitsSrc );
105
stream.readRawData( m_imageData.data(), m_cbBitsSrc );
108
BitBltRecord::~BitBltRecord()
112
bool BitBltRecord::hasImage() const
114
return ( ( m_cbBmiSrc != 0 ) && ( m_cbBmiSrc != 0 ) );
117
QImage* BitBltRecord::image()
120
if ( ! hasImage() ) {
124
if ( m_image != 0 ) {
128
QImage::Format format = QImage::Format_Invalid;
129
if ( m_BmiSrc->bitCount() == BI_BITCOUNT_4 ) {
130
if ( m_BmiSrc->compression() == 0x00 ) {
131
format = QImage::Format_RGB555;
133
kDebug(33100) << "Unexpected compression format for BI_BITCOUNT_4:"
134
<< m_BmiSrc->compression();
137
} else if ( m_BmiSrc->bitCount() == BI_BITCOUNT_5 ) {
138
format = QImage::Format_RGB888;
140
kDebug(33100) << "Unexpected format:" << m_BmiSrc->bitCount();
143
m_image = new QImage( (const uchar*)m_imageData.constData(),
144
m_BmiSrc->width(), m_BmiSrc->height(), format );
149
/*****************************************************************************/
150
StretchDiBitsRecord::StretchDiBitsRecord( QDataStream &stream )
161
stream >> m_offBmiSrc;
162
stream >> m_cbBmiSrc;
163
stream >> m_offBitsSrc;
164
stream >> m_cbBitsSrc;
165
stream >> m_UsageSrc;
166
stream >> m_BitBltRasterOperation;
171
kDebug(31000) << "m_cbBmiSrc =" << m_cbBmiSrc;
172
kDebug(31000) << "m_offBmiSrc =" << m_offBmiSrc;
173
kDebug(31000) << "m_cbBitsSrc =" << m_cbBitsSrc;
174
kDebug(31000) << "m_offBitsSrc =" << m_offBitsSrc;
175
//kDebug(31000) << "m_BitBltRasterOperation =" << hex << m_BitBltRasterOperation << dec;
178
// Read away those bytes that preceed the header. These are undefined
179
// according to the spec. 80 is the size of the record above.
182
while (m_offBmiSrc - padding > 80) {
186
m_BmiSrc = new BitmapInfoHeader( stream );
188
// 40 is the size of the header record.
189
while (m_offBitsSrc - padding > 80 + 40) {
193
m_imageData.resize( m_cbBitsSrc );
194
stream.readRawData( m_imageData.data(), m_cbBitsSrc );
197
StretchDiBitsRecord::~StretchDiBitsRecord()
203
QRect StretchDiBitsRecord::bounds() const
208
QImage* StretchDiBitsRecord::image()
210
if ( m_image != 0 ) {
214
QImage::Format format = QImage::Format_Invalid;
215
if (m_BmiSrc->bitCount() == BI_BITCOUNT_1) {
216
format = QImage::Format_Mono;
217
} else if ( m_BmiSrc->bitCount() == BI_BITCOUNT_4 ) {
218
if ( m_BmiSrc->compression() == BI_RGB ) {
219
format = QImage::Format_RGB555;
221
kDebug(33100) << "Unexpected compression format for BI_BITCOUNT_4:"
222
<< m_BmiSrc->compression();
225
} else if ( m_BmiSrc->bitCount() == BI_BITCOUNT_5 ) {
226
format = QImage::Format_RGB888;
228
kDebug(31000) << "Unexpected format:" << m_BmiSrc->bitCount();
232
// According to MS-WMF 2.2.2.3, the sign of the height decides if
233
// this is a compressed bitmap or not.
234
if (m_BmiSrc->height() > 0) {
235
// This bitmap is a top-down bitmap without compression.
236
m_image = new QImage( (const uchar*)m_imageData.constData(),
237
m_BmiSrc->width(), m_BmiSrc->height(), format );
238
// we have to mirror this bitmap in the X axis.
239
*m_image = m_image->mirrored(false, true);
241
// This bitmap is a bottom-up bitmap which uses compression.
242
switch (m_BmiSrc->compression()) {
244
m_image = new QImage( (const uchar*)m_imageData.constData(),
245
m_BmiSrc->width(), -m_BmiSrc->height(), format );
248
// These compressions are not yet supported, so return an empty image.
258
m_image = new QImage(m_BmiSrc->width(), m_BmiSrc->height(), format);
266
/*****************************************************************************/
267
ExtCreateFontIndirectWRecord::ExtCreateFontIndirectWRecord( QDataStream &stream, quint32 size )
272
// TODO: Check size, we might need to do a LogFontExDv parse
277
stream >> m_escapement;
280
stream >> m_orientation;
287
stream >> m_underline;
288
stream >> m_strikeout;
292
stream >> m_outPrecision;
293
stream >> m_clipPrecision;
295
stream >> m_pitchAndFamily;
299
for ( int i = 0; i < 32; ++i ) {
304
for ( int i = 0; i < 32; ++i ) {
305
if ( ! myChar[i].isNull() ) {
306
m_facename.append( myChar[i] );
311
for ( int i = 0; i < 64; ++i ) {
316
for ( int i = 0; i < 64; ++i ) {
317
if ( ! myChar[i].isNull() ) {
318
m_fullName.append( myChar[i] );
321
kDebug(33100) << "fullName:" << m_fullName;
323
for ( int i = 0; i < 32; ++i ) {
327
for ( int i = 0; i < 32; ++i ) {
328
if ( ! myChar[i].isNull() ) {
329
m_style.append( myChar[i] );
332
kDebug(33100) << "style:" << m_style;
334
for ( int i = 0; i < 32; ++i ) {
338
for ( int i = 0; i < 32; ++i ) {
339
if ( ! myChar[i].isNull() ) {
340
m_script.append( myChar[i] );
343
kDebug(33100) << "script:" << m_script;
345
soakBytes( stream, size ); // rest of the record.
348
ExtCreateFontIndirectWRecord::~ExtCreateFontIndirectWRecord()
352
void ExtCreateFontIndirectWRecord::soakBytes( QDataStream &stream, int numBytes )
355
for ( int i = 0; i < numBytes; ++i ) {
360
/*****************************************************************************/
361
EmrTextObject::EmrTextObject( QDataStream &stream, quint32 size, TextType textType )
363
stream >> m_referencePoint;
366
stream >> m_charCount;
369
stream >> m_offString;
371
// 36 bytes for the body of the parent structure (EMR_EXTTEXTOUTA or EMR_EXTTEXTOUTW)
372
// then parts of the EmrText structure
373
quint32 offString = m_offString - 36 - 8 - 4 - 4;
379
stream >> m_rectangle;
386
// as for offString. 36 bytes for parent, then the earlier parts of EmrText
387
quint32 offDx = m_offDx - 36 - 8 - 4 - 4 - 4 - 16 - 4;
389
soakBytes( stream, offString ); // skips over UndefinedSpace1.
393
if ( textType == SixteenBitChars ) {
394
m_textString = recordWChars( stream, m_charCount );
395
size -= 2 * m_charCount;
396
offDx -= 2 * m_charCount;
398
m_textString = recordChars( stream, m_charCount );
400
offDx -= m_charCount;
402
// TODO: parse the spacing array
403
soakBytes( stream, size );
406
EmrTextObject::~EmrTextObject()
410
QPoint EmrTextObject::referencePoint() const
412
return m_referencePoint;
415
QString EmrTextObject::textString() const
420
QString EmrTextObject::recordWChars( QDataStream &stream, int numChars )
424
for ( int i = 0; i < numChars; ++i ) {
426
text.append( myChar );
431
QString EmrTextObject::recordChars( QDataStream &stream, int numChars )
435
for ( int i = 0; i < numChars; ++i ) {
437
text.append( QChar( myChar ) );
442
void EmrTextObject::soakBytes( QDataStream &stream, int numBytes )
445
for ( int i = 0; i < numBytes; ++i ) {
450
/*****************************************************************************/
452
ExtTextOutARecord::ExtTextOutARecord( QDataStream &stream, quint32 size )
457
stream >> m_iGraphicsMode;
463
m_emrText = new EmrTextObject( stream, size, EmrTextObject::EightBitChars );
466
ExtTextOutARecord::~ExtTextOutARecord()
471
QPoint ExtTextOutARecord::referencePoint() const
473
return m_emrText->referencePoint();
476
QString ExtTextOutARecord::textString() const
478
return m_emrText->textString();