Branch libreoffice-5-0-4
[LibreOffice.git] / canvas / source / vcl / canvasbitmaphelper.cxx
blobd818ed8626342e72d90ee7002a17d4e382b6f865
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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;
47 namespace vclcanvas
49 CanvasBitmapHelper::CanvasBitmapHelper() :
50 mpBackBuffer(),
51 mpOutDevReference()
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,
79 mpBackBuffer,
80 false,
81 rBitmap.IsTransparent() );
84 void CanvasBitmapHelper::disposing()
86 mpBackBuffer.reset();
87 mpOutDevReference.reset();
89 // forward to base class
90 CanvasHelper::disposing();
93 geometry::IntegerSize2D CanvasBitmapHelper::getSize()
95 if( !mpBackBuffer )
96 return geometry::IntegerSize2D();
98 return vcl::unotools::integerSize2DFromSize( mpBackBuffer->getBitmapSizePixel() );
101 void CanvasBitmapHelper::clear()
103 // are we disposed?
104 if( mpBackBuffer )
105 mpBackBuffer->clear(); // alpha vdev needs special treatment
108 uno::Reference< rendering::XBitmap > CanvasBitmapHelper::getScaledBitmap( const geometry::RealSize2D& newSize,
109 bool beFast )
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()" );
133 if( !mpBackBuffer )
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(),
143 aAlpha );
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();
159 int nCurrPos(0);
160 for( int y=rect.Y1;
161 y<aBmpSize.Height() && y<rect.Y2;
162 ++y )
164 if( pAlphaReadAccess.get() != NULL )
166 for( int x=rect.X1;
167 x<aBmpSize.Width() && x<rect.X2;
168 ++x )
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();
176 else
178 for( int x=rect.X1;
179 x<aBmpSize.Width() && x<rect.X2;
180 ++x )
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);
190 return aRes;
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()" );
199 if( !mpBackBuffer )
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(),
222 aAlpha );
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);
239 for( y=rect.Y1;
240 y<aBmpSize.Height() && y<rect.Y2;
241 ++y )
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 );
252 for( x=rect.X1;
253 x<aBmpSize.Width() && x<rect.X2;
254 ++x )
256 *pScan++ = (sal_uInt8)pWriteAccess->GetBestPaletteIndex(
257 BitmapColor( data[ nCurrPos ],
258 data[ nCurrPos+1 ],
259 data[ nCurrPos+2 ] ) );
261 nCurrPos += 3;
263 // cast to unsigned byte, for correct subtraction result
264 *pAScan++ = static_cast<sal_uInt8>(255 -
265 static_cast<sal_uInt8>(data[ nCurrPos++ ]));
268 break;
270 case BMP_FORMAT_24BIT_TC_BGR:
272 Scanline pScan = pWriteAccess->GetScanline( y );
273 Scanline pAScan = pAlphaWriteAccess->GetScanline( y );
275 for( x=rect.X1;
276 x<aBmpSize.Width() && x<rect.X2;
277 ++x )
279 *pScan++ = data[ nCurrPos+2 ];
280 *pScan++ = data[ nCurrPos+1 ];
281 *pScan++ = data[ nCurrPos ];
283 nCurrPos += 3;
285 // cast to unsigned byte, for correct subtraction result
286 *pAScan++ = static_cast<sal_uInt8>(255 -
287 static_cast<sal_uInt8>(data[ nCurrPos++ ]));
290 break;
292 case BMP_FORMAT_24BIT_TC_RGB:
294 Scanline pScan = pWriteAccess->GetScanline( y );
295 Scanline pAScan = pAlphaWriteAccess->GetScanline( y );
297 for( x=rect.X1;
298 x<aBmpSize.Width() && x<rect.X2;
299 ++x )
301 *pScan++ = data[ nCurrPos ];
302 *pScan++ = data[ nCurrPos+1 ];
303 *pScan++ = data[ nCurrPos+2 ];
305 nCurrPos += 3;
307 // cast to unsigned byte, for correct subtraction result
308 *pAScan++ = static_cast<sal_uInt8>(255 -
309 static_cast<sal_uInt8>(data[ nCurrPos++ ]));
312 break;
314 default:
316 for( x=rect.X1;
317 x<aBmpSize.Width() && x<rect.X2;
318 ++x )
320 pWriteAccess->SetPixel( y, x, BitmapColor( data[ nCurrPos ],
321 data[ nCurrPos+1 ],
322 data[ nCurrPos+2 ] ) );
323 nCurrPos += 3;
325 // cast to unsigned byte, for correct subtraction result
326 pAlphaWriteAccess->SetPixel( y, x,
327 BitmapColor(
328 static_cast<sal_uInt8>(255 -
329 static_cast<sal_uInt8>(data[ nCurrPos++ ])) ) );
332 break;
335 else
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 );
345 for( x=rect.X1;
346 x<aBmpSize.Width() && x<rect.X2;
347 ++x )
349 *pScan++ = (sal_uInt8)pWriteAccess->GetBestPaletteIndex(
350 BitmapColor( data[ nCurrPos ],
351 data[ nCurrPos+1 ],
352 data[ nCurrPos+2 ] ) );
354 nCurrPos += 4; // skip three colors, _plus_ alpha
357 break;
359 case BMP_FORMAT_24BIT_TC_BGR:
361 Scanline pScan = pWriteAccess->GetScanline( y );
363 for( x=rect.X1;
364 x<aBmpSize.Width() && x<rect.X2;
365 ++x )
367 *pScan++ = data[ nCurrPos+2 ];
368 *pScan++ = data[ nCurrPos+1 ];
369 *pScan++ = data[ nCurrPos ];
371 nCurrPos += 4; // skip three colors, _plus_ alpha
374 break;
376 case BMP_FORMAT_24BIT_TC_RGB:
378 Scanline pScan = pWriteAccess->GetScanline( y );
380 for( x=rect.X1;
381 x<aBmpSize.Width() && x<rect.X2;
382 ++x )
384 *pScan++ = data[ nCurrPos ];
385 *pScan++ = data[ nCurrPos+1 ];
386 *pScan++ = data[ nCurrPos+2 ];
388 nCurrPos += 4; // skip three colors, _plus_ alpha
391 break;
393 default:
395 for( x=rect.X1;
396 x<aBmpSize.Width() && x<rect.X2;
397 ++x )
399 pWriteAccess->SetPixel( y, x, BitmapColor( data[ nCurrPos ],
400 data[ nCurrPos+1 ],
401 data[ nCurrPos+2 ] ) );
402 nCurrPos += 4; // skip three colors, _plus_ alpha
405 break;
409 bCopyBack = true;
413 // copy back only here, since the BitmapAccessors must be
414 // destroyed beforehand
415 if( bCopyBack )
417 if( aAlpha.IsEmpty() )
418 setBitmap( BitmapEx( aBitmap ) );
419 else
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()" );
431 if( !mpBackBuffer )
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(),
463 aAlpha );
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 ],
469 color[ 1 ],
470 color[ 2 ] ) );
472 if( pAlphaWriteAccess.get() != NULL )
473 pAlphaWriteAccess->SetPixel( pos.Y, pos.X, BitmapColor( 255 - color[ 3 ] ) );
475 bCopyBack = true;
478 // copy back only here, since the BitmapAccessors must be
479 // destroyed beforehand
480 if( bCopyBack )
482 if( aAlpha.IsEmpty() )
483 setBitmap( BitmapEx( aBitmap ) );
484 else
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()" );
495 if( !mpBackBuffer )
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(),
516 aAlpha );
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();
530 else
531 pRes[ 3 ] = sal_uInt8(255);
533 return aRes;
536 rendering::IntegerBitmapLayout CanvasBitmapHelper::getMemoryLayout()
538 if( !mpOutDev.get() )
539 return rendering::IntegerBitmapLayout(); // we're disposed
541 rendering::IntegerBitmapLayout xBitmapLayout( ::canvas::tools::getStdMemoryLayout(getSize()) );
542 if ( !hasAlpha() )
543 xBitmapLayout.ColorSpace = canvas::tools::getStdColorSpaceWithoutAlpha();
545 return xBitmapLayout;
548 BitmapEx CanvasBitmapHelper::getBitmap() const
550 if( !mpBackBuffer )
551 return BitmapEx(); // we're disposed
552 else
553 return mpBackBuffer->getBitmapReference();
558 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */