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 <canvas/debug.hxx>
22 #include <tools/diagnose_ex.h>
24 #include <com/sun/star/util/Endianness.hpp>
26 #include <rtl/math.hxx>
28 #include <tools/poly.hxx>
29 #include <vcl/window.hxx>
30 #include <vcl/bitmapex.hxx>
31 #include <vcl/bmpacc.hxx>
32 #include <vcl/canvastools.hxx>
34 #include <basegfx/matrix/b2dhommatrix.hxx>
35 #include <basegfx/point/b2dpoint.hxx>
36 #include <basegfx/tools/canvastools.hxx>
37 #include <basegfx/numeric/ftools.hxx>
39 #include <canvas/canvastools.hxx>
41 #include "canvasbitmap.hxx"
42 #include "canvasbitmaphelper.hxx"
45 using namespace ::com::sun::star
;
49 CanvasBitmapHelper::CanvasBitmapHelper() :
55 void CanvasBitmapHelper::setBitmap( const BitmapEx
& rBitmap
)
57 ENSURE_OR_THROW( mpOutDev
,
58 "Invalid reference device" );
60 mpBackBuffer
.reset( new BitmapBackBuffer( rBitmap
,
61 mpOutDev
->getOutDev() ) );
63 // tell canvas helper about the new target OutDev (don't
64 // protect state, it's our own VirDev, anyways)
65 setOutDev( mpBackBuffer
, false );
68 void CanvasBitmapHelper::init( const BitmapEx
& rBitmap
,
69 rendering::XGraphicDevice
& rDevice
,
70 const OutDevProviderSharedPtr
& rOutDevReference
)
72 mpOutDevReference
= rOutDevReference
;
73 mpBackBuffer
.reset( new BitmapBackBuffer( rBitmap
, rOutDevReference
->getOutDev() ));
75 // forward new settings to base class (ref device, output
76 // surface, no protection (own backbuffer), alpha depends on
77 // whether BmpEx is transparent or not)
78 CanvasHelper::init( rDevice
,
81 rBitmap
.IsTransparent() );
84 void CanvasBitmapHelper::disposing()
87 mpOutDevReference
.reset();
89 // forward to base class
90 CanvasHelper::disposing();
93 geometry::IntegerSize2D
CanvasBitmapHelper::getSize()
96 return geometry::IntegerSize2D();
98 return vcl::unotools::integerSize2DFromSize( mpBackBuffer
->getBitmapSizePixel() );
101 void CanvasBitmapHelper::clear()
105 mpBackBuffer
->clear(); // alpha vdev needs special treatment
108 uno::Reference
< rendering::XBitmap
> CanvasBitmapHelper::getScaledBitmap( const geometry::RealSize2D
& newSize
,
111 ENSURE_OR_THROW( mpDevice
,
112 "disposed CanvasHelper" );
114 SAL_INFO( "canvas.vcl", "::vclcanvas::CanvasBitmapHelper::getScaledBitmap()" );
116 if( !mpBackBuffer
|| mpDevice
)
117 return uno::Reference
< rendering::XBitmap
>(); // we're disposed
119 BitmapEx
aRes( mpBackBuffer
->getBitmapReference() );
121 aRes
.Scale( vcl::unotools::sizeFromRealSize2D(newSize
),
122 beFast
? BmpScaleFlag::Default
: BmpScaleFlag::BestQuality
);
124 return uno::Reference
< rendering::XBitmap
>(
125 new CanvasBitmap( aRes
, *mpDevice
, mpOutDevReference
) );
128 uno::Sequence
< sal_Int8
> CanvasBitmapHelper::getData( rendering::IntegerBitmapLayout
& rLayout
,
129 const geometry::IntegerRectangle2D
& rect
)
131 SAL_INFO( "canvas.vcl", "::vclcanvas::CanvasBitmapHelper::getData()" );
134 return uno::Sequence
< sal_Int8
>(); // we're disposed
136 rLayout
= getMemoryLayout();
137 Bitmap
aBitmap( mpBackBuffer
->getBitmapReference().GetBitmap() );
138 Bitmap
aAlpha( mpBackBuffer
->getBitmapReference().GetAlpha().GetBitmap() );
140 Bitmap::ScopedReadAccess
pReadAccess( aBitmap
);
141 Bitmap::ScopedReadAccess
pAlphaReadAccess( aAlpha
.IsEmpty() ?
142 (BitmapReadAccess
*)NULL
: aAlpha
.AcquireReadAccess(),
145 ENSURE_OR_THROW( pReadAccess
.get() != NULL
,
146 "Could not acquire read access to bitmap" );
148 // TODO(F1): Support more formats.
149 const Size
aBmpSize( aBitmap
.GetSizePixel() );
151 rLayout
.ScanLines
= aBmpSize
.Height();
152 rLayout
.ScanLineBytes
= aBmpSize
.Width()*4;
153 rLayout
.ScanLineStride
= rLayout
.ScanLineBytes
;
155 // for the time being, always return as BGRA
156 uno::Sequence
< sal_Int8
> aRes( 4*aBmpSize
.Width()*aBmpSize
.Height() );
157 sal_Int8
* pRes
= aRes
.getArray();
161 y
<aBmpSize
.Height() && y
<rect
.Y2
;
164 if( pAlphaReadAccess
.get() != NULL
)
167 x
<aBmpSize
.Width() && x
<rect
.X2
;
170 pRes
[ nCurrPos
++ ] = pReadAccess
->GetColor( y
, x
).GetRed();
171 pRes
[ nCurrPos
++ ] = pReadAccess
->GetColor( y
, x
).GetGreen();
172 pRes
[ nCurrPos
++ ] = pReadAccess
->GetColor( y
, x
).GetBlue();
173 pRes
[ nCurrPos
++ ] = pAlphaReadAccess
->GetPixel( y
, x
).GetIndex();
179 x
<aBmpSize
.Width() && x
<rect
.X2
;
182 pRes
[ nCurrPos
++ ] = pReadAccess
->GetColor( y
, x
).GetRed();
183 pRes
[ nCurrPos
++ ] = pReadAccess
->GetColor( y
, x
).GetGreen();
184 pRes
[ nCurrPos
++ ] = pReadAccess
->GetColor( y
, x
).GetBlue();
185 pRes
[ nCurrPos
++ ] = sal_uInt8(255);
193 void CanvasBitmapHelper::setData( const uno::Sequence
< sal_Int8
>& data
,
194 const rendering::IntegerBitmapLayout
& rLayout
,
195 const geometry::IntegerRectangle2D
& rect
)
197 SAL_INFO( "canvas.vcl", "::vclcanvas::CanvasBitmapHelper::setData()" );
200 return; // we're disposed
202 const rendering::IntegerBitmapLayout
aRefLayout( getMemoryLayout() );
203 ENSURE_ARG_OR_THROW( aRefLayout
.PlaneStride
!= rLayout
.PlaneStride
||
204 aRefLayout
.ColorSpace
!= rLayout
.ColorSpace
||
205 aRefLayout
.Palette
!= rLayout
.Palette
||
206 aRefLayout
.IsMsbFirst
!= rLayout
.IsMsbFirst
,
207 "Mismatching memory layout" );
209 // retrieve local copies from the BitmapEx, which are later
210 // stored back. Unfortunately, the BitmapEx does not permit
211 // in-place modifications, as they are necessary here.
212 Bitmap
aBitmap( mpBackBuffer
->getBitmapReference().GetBitmap() );
213 Bitmap
aAlpha( mpBackBuffer
->getBitmapReference().GetAlpha().GetBitmap() );
215 bool bCopyBack( false ); // only copy something back, if we
216 // actually changed a pixel
219 Bitmap::ScopedWriteAccess
pWriteAccess( aBitmap
);
220 Bitmap::ScopedWriteAccess
pAlphaWriteAccess( aAlpha
.IsEmpty() ?
221 (BitmapWriteAccess
*)NULL
: aAlpha
.AcquireWriteAccess(),
224 if( pAlphaWriteAccess
.get() )
226 DBG_ASSERT( pAlphaWriteAccess
->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL
||
227 pAlphaWriteAccess
->GetScanlineFormat() == BMP_FORMAT_8BIT_TC_MASK
,
228 "non-8bit alpha not supported!" );
231 ENSURE_OR_THROW( pWriteAccess
.get() != NULL
,
232 "Could not acquire write access to bitmap" );
234 // TODO(F1): Support more formats.
235 const Size
aBmpSize( aBitmap
.GetSizePixel() );
237 // for the time being, always read as BGRA
238 int x
, y
, nCurrPos(0);
240 y
<aBmpSize
.Height() && y
<rect
.Y2
;
243 if( pAlphaWriteAccess
.get() != NULL
)
245 switch( pWriteAccess
->GetScanlineFormat() )
247 case BMP_FORMAT_8BIT_PAL
:
249 Scanline pScan
= pWriteAccess
->GetScanline( y
);
250 Scanline pAScan
= pAlphaWriteAccess
->GetScanline( y
);
253 x
<aBmpSize
.Width() && x
<rect
.X2
;
256 *pScan
++ = (sal_uInt8
)pWriteAccess
->GetBestPaletteIndex(
257 BitmapColor( data
[ nCurrPos
],
259 data
[ nCurrPos
+2 ] ) );
263 // cast to unsigned byte, for correct subtraction result
264 *pAScan
++ = static_cast<sal_uInt8
>(255 -
265 static_cast<sal_uInt8
>(data
[ nCurrPos
++ ]));
270 case BMP_FORMAT_24BIT_TC_BGR
:
272 Scanline pScan
= pWriteAccess
->GetScanline( y
);
273 Scanline pAScan
= pAlphaWriteAccess
->GetScanline( y
);
276 x
<aBmpSize
.Width() && x
<rect
.X2
;
279 *pScan
++ = data
[ nCurrPos
+2 ];
280 *pScan
++ = data
[ nCurrPos
+1 ];
281 *pScan
++ = data
[ nCurrPos
];
285 // cast to unsigned byte, for correct subtraction result
286 *pAScan
++ = static_cast<sal_uInt8
>(255 -
287 static_cast<sal_uInt8
>(data
[ nCurrPos
++ ]));
292 case BMP_FORMAT_24BIT_TC_RGB
:
294 Scanline pScan
= pWriteAccess
->GetScanline( y
);
295 Scanline pAScan
= pAlphaWriteAccess
->GetScanline( y
);
298 x
<aBmpSize
.Width() && x
<rect
.X2
;
301 *pScan
++ = data
[ nCurrPos
];
302 *pScan
++ = data
[ nCurrPos
+1 ];
303 *pScan
++ = data
[ nCurrPos
+2 ];
307 // cast to unsigned byte, for correct subtraction result
308 *pAScan
++ = static_cast<sal_uInt8
>(255 -
309 static_cast<sal_uInt8
>(data
[ nCurrPos
++ ]));
317 x
<aBmpSize
.Width() && x
<rect
.X2
;
320 pWriteAccess
->SetPixel( y
, x
, BitmapColor( data
[ nCurrPos
],
322 data
[ nCurrPos
+2 ] ) );
325 // cast to unsigned byte, for correct subtraction result
326 pAlphaWriteAccess
->SetPixel( y
, x
,
328 static_cast<sal_uInt8
>(255 -
329 static_cast<sal_uInt8
>(data
[ nCurrPos
++ ])) ) );
337 // TODO(Q3): This is copy'n'pasted from
338 // canvashelper.cxx, unify!
339 switch( pWriteAccess
->GetScanlineFormat() )
341 case BMP_FORMAT_8BIT_PAL
:
343 Scanline pScan
= pWriteAccess
->GetScanline( y
);
346 x
<aBmpSize
.Width() && x
<rect
.X2
;
349 *pScan
++ = (sal_uInt8
)pWriteAccess
->GetBestPaletteIndex(
350 BitmapColor( data
[ nCurrPos
],
352 data
[ nCurrPos
+2 ] ) );
354 nCurrPos
+= 4; // skip three colors, _plus_ alpha
359 case BMP_FORMAT_24BIT_TC_BGR
:
361 Scanline pScan
= pWriteAccess
->GetScanline( y
);
364 x
<aBmpSize
.Width() && x
<rect
.X2
;
367 *pScan
++ = data
[ nCurrPos
+2 ];
368 *pScan
++ = data
[ nCurrPos
+1 ];
369 *pScan
++ = data
[ nCurrPos
];
371 nCurrPos
+= 4; // skip three colors, _plus_ alpha
376 case BMP_FORMAT_24BIT_TC_RGB
:
378 Scanline pScan
= pWriteAccess
->GetScanline( y
);
381 x
<aBmpSize
.Width() && x
<rect
.X2
;
384 *pScan
++ = data
[ nCurrPos
];
385 *pScan
++ = data
[ nCurrPos
+1 ];
386 *pScan
++ = data
[ nCurrPos
+2 ];
388 nCurrPos
+= 4; // skip three colors, _plus_ alpha
396 x
<aBmpSize
.Width() && x
<rect
.X2
;
399 pWriteAccess
->SetPixel( y
, x
, BitmapColor( data
[ nCurrPos
],
401 data
[ nCurrPos
+2 ] ) );
402 nCurrPos
+= 4; // skip three colors, _plus_ alpha
413 // copy back only here, since the BitmapAccessors must be
414 // destroyed beforehand
417 if( aAlpha
.IsEmpty() )
418 setBitmap( BitmapEx( aBitmap
) );
420 setBitmap( BitmapEx( aBitmap
,
421 AlphaMask( aAlpha
) ) );
425 void CanvasBitmapHelper::setPixel( const uno::Sequence
< sal_Int8
>& color
,
426 const rendering::IntegerBitmapLayout
& rLayout
,
427 const geometry::IntegerPoint2D
& pos
)
429 SAL_INFO( "canvas.vcl", "::vclcanvas::CanvasBitmapHelper::setPixel()" );
432 return; // we're disposed
434 const Size
aBmpSize( mpBackBuffer
->getBitmapReference().GetSizePixel() );
436 ENSURE_ARG_OR_THROW( pos
.X
>= 0 && pos
.X
< aBmpSize
.Width(),
437 "X coordinate out of bounds" );
438 ENSURE_ARG_OR_THROW( pos
.Y
>= 0 && pos
.Y
< aBmpSize
.Height(),
439 "Y coordinate out of bounds" );
440 ENSURE_ARG_OR_THROW( color
.getLength() > 3,
441 "not enough color components" );
443 const rendering::IntegerBitmapLayout
aRefLayout( getMemoryLayout() );
444 ENSURE_ARG_OR_THROW( aRefLayout
.PlaneStride
!= rLayout
.PlaneStride
||
445 aRefLayout
.ColorSpace
!= rLayout
.ColorSpace
||
446 aRefLayout
.Palette
!= rLayout
.Palette
||
447 aRefLayout
.IsMsbFirst
!= rLayout
.IsMsbFirst
,
448 "Mismatching memory layout" );
450 // retrieve local copies from the BitmapEx, which are later
451 // stored back. Unfortunately, the BitmapEx does not permit
452 // in-place modifications, as they are necessary here.
453 Bitmap
aBitmap( mpBackBuffer
->getBitmapReference().GetBitmap() );
454 Bitmap
aAlpha( mpBackBuffer
->getBitmapReference().GetAlpha().GetBitmap() );
456 bool bCopyBack( false ); // only copy something back, if we
457 // actually changed a pixel
460 Bitmap::ScopedWriteAccess
pWriteAccess( aBitmap
);
461 Bitmap::ScopedWriteAccess
pAlphaWriteAccess( aAlpha
.IsEmpty() ?
462 (BitmapWriteAccess
*)NULL
: aAlpha
.AcquireWriteAccess(),
465 ENSURE_OR_THROW( pWriteAccess
.get() != NULL
,
466 "Could not acquire write access to bitmap" );
468 pWriteAccess
->SetPixel( pos
.Y
, pos
.X
, BitmapColor( color
[ 0 ],
472 if( pAlphaWriteAccess
.get() != NULL
)
473 pAlphaWriteAccess
->SetPixel( pos
.Y
, pos
.X
, BitmapColor( 255 - color
[ 3 ] ) );
478 // copy back only here, since the BitmapAccessors must be
479 // destroyed beforehand
482 if( aAlpha
.IsEmpty() )
483 setBitmap( BitmapEx( aBitmap
) );
485 setBitmap( BitmapEx( aBitmap
,
486 AlphaMask( aAlpha
) ) );
490 uno::Sequence
< sal_Int8
> CanvasBitmapHelper::getPixel( rendering::IntegerBitmapLayout
& rLayout
,
491 const geometry::IntegerPoint2D
& pos
)
493 SAL_INFO( "canvas.vcl", "::vclcanvas::CanvasBitmapHelper::getPixel()" );
496 return uno::Sequence
< sal_Int8
>(); // we're disposed
498 rLayout
= getMemoryLayout();
499 rLayout
.ScanLines
= 1;
500 rLayout
.ScanLineBytes
= 4;
501 rLayout
.ScanLineStride
= rLayout
.ScanLineBytes
;
503 const Size
aBmpSize( mpBackBuffer
->getBitmapReference().GetSizePixel() );
505 ENSURE_ARG_OR_THROW( pos
.X
>= 0 && pos
.X
< aBmpSize
.Width(),
506 "X coordinate out of bounds" );
507 ENSURE_ARG_OR_THROW( pos
.Y
>= 0 && pos
.Y
< aBmpSize
.Height(),
508 "Y coordinate out of bounds" );
510 Bitmap
aBitmap( mpBackBuffer
->getBitmapReference().GetBitmap() );
511 Bitmap
aAlpha( mpBackBuffer
->getBitmapReference().GetAlpha().GetBitmap() );
513 Bitmap::ScopedReadAccess
pReadAccess( aBitmap
);
514 Bitmap::ScopedReadAccess
pAlphaReadAccess( aAlpha
.IsEmpty() ?
515 (BitmapReadAccess
*)NULL
: aAlpha
.AcquireReadAccess(),
517 ENSURE_OR_THROW( pReadAccess
.get() != NULL
,
518 "Could not acquire read access to bitmap" );
520 uno::Sequence
< sal_Int8
> aRes( 4 );
521 sal_Int8
* pRes
= aRes
.getArray();
523 const BitmapColor
aColor( pReadAccess
->GetColor( pos
.Y
, pos
.X
) );
524 pRes
[ 0 ] = aColor
.GetRed();
525 pRes
[ 1 ] = aColor
.GetGreen();
526 pRes
[ 2 ] = aColor
.GetBlue();
528 if( pAlphaReadAccess
.get() != NULL
)
529 pRes
[ 3 ] = pAlphaReadAccess
->GetPixel( pos
.Y
, pos
.X
).GetIndex();
531 pRes
[ 3 ] = sal_uInt8(255);
536 rendering::IntegerBitmapLayout
CanvasBitmapHelper::getMemoryLayout()
538 if( !mpOutDev
.get() )
539 return rendering::IntegerBitmapLayout(); // we're disposed
541 rendering::IntegerBitmapLayout
xBitmapLayout( ::canvas::tools::getStdMemoryLayout(getSize()) );
543 xBitmapLayout
.ColorSpace
= canvas::tools::getStdColorSpaceWithoutAlpha();
545 return xBitmapLayout
;
548 BitmapEx
CanvasBitmapHelper::getBitmap() const
551 return BitmapEx(); // we're disposed
553 return mpBackBuffer
->getBitmapReference();
558 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */