Update ooo320-m1
[ooovba.git] / canvas / source / vcl / canvasbitmaphelper.cxx
blob5e4fc2732b6e5b78e2f6fc071bde99e00d19416e
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: canvasbitmaphelper.cxx,v $
10 * $Revision: 1.13 $
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;
61 namespace vclcanvas
63 CanvasBitmapHelper::CanvasBitmapHelper() :
64 mpBackBuffer(),
65 mpOutDevReference()
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,
93 mpBackBuffer,
94 false,
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()
109 if( !mpBackBuffer )
110 return geometry::IntegerSize2D();
112 return ::vcl::unotools::integerSize2DFromSize( mpBackBuffer->getBitmapSizePixel() );
115 void CanvasBitmapHelper::clear()
117 // are we disposed?
118 if( mpBackBuffer )
119 mpBackBuffer->clear(); // alpha vdev needs special treatment
122 uno::Reference< rendering::XBitmap > CanvasBitmapHelper::getScaledBitmap( const geometry::RealSize2D& newSize,
123 sal_Bool beFast )
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()" );
147 if( !mpBackBuffer )
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(),
155 aBitmap );
156 ScopedBitmapReadAccess pAlphaReadAccess( aAlpha.IsEmpty() ?
157 (BitmapReadAccess*)NULL : aAlpha.AcquireReadAccess(),
158 aAlpha );
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();
174 int nCurrPos(0);
175 for( int y=rect.Y1;
176 y<aBmpSize.Height() && y<rect.Y2;
177 ++y )
179 if( pAlphaReadAccess.get() != NULL )
181 for( int x=rect.X1;
182 x<aBmpSize.Width() && x<rect.X2;
183 ++x )
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();
191 else
193 for( int x=rect.X1;
194 x<aBmpSize.Width() && x<rect.X2;
195 ++x )
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);
205 return aRes;
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()" );
214 if( !mpBackBuffer )
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(),
235 aBitmap );
236 ScopedBitmapWriteAccess pAlphaWriteAccess( aAlpha.IsEmpty() ?
237 (BitmapWriteAccess*)NULL : aAlpha.AcquireWriteAccess(),
238 aAlpha );
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);
255 for( y=rect.Y1;
256 y<aBmpSize.Height() && y<rect.Y2;
257 ++y )
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 );
268 for( x=rect.X1;
269 x<aBmpSize.Width() && x<rect.X2;
270 ++x )
272 *pScan++ = (BYTE)pWriteAccess->GetBestPaletteIndex(
273 BitmapColor( data[ nCurrPos ],
274 data[ nCurrPos+1 ],
275 data[ nCurrPos+2 ] ) );
277 nCurrPos += 3;
279 // cast to unsigned byte, for correct subtraction result
280 *pAScan++ = static_cast<BYTE>(255 -
281 static_cast<sal_uInt8>(data[ nCurrPos++ ]));
284 break;
286 case BMP_FORMAT_24BIT_TC_BGR:
288 Scanline pScan = pWriteAccess->GetScanline( y );
289 Scanline pAScan = pAlphaWriteAccess->GetScanline( y );
291 for( x=rect.X1;
292 x<aBmpSize.Width() && x<rect.X2;
293 ++x )
295 *pScan++ = data[ nCurrPos+2 ];
296 *pScan++ = data[ nCurrPos+1 ];
297 *pScan++ = data[ nCurrPos ];
299 nCurrPos += 3;
301 // cast to unsigned byte, for correct subtraction result
302 *pAScan++ = static_cast<BYTE>(255 -
303 static_cast<sal_uInt8>(data[ nCurrPos++ ]));
306 break;
308 case BMP_FORMAT_24BIT_TC_RGB:
310 Scanline pScan = pWriteAccess->GetScanline( y );
311 Scanline pAScan = pAlphaWriteAccess->GetScanline( y );
313 for( x=rect.X1;
314 x<aBmpSize.Width() && x<rect.X2;
315 ++x )
317 *pScan++ = data[ nCurrPos ];
318 *pScan++ = data[ nCurrPos+1 ];
319 *pScan++ = data[ nCurrPos+2 ];
321 nCurrPos += 3;
323 // cast to unsigned byte, for correct subtraction result
324 *pAScan++ = static_cast<BYTE>(255 -
325 static_cast<sal_uInt8>(data[ nCurrPos++ ]));
328 break;
330 default:
332 for( x=rect.X1;
333 x<aBmpSize.Width() && x<rect.X2;
334 ++x )
336 pWriteAccess->SetPixel( y, x, BitmapColor( data[ nCurrPos ],
337 data[ nCurrPos+1 ],
338 data[ nCurrPos+2 ] ) );
339 nCurrPos += 3;
341 // cast to unsigned byte, for correct subtraction result
342 pAlphaWriteAccess->SetPixel( y, x,
343 BitmapColor(
344 static_cast<BYTE>(255 -
345 static_cast<sal_uInt8>(data[ nCurrPos++ ])) ) );
348 break;
351 else
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 );
361 for( x=rect.X1;
362 x<aBmpSize.Width() && x<rect.X2;
363 ++x )
365 *pScan++ = (BYTE)pWriteAccess->GetBestPaletteIndex(
366 BitmapColor( data[ nCurrPos ],
367 data[ nCurrPos+1 ],
368 data[ nCurrPos+2 ] ) );
370 nCurrPos += 4; // skip three colors, _plus_ alpha
373 break;
375 case BMP_FORMAT_24BIT_TC_BGR:
377 Scanline pScan = pWriteAccess->GetScanline( y );
379 for( x=rect.X1;
380 x<aBmpSize.Width() && x<rect.X2;
381 ++x )
383 *pScan++ = data[ nCurrPos+2 ];
384 *pScan++ = data[ nCurrPos+1 ];
385 *pScan++ = data[ nCurrPos ];
387 nCurrPos += 4; // skip three colors, _plus_ alpha
390 break;
392 case BMP_FORMAT_24BIT_TC_RGB:
394 Scanline pScan = pWriteAccess->GetScanline( y );
396 for( x=rect.X1;
397 x<aBmpSize.Width() && x<rect.X2;
398 ++x )
400 *pScan++ = data[ nCurrPos ];
401 *pScan++ = data[ nCurrPos+1 ];
402 *pScan++ = data[ nCurrPos+2 ];
404 nCurrPos += 4; // skip three colors, _plus_ alpha
407 break;
409 default:
411 for( x=rect.X1;
412 x<aBmpSize.Width() && x<rect.X2;
413 ++x )
415 pWriteAccess->SetPixel( y, x, BitmapColor( data[ nCurrPos ],
416 data[ nCurrPos+1 ],
417 data[ nCurrPos+2 ] ) );
418 nCurrPos += 4; // skip three colors, _plus_ alpha
421 break;
425 bCopyBack = true;
429 // copy back only here, since the BitmapAccessors must be
430 // destroyed beforehand
431 if( bCopyBack )
433 if( aAlpha.IsEmpty() )
434 setBitmap( BitmapEx( aBitmap ) );
435 else
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()" );
447 if( !mpBackBuffer )
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(),
477 aBitmap );
478 ScopedBitmapWriteAccess pAlphaWriteAccess( aAlpha.IsEmpty() ?
479 (BitmapWriteAccess*)NULL : aAlpha.AcquireWriteAccess(),
480 aAlpha );
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 ],
486 color[ 1 ],
487 color[ 2 ] ) );
489 if( pAlphaWriteAccess.get() != NULL )
490 pAlphaWriteAccess->SetPixel( pos.Y, pos.X, BitmapColor( 255 - color[ 3 ] ) );
492 bCopyBack = true;
495 // copy back only here, since the BitmapAccessors must be
496 // destroyed beforehand
497 if( bCopyBack )
499 if( aAlpha.IsEmpty() )
500 setBitmap( BitmapEx( aBitmap ) );
501 else
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()" );
512 if( !mpBackBuffer )
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(),
531 aBitmap );
532 ScopedBitmapReadAccess pAlphaReadAccess( aAlpha.IsEmpty() ?
533 (BitmapReadAccess*)NULL : aAlpha.AcquireReadAccess(),
534 aAlpha );
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();
548 else
549 pRes[ 3 ] = sal_uInt8(255);
551 return aRes;
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
564 if( !mpBackBuffer )
565 return BitmapEx(); // we're disposed
566 else
567 return mpBackBuffer->getBitmapReference();