1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: canvasbitmaphelper.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_canvas.hxx"
34 #include <canvas/debug.hxx>
35 #include <tools/diagnose_ex.h>
37 #include <com/sun/star/util/Endianness.hpp>
39 #include <rtl/logfile.hxx>
40 #include <rtl/math.hxx>
42 #include <tools/poly.hxx>
43 #include <vcl/window.hxx>
44 #include <vcl/bitmapex.hxx>
45 #include <vcl/bmpacc.hxx>
46 #include <vcl/canvastools.hxx>
48 #include <basegfx/matrix/b2dhommatrix.hxx>
49 #include <basegfx/point/b2dpoint.hxx>
50 #include <basegfx/tools/canvastools.hxx>
51 #include <basegfx/numeric/ftools.hxx>
53 #include <canvas/canvastools.hxx>
55 #include "canvasbitmap.hxx"
56 #include "canvasbitmaphelper.hxx"
59 using namespace ::com::sun::star
;
63 CanvasBitmapHelper::CanvasBitmapHelper() :
69 void CanvasBitmapHelper::setBitmap( const BitmapEx
& rBitmap
)
71 ENSURE_OR_THROW( mpOutDev
,
72 "Invalid reference device" );
74 mpBackBuffer
.reset( new BitmapBackBuffer( rBitmap
,
75 mpOutDev
->getOutDev() ) );
77 // tell canvas helper about the new target OutDev (don't
78 // protect state, it's our own VirDev, anyways)
79 setOutDev( mpBackBuffer
, false );
82 void CanvasBitmapHelper::init( const BitmapEx
& rBitmap
,
83 rendering::XGraphicDevice
& rDevice
,
84 const OutDevProviderSharedPtr
& rOutDevReference
)
86 mpOutDevReference
= rOutDevReference
;
87 mpBackBuffer
.reset( new BitmapBackBuffer( rBitmap
, rOutDevReference
->getOutDev() ));
89 // forward new settings to base class (ref device, output
90 // surface, no protection (own backbuffer), alpha depends on
91 // whether BmpEx is transparent or not)
92 CanvasHelper::init( rDevice
,
95 rBitmap
.IsTransparent() );
98 void CanvasBitmapHelper::disposing()
100 mpBackBuffer
.reset();
101 mpOutDevReference
.reset();
103 // forward to base class
104 CanvasHelper::disposing();
107 geometry::IntegerSize2D
CanvasBitmapHelper::getSize()
110 return geometry::IntegerSize2D();
112 return ::vcl::unotools::integerSize2DFromSize( mpBackBuffer
->getBitmapSizePixel() );
115 void CanvasBitmapHelper::clear()
119 mpBackBuffer
->clear(); // alpha vdev needs special treatment
122 uno::Reference
< rendering::XBitmap
> CanvasBitmapHelper::getScaledBitmap( const geometry::RealSize2D
& newSize
,
125 ENSURE_OR_THROW( mpDevice
,
126 "disposed CanvasHelper" );
128 RTL_LOGFILE_CONTEXT( aLog
, "::vclcanvas::CanvasBitmapHelper::getScaledBitmap()" );
130 if( !mpBackBuffer
|| mpDevice
)
131 return uno::Reference
< rendering::XBitmap
>(); // we're disposed
133 BitmapEx
aRes( mpBackBuffer
->getBitmapReference() );
135 aRes
.Scale( ::vcl::unotools::sizeFromRealSize2D(newSize
),
136 beFast
? BMP_SCALE_FAST
: BMP_SCALE_INTERPOLATE
);
138 return uno::Reference
< rendering::XBitmap
>(
139 new CanvasBitmap( aRes
, *mpDevice
, mpOutDevReference
) );
142 uno::Sequence
< sal_Int8
> CanvasBitmapHelper::getData( rendering::IntegerBitmapLayout
& rLayout
,
143 const geometry::IntegerRectangle2D
& rect
)
145 RTL_LOGFILE_CONTEXT( aLog
, "::vclcanvas::CanvasBitmapHelper::getData()" );
148 return uno::Sequence
< sal_Int8
>(); // we're disposed
150 rLayout
= getMemoryLayout();
151 Bitmap
aBitmap( mpBackBuffer
->getBitmapReference().GetBitmap() );
152 Bitmap
aAlpha( mpBackBuffer
->getBitmapReference().GetAlpha().GetBitmap() );
154 ScopedBitmapReadAccess
pReadAccess( aBitmap
.AcquireReadAccess(),
156 ScopedBitmapReadAccess
pAlphaReadAccess( aAlpha
.IsEmpty() ?
157 (BitmapReadAccess
*)NULL
: aAlpha
.AcquireReadAccess(),
160 ENSURE_OR_THROW( pReadAccess
.get() != NULL
,
161 "Could not acquire read access to bitmap" );
163 // TODO(F1): Support more formats.
164 const Size
aBmpSize( aBitmap
.GetSizePixel() );
166 rLayout
.ScanLines
= aBmpSize
.Height();
167 rLayout
.ScanLineBytes
= aBmpSize
.Width()*4;
168 rLayout
.ScanLineStride
= rLayout
.ScanLineBytes
;
170 // for the time being, always return as BGRA
171 uno::Sequence
< sal_Int8
> aRes( 4*aBmpSize
.Width()*aBmpSize
.Height() );
172 sal_Int8
* pRes
= aRes
.getArray();
176 y
<aBmpSize
.Height() && y
<rect
.Y2
;
179 if( pAlphaReadAccess
.get() != NULL
)
182 x
<aBmpSize
.Width() && x
<rect
.X2
;
185 pRes
[ nCurrPos
++ ] = pReadAccess
->GetColor( y
, x
).GetRed();
186 pRes
[ nCurrPos
++ ] = pReadAccess
->GetColor( y
, x
).GetGreen();
187 pRes
[ nCurrPos
++ ] = pReadAccess
->GetColor( y
, x
).GetBlue();
188 pRes
[ nCurrPos
++ ] = pAlphaReadAccess
->GetPixel( y
, x
).GetIndex();
194 x
<aBmpSize
.Width() && x
<rect
.X2
;
197 pRes
[ nCurrPos
++ ] = pReadAccess
->GetColor( y
, x
).GetRed();
198 pRes
[ nCurrPos
++ ] = pReadAccess
->GetColor( y
, x
).GetGreen();
199 pRes
[ nCurrPos
++ ] = pReadAccess
->GetColor( y
, x
).GetBlue();
200 pRes
[ nCurrPos
++ ] = sal_uInt8(255);
208 void CanvasBitmapHelper::setData( const uno::Sequence
< sal_Int8
>& data
,
209 const rendering::IntegerBitmapLayout
& rLayout
,
210 const geometry::IntegerRectangle2D
& rect
)
212 RTL_LOGFILE_CONTEXT( aLog
, "::vclcanvas::CanvasBitmapHelper::setData()" );
215 return; // we're disposed
217 const rendering::IntegerBitmapLayout
aRefLayout( getMemoryLayout() );
218 ENSURE_ARG_OR_THROW( aRefLayout
.PlaneStride
!= rLayout
.PlaneStride
||
219 aRefLayout
.ColorSpace
!= rLayout
.ColorSpace
||
220 aRefLayout
.Palette
!= rLayout
.Palette
||
221 aRefLayout
.IsMsbFirst
!= rLayout
.IsMsbFirst
,
222 "Mismatching memory layout" );
224 // retrieve local copies from the BitmapEx, which are later
225 // stored back. Unfortunately, the BitmapEx does not permit
226 // in-place modifications, as they are necessary here.
227 Bitmap
aBitmap( mpBackBuffer
->getBitmapReference().GetBitmap() );
228 Bitmap
aAlpha( mpBackBuffer
->getBitmapReference().GetAlpha().GetBitmap() );
230 bool bCopyBack( false ); // only copy something back, if we
231 // actually changed a pixel
234 ScopedBitmapWriteAccess
pWriteAccess( aBitmap
.AcquireWriteAccess(),
236 ScopedBitmapWriteAccess
pAlphaWriteAccess( aAlpha
.IsEmpty() ?
237 (BitmapWriteAccess
*)NULL
: aAlpha
.AcquireWriteAccess(),
240 if( pAlphaWriteAccess
.get() )
242 DBG_ASSERT( pAlphaWriteAccess
->GetScanlineFormat() == BMP_FORMAT_8BIT_PAL
||
243 pAlphaWriteAccess
->GetScanlineFormat() == BMP_FORMAT_8BIT_TC_MASK
,
244 "non-8bit alpha not supported!" );
247 ENSURE_OR_THROW( pWriteAccess
.get() != NULL
,
248 "Could not acquire write access to bitmap" );
250 // TODO(F1): Support more formats.
251 const Size
aBmpSize( aBitmap
.GetSizePixel() );
253 // for the time being, always read as BGRA
254 int x
, y
, nCurrPos(0);
256 y
<aBmpSize
.Height() && y
<rect
.Y2
;
259 if( pAlphaWriteAccess
.get() != NULL
)
261 switch( pWriteAccess
->GetScanlineFormat() )
263 case BMP_FORMAT_8BIT_PAL
:
265 Scanline pScan
= pWriteAccess
->GetScanline( y
);
266 Scanline pAScan
= pAlphaWriteAccess
->GetScanline( y
);
269 x
<aBmpSize
.Width() && x
<rect
.X2
;
272 *pScan
++ = (BYTE
)pWriteAccess
->GetBestPaletteIndex(
273 BitmapColor( data
[ nCurrPos
],
275 data
[ nCurrPos
+2 ] ) );
279 // cast to unsigned byte, for correct subtraction result
280 *pAScan
++ = static_cast<BYTE
>(255 -
281 static_cast<sal_uInt8
>(data
[ nCurrPos
++ ]));
286 case BMP_FORMAT_24BIT_TC_BGR
:
288 Scanline pScan
= pWriteAccess
->GetScanline( y
);
289 Scanline pAScan
= pAlphaWriteAccess
->GetScanline( y
);
292 x
<aBmpSize
.Width() && x
<rect
.X2
;
295 *pScan
++ = data
[ nCurrPos
+2 ];
296 *pScan
++ = data
[ nCurrPos
+1 ];
297 *pScan
++ = data
[ nCurrPos
];
301 // cast to unsigned byte, for correct subtraction result
302 *pAScan
++ = static_cast<BYTE
>(255 -
303 static_cast<sal_uInt8
>(data
[ nCurrPos
++ ]));
308 case BMP_FORMAT_24BIT_TC_RGB
:
310 Scanline pScan
= pWriteAccess
->GetScanline( y
);
311 Scanline pAScan
= pAlphaWriteAccess
->GetScanline( y
);
314 x
<aBmpSize
.Width() && x
<rect
.X2
;
317 *pScan
++ = data
[ nCurrPos
];
318 *pScan
++ = data
[ nCurrPos
+1 ];
319 *pScan
++ = data
[ nCurrPos
+2 ];
323 // cast to unsigned byte, for correct subtraction result
324 *pAScan
++ = static_cast<BYTE
>(255 -
325 static_cast<sal_uInt8
>(data
[ nCurrPos
++ ]));
333 x
<aBmpSize
.Width() && x
<rect
.X2
;
336 pWriteAccess
->SetPixel( y
, x
, BitmapColor( data
[ nCurrPos
],
338 data
[ nCurrPos
+2 ] ) );
341 // cast to unsigned byte, for correct subtraction result
342 pAlphaWriteAccess
->SetPixel( y
, x
,
344 static_cast<BYTE
>(255 -
345 static_cast<sal_uInt8
>(data
[ nCurrPos
++ ])) ) );
353 // TODO(Q3): This is copy'n'pasted from
354 // canvashelper.cxx, unify!
355 switch( pWriteAccess
->GetScanlineFormat() )
357 case BMP_FORMAT_8BIT_PAL
:
359 Scanline pScan
= pWriteAccess
->GetScanline( y
);
362 x
<aBmpSize
.Width() && x
<rect
.X2
;
365 *pScan
++ = (BYTE
)pWriteAccess
->GetBestPaletteIndex(
366 BitmapColor( data
[ nCurrPos
],
368 data
[ nCurrPos
+2 ] ) );
370 nCurrPos
+= 4; // skip three colors, _plus_ alpha
375 case BMP_FORMAT_24BIT_TC_BGR
:
377 Scanline pScan
= pWriteAccess
->GetScanline( y
);
380 x
<aBmpSize
.Width() && x
<rect
.X2
;
383 *pScan
++ = data
[ nCurrPos
+2 ];
384 *pScan
++ = data
[ nCurrPos
+1 ];
385 *pScan
++ = data
[ nCurrPos
];
387 nCurrPos
+= 4; // skip three colors, _plus_ alpha
392 case BMP_FORMAT_24BIT_TC_RGB
:
394 Scanline pScan
= pWriteAccess
->GetScanline( y
);
397 x
<aBmpSize
.Width() && x
<rect
.X2
;
400 *pScan
++ = data
[ nCurrPos
];
401 *pScan
++ = data
[ nCurrPos
+1 ];
402 *pScan
++ = data
[ nCurrPos
+2 ];
404 nCurrPos
+= 4; // skip three colors, _plus_ alpha
412 x
<aBmpSize
.Width() && x
<rect
.X2
;
415 pWriteAccess
->SetPixel( y
, x
, BitmapColor( data
[ nCurrPos
],
417 data
[ nCurrPos
+2 ] ) );
418 nCurrPos
+= 4; // skip three colors, _plus_ alpha
429 // copy back only here, since the BitmapAccessors must be
430 // destroyed beforehand
433 if( aAlpha
.IsEmpty() )
434 setBitmap( BitmapEx( aBitmap
) );
436 setBitmap( BitmapEx( aBitmap
,
437 AlphaMask( aAlpha
) ) );
441 void CanvasBitmapHelper::setPixel( const uno::Sequence
< sal_Int8
>& color
,
442 const rendering::IntegerBitmapLayout
& rLayout
,
443 const geometry::IntegerPoint2D
& pos
)
445 RTL_LOGFILE_CONTEXT( aLog
, "::vclcanvas::CanvasBitmapHelper::setPixel()" );
448 return; // we're disposed
450 const Size
aBmpSize( mpBackBuffer
->getBitmapReference().GetSizePixel() );
452 ENSURE_ARG_OR_THROW( pos
.X
>= 0 && pos
.X
< aBmpSize
.Width(),
453 "X coordinate out of bounds" );
454 ENSURE_ARG_OR_THROW( pos
.Y
>= 0 && pos
.Y
< aBmpSize
.Height(),
455 "Y coordinate out of bounds" );
456 ENSURE_ARG_OR_THROW( color
.getLength() > 3,
457 "not enough color components" );
459 const rendering::IntegerBitmapLayout
aRefLayout( getMemoryLayout() );
460 ENSURE_ARG_OR_THROW( aRefLayout
.PlaneStride
!= rLayout
.PlaneStride
||
461 aRefLayout
.ColorSpace
!= rLayout
.ColorSpace
||
462 aRefLayout
.Palette
!= rLayout
.Palette
||
463 aRefLayout
.IsMsbFirst
!= rLayout
.IsMsbFirst
,
464 "Mismatching memory layout" );
466 // retrieve local copies from the BitmapEx, which are later
467 // stored back. Unfortunately, the BitmapEx does not permit
468 // in-place modifications, as they are necessary here.
469 Bitmap
aBitmap( mpBackBuffer
->getBitmapReference().GetBitmap() );
470 Bitmap
aAlpha( mpBackBuffer
->getBitmapReference().GetAlpha().GetBitmap() );
472 bool bCopyBack( false ); // only copy something back, if we
473 // actually changed a pixel
476 ScopedBitmapWriteAccess
pWriteAccess( aBitmap
.AcquireWriteAccess(),
478 ScopedBitmapWriteAccess
pAlphaWriteAccess( aAlpha
.IsEmpty() ?
479 (BitmapWriteAccess
*)NULL
: aAlpha
.AcquireWriteAccess(),
482 ENSURE_OR_THROW( pWriteAccess
.get() != NULL
,
483 "Could not acquire write access to bitmap" );
485 pWriteAccess
->SetPixel( pos
.Y
, pos
.X
, BitmapColor( color
[ 0 ],
489 if( pAlphaWriteAccess
.get() != NULL
)
490 pAlphaWriteAccess
->SetPixel( pos
.Y
, pos
.X
, BitmapColor( 255 - color
[ 3 ] ) );
495 // copy back only here, since the BitmapAccessors must be
496 // destroyed beforehand
499 if( aAlpha
.IsEmpty() )
500 setBitmap( BitmapEx( aBitmap
) );
502 setBitmap( BitmapEx( aBitmap
,
503 AlphaMask( aAlpha
) ) );
507 uno::Sequence
< sal_Int8
> CanvasBitmapHelper::getPixel( rendering::IntegerBitmapLayout
& rLayout
,
508 const geometry::IntegerPoint2D
& pos
)
510 RTL_LOGFILE_CONTEXT( aLog
, "::vclcanvas::CanvasBitmapHelper::getPixel()" );
513 return uno::Sequence
< sal_Int8
>(); // we're disposed
515 rLayout
= getMemoryLayout();
516 rLayout
.ScanLines
= 1;
517 rLayout
.ScanLineBytes
= 4;
518 rLayout
.ScanLineStride
= rLayout
.ScanLineBytes
;
520 const Size
aBmpSize( mpBackBuffer
->getBitmapReference().GetSizePixel() );
522 ENSURE_ARG_OR_THROW( pos
.X
>= 0 && pos
.X
< aBmpSize
.Width(),
523 "X coordinate out of bounds" );
524 ENSURE_ARG_OR_THROW( pos
.Y
>= 0 && pos
.Y
< aBmpSize
.Height(),
525 "Y coordinate out of bounds" );
527 Bitmap
aBitmap( mpBackBuffer
->getBitmapReference().GetBitmap() );
528 Bitmap
aAlpha( mpBackBuffer
->getBitmapReference().GetAlpha().GetBitmap() );
530 ScopedBitmapReadAccess
pReadAccess( aBitmap
.AcquireReadAccess(),
532 ScopedBitmapReadAccess
pAlphaReadAccess( aAlpha
.IsEmpty() ?
533 (BitmapReadAccess
*)NULL
: aAlpha
.AcquireReadAccess(),
535 ENSURE_OR_THROW( pReadAccess
.get() != NULL
,
536 "Could not acquire read access to bitmap" );
538 uno::Sequence
< sal_Int8
> aRes( 4 );
539 sal_Int8
* pRes
= aRes
.getArray();
541 const BitmapColor
aColor( pReadAccess
->GetColor( pos
.Y
, pos
.X
) );
542 pRes
[ 0 ] = aColor
.GetRed();
543 pRes
[ 1 ] = aColor
.GetGreen();
544 pRes
[ 2 ] = aColor
.GetBlue();
546 if( pAlphaReadAccess
.get() != NULL
)
547 pRes
[ 3 ] = pAlphaReadAccess
->GetPixel( pos
.Y
, pos
.X
).GetIndex();
549 pRes
[ 3 ] = sal_uInt8(255);
554 rendering::IntegerBitmapLayout
CanvasBitmapHelper::getMemoryLayout()
556 if( !mpOutDev
.get() )
557 return rendering::IntegerBitmapLayout(); // we're disposed
559 return ::canvas::tools::getStdMemoryLayout(getSize());
562 BitmapEx
CanvasBitmapHelper::getBitmap() const
565 return BitmapEx(); // we're disposed
567 return mpBackBuffer
->getBitmapReference();