1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <sal/log.hxx>
22 #include <unotools/configmgr.hxx>
23 #include <vcl/BitmapTools.hxx>
27 #include "elements.hxx"
31 Color
BMCOL(sal_uInt32 _col
) {
32 return Color( static_cast<sal_Int8
>(_col
>> 16 ), static_cast<sal_Int8
>( _col
>> 8 ), static_cast<sal_Int8
>(_col
) );
37 CGMBitmap::CGMBitmap( CGM
& rCGM
) :
39 pCGMBitmapDescriptor ( new CGMBitmapDescriptor
)
41 ImplGetBitmap( *pCGMBitmapDescriptor
);
45 CGMBitmap::~CGMBitmap()
51 bool isLegalBitsPerPixel(sal_uInt32 nBitsPerPixel
)
53 switch (nBitsPerPixel
)
69 void CGMBitmap::ImplGetBitmap( CGMBitmapDescriptor
& rDesc
)
71 rDesc
.mbStatus
= true;
73 if (!ImplGetDimensions(rDesc
) || !rDesc
.mpBuf
)
76 if (!isLegalBitsPerPixel(rDesc
.mnDstBitsPerPixel
))
78 rDesc
.mbStatus
= false;
86 vcl::bitmap::RawBitmap
aBitmap( Size( rDesc
.mnX
, rDesc
.mnY
), 24 );
88 // the picture may either be read from left to right or right to left, from top to bottom ...
90 tools::Long nxCount
= rDesc
.mnX
+ 1; // +1 because we are using prefix decreasing
91 tools::Long nyCount
= rDesc
.mnY
+ 1;
92 tools::Long nx
, ny
, nxC
;
94 switch ( rDesc
.mnDstBitsPerPixel
) {
97 std::vector
<Color
> palette(2);
98 if ( rDesc
.mnLocalColorPrecision
== 1 )
99 palette
= ImplGeneratePalette( rDesc
);
101 palette
[0] = BMCOL( mpCGM
->pElement
->nBackGroundColor
);
102 palette
[1] = ( mpCGM
->pElement
->nAspectSourceFlags
& ASF_FILLINTERIORSTYLE
)
103 ? BMCOL( mpCGM
->pElement
->pFillBundle
->GetColor() )
104 : BMCOL( mpCGM
->pElement
->aFillBundle
.GetColor() );
106 for (ny
= 0; bOk
&& --nyCount
; ny
++, rDesc
.mpBuf
+= rDesc
.mnScanSize
) {
108 for ( nx
= 0; --nxC
; nx
++ ) {
109 // this is not fast, but a one bit/pixel format is rarely used
110 const sal_uInt8
* pPos
= rDesc
.mpBuf
+ (nx
>> 3);
111 if (pPos
>= rDesc
.mpEndBuf
)
113 SAL_WARN("filter.icgm", "buffer is too small");
117 sal_uInt8 colorIndex
= static_cast<sal_uInt8
>((*pPos
>> ((nx
& 7)^7))) & 1;
118 aBitmap
.SetPixel(ny
, nx
, palette
[colorIndex
]);
126 auto palette
= ImplGeneratePalette( rDesc
);
127 for (ny
= 0; bOk
&& --nyCount
; ny
++, rDesc
.mpBuf
+= rDesc
.mnScanSize
) {
129 for ( nx
= 0; --nxC
; nx
++ ) {
130 // this is not fast, but a two bits/pixel format is rarely used
131 const sal_uInt8
* pPos
= rDesc
.mpBuf
+ (nx
>> 2);
132 if (pPos
>= rDesc
.mpEndBuf
)
134 SAL_WARN("filter.icgm", "buffer is too small");
138 aBitmap
.SetPixel(ny
, nx
, palette
[static_cast<sal_uInt8
>( (*pPos
>> (((nx
& 3)^3) << 1))) & 3]);
146 auto palette
= ImplGeneratePalette( rDesc
);
147 for (ny
= 0; bOk
&& --nyCount
; ny
++, rDesc
.mpBuf
+= rDesc
.mnScanSize
) {
149 sal_uInt8
* pTemp
= rDesc
.mpBuf
;
150 for ( nx
= 0; --nxC
; nx
++ ) {
152 if (pTemp
>= rDesc
.mpEndBuf
)
154 SAL_WARN("filter.icgm", "buffer is too small");
159 sal_uInt8 nDat
= *pTemp
++;
161 aBitmap
.SetPixel(ny
, nx
, palette
[static_cast<sal_uInt8
>(nDat
>> 4)]);
164 aBitmap
.SetPixel(ny
, nx
, palette
[static_cast<sal_uInt8
>(nDat
& 15)]);
174 auto palette
= ImplGeneratePalette( rDesc
);
175 for (ny
= 0; bOk
&& --nyCount
; ny
++, rDesc
.mpBuf
+= rDesc
.mnScanSize
) {
176 sal_uInt8
* pTemp
= rDesc
.mpBuf
;
178 for ( nx
= 0; --nxC
; nx
++ ) {
180 if (pTemp
>= rDesc
.mpEndBuf
)
182 SAL_WARN("filter.icgm", "buffer is too small");
187 aBitmap
.SetPixel(ny
, nx
, palette
[*(pTemp
++)]);
196 for (ny
= 0; bOk
&& --nyCount
; ny
++, rDesc
.mpBuf
+= rDesc
.mnScanSize
) {
197 sal_uInt8
* pTemp
= rDesc
.mpBuf
;
199 for ( nx
= 0; --nxC
; nx
++ ) {
201 if (pTemp
+ 2 >= rDesc
.mpEndBuf
)
203 SAL_WARN("filter.icgm", "buffer is too small");
208 aBitmapColor
.SetRed( *pTemp
++ );
209 aBitmapColor
.SetGreen( *pTemp
++ );
210 aBitmapColor
.SetBlue( *pTemp
++ );
211 aBitmap
.SetPixel(ny
, nx
, aBitmapColor
);
218 if ( rDesc
.mbStatus
)
219 rDesc
.mxBitmap
= vcl::bitmap::CreateFromData(std::move(aBitmap
));
222 double nX
= rDesc
.mnR
.X
- rDesc
.mnQ
.X
;
223 double nY
= rDesc
.mnR
.Y
- rDesc
.mnQ
.Y
;
225 rDesc
.mndy
= sqrt( nX
* nX
+ nY
* nY
);
227 nX
= rDesc
.mnR
.X
- rDesc
.mnP
.X
;
228 nY
= rDesc
.mnR
.Y
- rDesc
.mnP
.Y
;
230 rDesc
.mndx
= sqrt( nX
* nX
+ nY
* nY
);
232 nX
= rDesc
.mnR
.X
- rDesc
.mnP
.X
;
233 nY
= rDesc
.mnR
.Y
- rDesc
.mnP
.Y
;
235 double fSqrt
= sqrt(nX
* nX
+ nY
* nY
);
236 rDesc
.mnOrientation
= fSqrt
!= 0.0 ? (acos(nX
/ fSqrt
) * 57.29577951308) : 0.0;
238 rDesc
.mnOrientation
= 360 - rDesc
.mnOrientation
;
240 nX
= rDesc
.mnQ
.X
- rDesc
.mnR
.X
;
241 nY
= rDesc
.mnQ
.Y
- rDesc
.mnR
.Y
;
243 double fAngle
= 0.01745329251994 * ( 360 - rDesc
.mnOrientation
);
244 double fSin
= sin(fAngle
);
245 double fCos
= cos(fAngle
);
246 nX
= fCos
* nX
+ fSin
* nY
;
247 nY
= -( fSin
* nX
- fCos
* nY
);
249 fSqrt
= sqrt(nX
* nX
+ nY
* nY
);
250 fAngle
= fSqrt
!= 0.0 ? (acos(nX
/ fSqrt
) * 57.29577951308) : 0.0;
252 fAngle
= 360 - fAngle
;
254 if ( fAngle
> 180 ) { // is the picture build upwards or downwards ?
255 rDesc
.mnOrigin
= rDesc
.mnP
;
257 rDesc
.mbVMirror
= true;
258 rDesc
.mnOrigin
= rDesc
.mnP
;
259 rDesc
.mnOrigin
.X
+= rDesc
.mnQ
.X
- rDesc
.mnR
.X
;
260 rDesc
.mnOrigin
.Y
+= rDesc
.mnQ
.Y
- rDesc
.mnR
.Y
;
263 catch (const std::bad_alloc
&)
265 rDesc
.mbStatus
= false;
269 std::vector
<Color
> CGMBitmap::ImplGeneratePalette( CGMBitmapDescriptor
const & rDesc
)
271 sal_uInt16 nColors
= sal::static_int_cast
< sal_uInt16
>(
272 1 << rDesc
.mnDstBitsPerPixel
);
273 std::vector
<Color
> palette( nColors
);
274 for ( sal_uInt16 i
= 0; i
< nColors
; i
++ )
276 palette
[i
] = BMCOL( mpCGM
->pElement
->aLatestColorTable
[ i
] );
282 bool CGMBitmap::ImplGetDimensions( CGMBitmapDescriptor
& rDesc
)
284 mpCGM
->ImplGetPoint( rDesc
.mnP
); // parallelogram p < - > r
285 mpCGM
->ImplGetPoint( rDesc
.mnQ
); // |
286 mpCGM
->ImplGetPoint( rDesc
.mnR
); // q
287 sal_uInt32 nPrecision
= mpCGM
->pElement
->nIntegerPrecision
;
288 rDesc
.mnX
= mpCGM
->ImplGetUI( nPrecision
);
289 rDesc
.mnY
= mpCGM
->ImplGetUI( nPrecision
);
290 rDesc
.mnLocalColorPrecision
= mpCGM
->ImplGetI( nPrecision
);
291 rDesc
.mnScanSize
= 0;
292 switch( rDesc
.mnLocalColorPrecision
)
294 case tools::Long(0x80000001) : // monochrome ( bit = 0->backgroundcolor )
295 case 0 : // bit = 1->fillcolor
296 rDesc
.mnDstBitsPerPixel
= 1;
298 case 1 : // 2 color indexed ( monochrome )
300 rDesc
.mnDstBitsPerPixel
= 1;
302 case 2 : // 4 color indexed
304 rDesc
.mnDstBitsPerPixel
= 2;
306 case 4 : // 16 color indexed
308 rDesc
.mnDstBitsPerPixel
= 4;
310 case 8 : // 256 color indexed
312 rDesc
.mnDstBitsPerPixel
= 8;
313 rDesc
.mnScanSize
= rDesc
.mnX
;
317 rDesc
.mbStatus
= false;
319 case 24 : // 24 bit directColor ( 8 bits each component )
321 rDesc
.mnDstBitsPerPixel
= 24;
325 rDesc
.mbStatus
= false;
329 // mnCompressionMode == 0 : CCOMP_RUNLENGTH
330 // == 1 : CCOMP_PACKED ( no compression. each row starts on a 4 byte boundary )
331 if ( ( rDesc
.mnCompressionMode
= mpCGM
->ImplGetUI16() ) != 1 )
332 rDesc
.mbStatus
= false;
334 if ( !( rDesc
.mnX
|| rDesc
.mnY
) )
335 rDesc
.mbStatus
= false;
337 sal_uInt32 nHeaderSize
= 2 + 3 * nPrecision
+ 3 * mpCGM
->ImplGetPointSize();
339 sal_uInt32 nWidthBits
;
340 if (o3tl::checked_multiply(rDesc
.mnX
, rDesc
.mnDstBitsPerPixel
, nWidthBits
))
342 rDesc
.mbStatus
= false;
346 rDesc
.mnScanSize
= (nWidthBits
+ 7) >> 3;
348 sal_uInt32 nScanSize
;
349 nScanSize
= rDesc
.mnScanSize
;
350 if ( ( nScanSize
* rDesc
.mnY
+ nHeaderSize
) != mpCGM
->mnElementSize
) // try a scansize without dw alignment
352 nScanSize
= ( rDesc
.mnScanSize
+ 1 ) & ~1;
353 if ( ( nScanSize
* rDesc
.mnY
+ nHeaderSize
) != mpCGM
->mnElementSize
) // then we'll try word alignment
355 nScanSize
= ( rDesc
.mnScanSize
+ 3 ) & ~3;
356 if ( ( nScanSize
* rDesc
.mnY
+ nHeaderSize
) != mpCGM
->mnElementSize
) // and last we'll try dword alignment
358 nScanSize
= ( rDesc
.mnScanSize
+ 1 ) & ~1; // and LAST BUT NOT LEAST we'll try word alignment without aligning the last line
359 if ( ( nScanSize
* ( rDesc
.mnY
- 1 ) + rDesc
.mnScanSize
+ nHeaderSize
) != mpCGM
->mnElementSize
)
361 nScanSize
= ( rDesc
.mnScanSize
+ 3 ) & ~3;
362 if ( ( nScanSize
* ( rDesc
.mnY
- 1 ) + rDesc
.mnScanSize
+ nHeaderSize
) != mpCGM
->mnElementSize
)
364 mpCGM
->mnParaSize
= 0; // this format is corrupt
365 rDesc
.mbStatus
= false;
371 rDesc
.mnScanSize
= nScanSize
;
372 if ( rDesc
.mbStatus
)
374 rDesc
.mpBuf
= mpCGM
->mpSource
+ mpCGM
->mnParaSize
; // mpBuf now points to the first scanline
375 rDesc
.mpEndBuf
= mpCGM
->mpEndValidSource
;
376 mpCGM
->mnParaSize
+= rDesc
.mnScanSize
* rDesc
.mnY
;
378 return rDesc
.mbStatus
;
382 void CGMBitmap::ImplInsert( CGMBitmapDescriptor
const & rSource
, CGMBitmapDescriptor
& rDest
)
384 if (utl::ConfigManager::IsFuzzing() && rDest
.mxBitmap
.GetSizePixel().Height() + rSource
.mnY
> SAL_MAX_UINT16
)
386 SAL_WARN("filter.icgm", "bitmap would expand too much");
387 rDest
.mbStatus
= false;
390 rDest
.mxBitmap
.Expand( 0, rSource
.mnY
);
391 rDest
.mxBitmap
.CopyPixel( tools::Rectangle( Point( 0, rDest
.mnY
), Size( rSource
.mnX
, rSource
.mnY
) ),
392 tools::Rectangle( Point( 0, 0 ), Size( rSource
.mnX
, rSource
.mnY
) ), &rSource
.mxBitmap
);
394 if ( ( rSource
.mnR
.Y
== rDest
.mnQ
.Y
) && ( rSource
.mnR
.X
== rDest
.mnQ
.X
) )
395 { // Insert on Bottom
396 if ( mpCGM
->mnVDCYmul
== -1 )
397 rDest
.mnOrigin
= rSource
.mnOrigin
; // new origin
398 FloatPoint aFloatPoint
;
399 aFloatPoint
.X
= rSource
.mnQ
.X
- rSource
.mnR
.X
;
400 aFloatPoint
.Y
= rSource
.mnQ
.Y
- rSource
.mnR
.Y
;
401 rDest
.mnQ
.X
+= aFloatPoint
.X
;
402 rDest
.mnQ
.Y
+= aFloatPoint
.Y
;
403 rDest
.mnP
= rSource
.mnP
;
404 rDest
.mnR
= rSource
.mnR
;
408 if ( mpCGM
->mnVDCYmul
== 1 )
409 rDest
.mnOrigin
= rSource
.mnOrigin
; // new origin
410 rDest
.mnP
= rSource
.mnP
;
411 rDest
.mnR
= rSource
.mnR
;
413 rDest
.mnY
+= rSource
.mnY
;
414 rDest
.mndy
+= rSource
.mndy
;
417 std::unique_ptr
<CGMBitmap
> CGMBitmap::GetNext()
419 std::unique_ptr
<CGMBitmap
> xCGMTempBitmap
;
420 if (!!pCGMBitmapDescriptor
->mxBitmap
&& pCGMBitmapDescriptor
->mbStatus
)
422 xCGMTempBitmap
.reset(new CGMBitmap(*mpCGM
));
423 if ( ( static_cast<tools::Long
>(xCGMTempBitmap
->pCGMBitmapDescriptor
->mnOrientation
) == static_cast<tools::Long
>(pCGMBitmapDescriptor
->mnOrientation
) ) &&
424 ( ( ( xCGMTempBitmap
->pCGMBitmapDescriptor
->mnR
.X
== pCGMBitmapDescriptor
->mnQ
.X
) &&
425 ( xCGMTempBitmap
->pCGMBitmapDescriptor
->mnR
.Y
== pCGMBitmapDescriptor
->mnQ
.Y
) ) ||
426 ( ( xCGMTempBitmap
->pCGMBitmapDescriptor
->mnQ
.X
== pCGMBitmapDescriptor
->mnR
.X
) &&
427 ( xCGMTempBitmap
->pCGMBitmapDescriptor
->mnQ
.Y
== pCGMBitmapDescriptor
->mnR
.Y
) ) ) )
429 ImplInsert( *(xCGMTempBitmap
->pCGMBitmapDescriptor
), *pCGMBitmapDescriptor
);
430 xCGMTempBitmap
.reset();
431 return xCGMTempBitmap
;
434 pCGMBitmapDescriptor
.swap(xCGMTempBitmap
->pCGMBitmapDescriptor
);
436 return xCGMTempBitmap
;
439 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */