Bug Summary

File:home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx
Warning:line 1121, column 45
Division by zero

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name pngread.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/glm -isystem /usr/include/glib-2.0 -isystem /usr/lib64/glib-2.0/include -isystem /usr/include/libmount -isystem /usr/include/blkid -isystem /usr/include/cairo -isystem /usr/include/glib-2.0 -isystem /usr/lib64/glib-2.0/include -isystem /usr/include/pixman-1 -isystem /usr/include/freetype2 -isystem /usr/include/libpng16 -isystem /usr/include/libxml2 -isystem /usr/include/freetype2 -isystem /usr/include/libpng16 -isystem /usr/include/dbus-1.0 -isystem /usr/lib64/dbus-1.0/include -isystem /usr/include/freetype2 -isystem /usr/include/libpng16 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D VCL_DLLIMPLEMENTATION -D DLLIMPLEMENTATION_UITEST -D CUI_DLL_NAME="libcuilo.so" -D DESKTOP_DETECTOR_DLL_NAME="libdesktop_detectorlo.so" -D TK_DLL_NAME="libtklo.so" -D SYSTEM_ZLIB -D GLM_FORCE_CTOR_INIT -D SK_USER_CONFIG_HEADER=</home/maarten/src/libreoffice/core/config_host/config_skia.h> -D SKIA_DLL -D ENABLE_CUPS -D HAVE_VALGRIND_HEADERS -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/epoxy/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/core -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/effects -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/gpu -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/config -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/ports -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/include/third_party/vulkan -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia/tools/gpu -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/skia -I /home/maarten/src/libreoffice/core/external/skia/inc/ -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/mdds/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/lcms2/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/harfbuzz/src -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/graphite/include -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/pdfium -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/pdfium/public -D COMPONENT_BUILD -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/libpng -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/libjpeg-turbo -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/vcl/inc -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libxml2 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx

/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <sal/config.h>
21#include <sal/log.hxx>
22#include <o3tl/safeint.hxx>
23#include <osl/diagnose.h>
24
25#include <cassert>
26#include <memory>
27#include <unotools/configmgr.hxx>
28#include <vcl/pngread.hxx>
29
30#include <cmath>
31#include <rtl/crc.h>
32#include <tools/zcodec.hxx>
33#include <tools/stream.hxx>
34#include <vcl/alpha.hxx>
35#include <osl/endian.h>
36#include <bitmapwriteaccess.hxx>
37
38namespace vcl
39{
40
41#define PNGCHUNK_IHDR0x49484452 0x49484452
42#define PNGCHUNK_PLTE0x504c5445 0x504c5445
43#define PNGCHUNK_IDAT0x49444154 0x49444154
44#define PNGCHUNK_IEND0x49454e44 0x49454e44
45#define PNGCHUNK_bKGD0x624b4744 0x624b4744
46#define PNGCHUNK_gAMA0x67414d41 0x67414d41
47#define PNGCHUNK_pHYs0x70485973 0x70485973
48#define PNGCHUNK_tRNS0x74524e53 0x74524e53
49
50#define VIEWING_GAMMA2.35 2.35
51#define DISPLAY_GAMMA1.0 1.0
52
53
54const sal_uInt8 mpDefaultColorTable[ 256 ] =
55{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
56 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
57 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
58 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
59 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
60 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
61 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
62 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
63 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
64 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
65 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
66 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
67 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
68 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
69 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
70 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
71};
72
73class PNGReaderImpl
74{
75private:
76 SvStream& mrPNGStream;
77 SvStreamEndian mnOrigStreamMode;
78
79 std::vector<vcl::PNGReader::ChunkData> maChunkSeq;
80 std::vector<vcl::PNGReader::ChunkData>::iterator maChunkIter;
81 std::vector<sal_uInt8>::iterator maDataIter;
82
83 std::unique_ptr<Bitmap> mpBmp;
84 BitmapScopedWriteAccess mxAcc;
85 std::unique_ptr<Bitmap> mpMaskBmp;
86 BitmapScopedWriteAccess mxMaskAcc;
87 std::unique_ptr<AlphaMask> mpAlphaMask;
88 AlphaScopedWriteAccess mxAlphaAcc;
89 BitmapWriteAccess* mpMaskAcc;
90
91 ZCodec mpZCodec;
92 std::unique_ptr<sal_uInt8[]>
93 mpInflateInBuf; // as big as the size of a scanline + alphachannel + 1
94 std::unique_ptr<sal_uInt8[]>
95 mpScanPrior; // pointer to the latest scanline
96 std::unique_ptr<sal_uInt8[]>
97 mpTransTab; // for transparency in images with palette colortype
98 sal_uInt8* mpScanCurrent; // pointer into the current scanline
99 sal_uInt8* mpColorTable;
100 std::size_t mnStreamSize; // estimate of PNG file size
101 sal_uInt32 mnChunkType; // Type of current PNG chunk
102 sal_Int32 mnChunkLen; // Length of current PNG chunk
103 Size maOrigSize; // pixel size of the full image
104 Size maTargetSize; // pixel size of the result image
105 Size maPhysSize; // preferred size in MapUnit::Map100thMM units
106 sal_uInt32 mnBPP; // number of bytes per pixel
107 sal_uInt32 mnScansize; // max size of scanline
108 sal_uInt32 mnYpos; // latest y position in full image
109 int mnPass; // if interlaced the latest pass ( 1..7 ) else 7
110 sal_uInt32 mnXStart; // the starting X for the current pass
111 sal_uInt32 mnXAdd; // the increment for input images X coords for the current pass
112 sal_uInt32 mnYAdd; // the increment for input images Y coords for the current pass
113 int mnPreviewShift; // shift to convert orig image coords into preview image coords
114 int mnPreviewMask; // == ((1 << mnPreviewShift) - 1)
115 sal_uInt16 mnTargetDepth; // pixel depth of target bitmap
116 sal_uInt8 mnTransRed;
117 sal_uInt8 mnTransGreen;
118 sal_uInt8 mnTransBlue;
119 sal_uInt8 mnPngDepth; // pixel depth of PNG data
120 sal_uInt8 mnColorType;
121 sal_uInt8 mnCompressionType;
122 sal_uInt8 mnFilterType;
123 sal_uInt8 mnInterlaceType;
124 const BitmapColor mcTranspColor; // transparency mask's transparency "color"
125 const BitmapColor mcOpaqueColor; // transparency mask's opaque "color"
126 bool mbTransparent : 1; // graphic includes a tRNS Chunk or an alpha Channel
127 bool mbAlphaChannel : 1; // is true for ColorType 4 and 6
128 bool mbRGBTriple : 1;
129 bool mbPalette : 1; // false if we need a Palette
130 bool mbGrayScale : 1;
131 bool mbzCodecInUse : 1;
132 bool mbStatus : 1;
133 bool mbIDATStarted : 1; // true if IDAT seen
134 bool mbIDATComplete : 1; // true if finished with enough IDAT chunks
135 bool mbpHYs : 1; // true if physical size of pixel available
136 bool mbIgnoreCRC : 1; // skip checking CRCs while fuzzing
137
138#if OSL_DEBUG_LEVEL1 > 0
139 // do some checks in debug mode
140 sal_Int32 mnAllocSizeScanline;
141 sal_Int32 mnAllocSizeScanlineAlpha;
142#endif
143 // the temporary Scanline (and alpha) for direct scanline copy to Bitmap
144 std::unique_ptr<sal_uInt8[]>
145 mpScanline;
146 std::unique_ptr<sal_uInt8[]>
147 mpScanlineAlpha;
148
149 bool ReadNextChunk();
150
151 void ImplSetPixel( sal_uInt32 y, sal_uInt32 x, const BitmapColor & );
152 void ImplSetPixel( sal_uInt32 y, sal_uInt32 x, sal_uInt8 nPalIndex );
153 void ImplSetTranspPixel( sal_uInt32 y, sal_uInt32 x, const BitmapColor &, bool bTrans );
154 void ImplSetAlphaPixel( sal_uInt32 y, sal_uInt32 x, sal_uInt8 nPalIndex, sal_uInt8 nAlpha );
155 void ImplSetAlphaPixel( sal_uInt32 y, sal_uInt32 x, const BitmapColor&, sal_uInt8 nAlpha );
156 void ImplReadIDAT();
157 bool ImplPreparePass();
158 void ImplApplyFilter();
159 void ImplDrawScanline( sal_uInt32 nXStart, sal_uInt32 nXAdd );
160 bool ImplReadTransparent();
161 void ImplGetGamma();
162 void ImplGetBackground();
163 sal_uInt8 ImplScaleColor();
164 bool ImplReadHeader();
165 bool ImplReadPalette();
166 void ImplGetGrayPalette( sal_uInt16 );
167 sal_uInt32 ImplReadsal_uInt32();
168
169public:
170
171 explicit PNGReaderImpl( SvStream& );
172 ~PNGReaderImpl();
173
174 BitmapEx GetBitmapEx();
175 const std::vector<vcl::PNGReader::ChunkData>& GetAllChunks();
176};
177
178PNGReaderImpl::PNGReaderImpl( SvStream& rPNGStream )
179: mrPNGStream( rPNGStream ),
180 mpMaskAcc ( nullptr ),
181 mpScanCurrent ( nullptr ),
182 mpColorTable ( const_cast<sal_uInt8*>(mpDefaultColorTable) ),
183 mnChunkType ( 0 ),
184 mnChunkLen ( 0 ),
185 mnBPP ( 0 ),
186 mnScansize ( 0 ),
187 mnYpos ( 0 ),
188 mnPass ( 0 ),
189 mnXStart ( 0 ),
190 mnXAdd ( 0 ),
191 mnYAdd ( 0 ),
192 mnTargetDepth ( 0 ),
193 mnTransRed ( 0 ),
194 mnTransGreen ( 0 ),
195 mnTransBlue ( 0 ),
196 mnPngDepth ( 0 ),
197 mnColorType ( 0 ),
198 mnCompressionType( 0 ),
199 mnFilterType ( 0 ),
200 mnInterlaceType ( 0 ),
201 mcTranspColor ( BitmapColor( 0xFF )),
202 mcOpaqueColor ( BitmapColor( 0x00 )),
203 mbTransparent( false ),
204 mbAlphaChannel( false ),
205 mbRGBTriple( false ),
206 mbPalette( false ),
207 mbGrayScale( false ),
208 mbzCodecInUse ( false ),
209 mbStatus( true ),
210 mbIDATStarted( false ),
211 mbIDATComplete( false ),
212 mbpHYs ( false ),
213 mbIgnoreCRC( utl::ConfigManager::IsFuzzing() )
214#if OSL_DEBUG_LEVEL1 > 0
215 ,mnAllocSizeScanline(0),
216 mnAllocSizeScanlineAlpha(0)
217#endif
218{
219 // prepare the PNG data stream
220 mnOrigStreamMode = mrPNGStream.GetEndian();
221 mrPNGStream.SetEndian( SvStreamEndian::BIG );
222
223 // prepare the chunk reader
224 maChunkSeq.reserve( 16 );
225 maChunkIter = maChunkSeq.begin();
226
227 // estimate PNG file size (to allow sanity checks)
228 mnStreamSize = mrPNGStream.TellEnd();
229
230 // check the PNG header magic
231 sal_uInt32 nDummy = 0;
232 mrPNGStream.ReadUInt32( nDummy );
233 mbStatus = (nDummy == 0x89504e47);
234 mrPNGStream.ReadUInt32( nDummy );
235 mbStatus = (nDummy == 0x0d0a1a0a) && mbStatus;
236
237 mnPreviewShift = 0;
238 mnPreviewMask = (1 << mnPreviewShift) - 1;
239}
240
241PNGReaderImpl::~PNGReaderImpl()
242{
243 mrPNGStream.SetEndian( mnOrigStreamMode );
244
245 if ( mbzCodecInUse )
246 mpZCodec.EndCompression();
247
248 if( mpColorTable != mpDefaultColorTable )
249 delete[] mpColorTable;
250}
251
252bool PNGReaderImpl::ReadNextChunk()
253{
254 if( maChunkIter == maChunkSeq.end() )
255 {
256 // get the next chunk from the stream
257
258 // unless we are at the end of the PNG stream
259 if (!mrPNGStream.good())
260 return false;
261 if( !maChunkSeq.empty() && (maChunkSeq.back().nType == PNGCHUNK_IEND0x49454e44) )
262 return false;
263
264 PNGReader::ChunkData aDummyChunk;
265 maChunkIter = maChunkSeq.insert( maChunkSeq.end(), aDummyChunk );
266 PNGReader::ChunkData& rChunkData = *maChunkIter;
267
268 // read the chunk header
269 mnChunkLen = 0;
270 mnChunkType = 0;
271 mrPNGStream.ReadInt32( mnChunkLen ).ReadUInt32( mnChunkType );
272 rChunkData.nType = mnChunkType;
273
274 // fdo#61847 truncate over-long, trailing chunks
275 const std::size_t nStreamPos = mrPNGStream.Tell();
276 if( mnChunkLen < 0 || nStreamPos + mnChunkLen >= mnStreamSize )
277 mnChunkLen = mnStreamSize - nStreamPos;
278
279 // calculate chunktype CRC (swap it back to original byte order)
280 sal_uInt32 nChunkType = mnChunkType;
281 #if defined(__LITTLEENDIAN) || defined(OSL_LITENDIAN)
282 nChunkType = OSL_SWAPDWORD( nChunkType )((sal_uInt32)((((sal_uInt16)((sal_uInt16)((((sal_uInt8)(((sal_uInt16
)(((sal_uInt16)(((sal_uInt32)(nChunkType) >> 16) & 0xFFFF
))) >> 8) & 0xFF))) & 0xFF) | (((sal_uInt16)(((
sal_uInt8)((sal_uInt16)(((sal_uInt16)(((sal_uInt32)(nChunkType
) >> 16) & 0xFFFF))) & 0xFF))) & 0xFF) <<
8)))) & 0xFFFF) | (((sal_uInt32)(((sal_uInt16)((sal_uInt16
)((((sal_uInt8)(((sal_uInt16)(((sal_uInt16)((sal_uInt32)(nChunkType
) & 0xFFFF))) >> 8) & 0xFF))) & 0xFF) | (((
sal_uInt16)(((sal_uInt8)((sal_uInt16)(((sal_uInt16)((sal_uInt32
)(nChunkType) & 0xFFFF))) & 0xFF))) & 0xFF) <<
8)))) & 0xFFFF) << 16))
;
283 #endif
284 sal_uInt32 nCRC32 = rtl_crc32( 0, &nChunkType, 4 );
285
286 // read the chunk data and check the CRC
287 if( mnChunkLen && !mrPNGStream.eof() )
288 {
289 rChunkData.aData.resize( mnChunkLen );
290
291 sal_Int32 nBytesRead = 0;
292 do
293 {
294 sal_uInt8& rPtr = rChunkData.aData[nBytesRead];
295 nBytesRead += mrPNGStream.ReadBytes(&rPtr, mnChunkLen - nBytesRead);
296 } while (nBytesRead < mnChunkLen && mrPNGStream.good());
297
298 nCRC32 = rtl_crc32( nCRC32, rChunkData.aData.data(), mnChunkLen );
299 maDataIter = rChunkData.aData.begin();
300 }
301 sal_uInt32 nCheck(0);
302 mrPNGStream.ReadUInt32( nCheck );
303 if (!mbIgnoreCRC && nCRC32 != nCheck)
304 return false;
305 }
306 else
307 {
308 // the next chunk was already read
309 mnChunkType = (*maChunkIter).nType;
310 mnChunkLen = (*maChunkIter).aData.size();
311 maDataIter = (*maChunkIter).aData.begin();
312 }
313
314 ++maChunkIter;
315 return mnChunkType != PNGCHUNK_IEND0x49454e44;
316}
317
318const std::vector< vcl::PNGReader::ChunkData >& PNGReaderImpl::GetAllChunks()
319{
320 // read the remaining chunks from mrPNGStream
321 while( ReadNextChunk() ) ;
322 return maChunkSeq;
323}
324
325BitmapEx PNGReaderImpl::GetBitmapEx()
326{
327 // reset to the first chunk
328 maChunkIter = maChunkSeq.begin();
329
330 // first chunk must be IDHR
331 if( mbStatus && ReadNextChunk() )
332 {
333 if (mnChunkType == PNGCHUNK_IHDR0x49484452)
334 mbStatus = ImplReadHeader();
335 else
336 mbStatus = false;
337 }
338
339 // parse the remaining chunks
340 while (mbStatus && !mbIDATComplete && ReadNextChunk())
341 {
342 switch( mnChunkType )
343 {
344 case PNGCHUNK_IHDR0x49484452 :
345 {
346 mbStatus = false; //IHDR should only appear as the first chunk
347 }
348 break;
349
350 case PNGCHUNK_gAMA0x67414d41 : // the gamma chunk must precede
351 { // the 'IDAT' and also the 'PLTE'(if available )
352 if (!mbIDATComplete)
353 ImplGetGamma();
354 }
355 break;
356
357 case PNGCHUNK_PLTE0x504c5445 :
358 {
359 if (!mbPalette && !mbIDATStarted)
360 mbStatus = ImplReadPalette();
361 }
362 break;
363
364 case PNGCHUNK_tRNS0x74524e53 :
365 {
366 if (!mbIDATComplete) // the tRNS chunk must precede the IDAT
367 mbStatus = ImplReadTransparent();
368 }
369 break;
370
371 case PNGCHUNK_bKGD0x624b4744 : // the background chunk must appear
372 {
373 if (!mbIDATComplete && mbPalette) // before the 'IDAT' and after the
374 ImplGetBackground(); // PLTE(if available ) chunk.
375 }
376 break;
377
378 case PNGCHUNK_IDAT0x49444154 :
379 {
380 if ( !mpInflateInBuf ) // taking care that the header has properly been read
381 mbStatus = false;
382 else if (!mbIDATComplete) // the gfx is finished, but there may be left a zlibCRC of about 4Bytes
383 ImplReadIDAT();
384 }
385 break;
386
387 case PNGCHUNK_pHYs0x70485973 :
388 {
389 if (!mbIDATComplete && mnChunkLen == 9)
390 {
391 sal_uInt32 nXPixelPerMeter = ImplReadsal_uInt32();
392 sal_uInt32 nYPixelPerMeter = ImplReadsal_uInt32();
393
394 sal_uInt8 nUnitSpecifier = *maDataIter++;
395 if( (nUnitSpecifier == 1) && nXPixelPerMeter && nYPixelPerMeter )
396 {
397 mbpHYs = true;
398
399 // convert into MapUnit::Map100thMM
400 maPhysSize.setWidth( static_cast<sal_Int32>( (100000.0 * maOrigSize.Width()) / nXPixelPerMeter ) );
401 maPhysSize.setHeight( static_cast<sal_Int32>( (100000.0 * maOrigSize.Height()) / nYPixelPerMeter ) );
402 }
403 }
404 }
405 break;
406
407 case PNGCHUNK_IEND0x49454e44:
408 mbStatus = mbIDATComplete; // there is a problem if the image is not complete yet
409 break;
410 }
411 }
412
413 // release write access of the bitmaps
414 mxAcc.reset();
415 mxMaskAcc.reset();
416 mxAlphaAcc.reset();
417 mpMaskAcc = nullptr;
418
419 // return the resulting BitmapEx
420 BitmapEx aRet;
421
422 if (!mbStatus || !mbIDATComplete)
423 aRet.Clear();
424 else
425 {
426 if ( mpAlphaMask )
427 aRet = BitmapEx( *mpBmp, *mpAlphaMask );
428 else if ( mpMaskBmp )
429 aRet = BitmapEx( *mpBmp, *mpMaskBmp );
430 else
431 aRet = *mpBmp;
432
433 if ( mbpHYs && maPhysSize.Width() && maPhysSize.Height() )
434 {
435 aRet.SetPrefMapMode(MapMode(MapUnit::Map100thMM));
436 aRet.SetPrefSize( maPhysSize );
437 }
438 }
439 return aRet;
440}
441
442bool PNGReaderImpl::ImplReadHeader()
443{
444 if( mnChunkLen < 13 )
445 return false;
446
447 maOrigSize.setWidth( ImplReadsal_uInt32() );
448 maOrigSize.setHeight( ImplReadsal_uInt32() );
449
450 if (maOrigSize.IsEmpty())
451 return false;
452
453 mnPngDepth = *(maDataIter++);
454 mnColorType = *(maDataIter++);
455
456 mnCompressionType = *(maDataIter++);
457 if( mnCompressionType != 0 ) // unknown compression type
458 return false;
459
460 mnFilterType = *(maDataIter++);
461 if( mnFilterType != 0 ) // unknown filter type
462 return false;
463
464 mnInterlaceType = *(maDataIter++);
465 switch ( mnInterlaceType ) // filter type valid ?
466 {
467 case 0 : // progressive image
468 mnPass = 7;
469 break;
470 case 1 : // Adam7-interlaced image
471 mnPass = 0;
472 break;
473 default:
474 return false;
475 }
476
477 mbPalette = true;
478 mbIDATStarted = mbIDATComplete = mbAlphaChannel = mbTransparent = false;
479 mbGrayScale = mbRGBTriple = false;
480 mnTargetDepth = mnPngDepth;
481 sal_uInt64 nScansize64 = ( ( static_cast< sal_uInt64 >( maOrigSize.Width() ) * mnPngDepth ) + 7 ) >> 3;
482
483 // valid color types are 0,2,3,4 & 6
484 switch ( mnColorType )
485 {
486 case 0 : // each pixel is a grayscale
487 {
488 switch ( mnPngDepth )
489 {
490 case 2 : // 2bit target not available -> use four bits
491 mnTargetDepth = 4; // we have to expand the bitmap
492 mbGrayScale = true;
493 break;
494 case 16 :
495 mnTargetDepth = 8; // we have to reduce the bitmap
496 [[fallthrough]];
497 case 1 :
498 case 4 :
499 case 8 :
500 mbGrayScale = true;
501 break;
502 default :
503 return false;
504 }
505 }
506 break;
507
508 case 2 : // each pixel is an RGB triple
509 {
510 mbRGBTriple = true;
511 nScansize64 *= 3;
512 switch ( mnPngDepth )
513 {
514 case 16 : // we have to reduce the bitmap
515 case 8 :
516 mnTargetDepth = 24;
517 break;
518 default :
519 return false;
520 }
521 }
522 break;
523
524 case 3 : // each pixel is a palette index
525 {
526 switch ( mnPngDepth )
527 {
528 case 2 :
529 mnTargetDepth = 4; // we have to expand the bitmap
530 mbPalette = false;
531 break;
532 case 1 :
533 case 4 :
534 case 8 :
535 mbPalette = false;
536 break;
537 default :
538 return false;
539 }
540 }
541 break;
542
543 case 4 : // each pixel is a grayscale sample followed by an alpha sample
544 {
545 nScansize64 *= 2;
546 mbAlphaChannel = true;
547 switch ( mnPngDepth )
548 {
549 case 16 :
550 mnTargetDepth = 8; // we have to reduce the bitmap
551 [[fallthrough]];
552 case 8 :
553 mbGrayScale = true;
554 break;
555 default :
556 return false;
557 }
558 }
559 break;
560
561 case 6 : // each pixel is an RGB triple followed by an alpha sample
562 {
563 mbRGBTriple = true;
564 nScansize64 *= 4;
565 mbAlphaChannel = true;
566 switch (mnPngDepth )
567 {
568 case 16 : // we have to reduce the bitmap
569 case 8 :
570 mnTargetDepth = 24;
571 break;
572 default :
573 return false;
574 }
575 }
576 break;
577
578 default :
579 return false;
580 }
581
582 mnBPP = static_cast< sal_uInt32 >( nScansize64 / maOrigSize.Width() );
583 if ( !mnBPP )
584 mnBPP = 1;
585
586 nScansize64++; // each scanline includes one filterbyte
587
588 if ( nScansize64 > SAL_MAX_UINT32((sal_uInt32) 0xFFFFFFFF) )
589 return false;
590
591 // assume max theoretical compression of 1:1032
592 sal_uInt64 nMinSizeRequired = (nScansize64 * maOrigSize.Height()) / 1032;
593 if (nMinSizeRequired > mnStreamSize)
594 {
595 SAL_WARN("vcl.gdi", "overlarge png dimensions: " <<do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl.gdi")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "overlarge png dimensions: "
<< maOrigSize.Width() << " x " << maOrigSize
.Height() << " depth: " << static_cast<int>
(mnPngDepth) << " couldn't be supplied by file length "
<< mnStreamSize << " at least " << nMinSizeRequired
<< " needed ") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "597" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "overlarge png dimensions: " << maOrigSize
.Width() << " x " << maOrigSize.Height() <<
" depth: " << static_cast<int>(mnPngDepth) <<
" couldn't be supplied by file length " << mnStreamSize
<< " at least " << nMinSizeRequired << " needed "
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "overlarge png dimensions: " << maOrigSize.Width
() << " x " << maOrigSize.Height() << " depth: "
<< static_cast<int>(mnPngDepth) << " couldn't be supplied by file length "
<< mnStreamSize << " at least " << nMinSizeRequired
<< " needed "; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "597" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "overlarge png dimensions: " << maOrigSize.
Width() << " x " << maOrigSize.Height() << " depth: "
<< static_cast<int>(mnPngDepth) << " couldn't be supplied by file length "
<< mnStreamSize << " at least " << nMinSizeRequired
<< " needed ") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "597" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "overlarge png dimensions: " << maOrigSize
.Width() << " x " << maOrigSize.Height() <<
" depth: " << static_cast<int>(mnPngDepth) <<
" couldn't be supplied by file length " << mnStreamSize
<< " at least " << nMinSizeRequired << " needed "
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "overlarge png dimensions: " << maOrigSize.Width
() << " x " << maOrigSize.Height() << " depth: "
<< static_cast<int>(mnPngDepth) << " couldn't be supplied by file length "
<< mnStreamSize << " at least " << nMinSizeRequired
<< " needed "; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "597" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
596 maOrigSize.Width() << " x " << maOrigSize.Height() << " depth: " << static_cast<int>(mnPngDepth) <<do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl.gdi")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "overlarge png dimensions: "
<< maOrigSize.Width() << " x " << maOrigSize
.Height() << " depth: " << static_cast<int>
(mnPngDepth) << " couldn't be supplied by file length "
<< mnStreamSize << " at least " << nMinSizeRequired
<< " needed ") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "597" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "overlarge png dimensions: " << maOrigSize
.Width() << " x " << maOrigSize.Height() <<
" depth: " << static_cast<int>(mnPngDepth) <<
" couldn't be supplied by file length " << mnStreamSize
<< " at least " << nMinSizeRequired << " needed "
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "overlarge png dimensions: " << maOrigSize.Width
() << " x " << maOrigSize.Height() << " depth: "
<< static_cast<int>(mnPngDepth) << " couldn't be supplied by file length "
<< mnStreamSize << " at least " << nMinSizeRequired
<< " needed "; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "597" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "overlarge png dimensions: " << maOrigSize.
Width() << " x " << maOrigSize.Height() << " depth: "
<< static_cast<int>(mnPngDepth) << " couldn't be supplied by file length "
<< mnStreamSize << " at least " << nMinSizeRequired
<< " needed ") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "597" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "overlarge png dimensions: " << maOrigSize
.Width() << " x " << maOrigSize.Height() <<
" depth: " << static_cast<int>(mnPngDepth) <<
" couldn't be supplied by file length " << mnStreamSize
<< " at least " << nMinSizeRequired << " needed "
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "overlarge png dimensions: " << maOrigSize.Width
() << " x " << maOrigSize.Height() << " depth: "
<< static_cast<int>(mnPngDepth) << " couldn't be supplied by file length "
<< mnStreamSize << " at least " << nMinSizeRequired
<< " needed "; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "597" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
597 " couldn't be supplied by file length " << mnStreamSize << " at least " << nMinSizeRequired << " needed ")do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl.gdi")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "overlarge png dimensions: "
<< maOrigSize.Width() << " x " << maOrigSize
.Height() << " depth: " << static_cast<int>
(mnPngDepth) << " couldn't be supplied by file length "
<< mnStreamSize << " at least " << nMinSizeRequired
<< " needed ") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "597" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "overlarge png dimensions: " << maOrigSize
.Width() << " x " << maOrigSize.Height() <<
" depth: " << static_cast<int>(mnPngDepth) <<
" couldn't be supplied by file length " << mnStreamSize
<< " at least " << nMinSizeRequired << " needed "
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "overlarge png dimensions: " << maOrigSize.Width
() << " x " << maOrigSize.Height() << " depth: "
<< static_cast<int>(mnPngDepth) << " couldn't be supplied by file length "
<< mnStreamSize << " at least " << nMinSizeRequired
<< " needed "; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "597" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "overlarge png dimensions: " << maOrigSize.
Width() << " x " << maOrigSize.Height() << " depth: "
<< static_cast<int>(mnPngDepth) << " couldn't be supplied by file length "
<< mnStreamSize << " at least " << nMinSizeRequired
<< " needed ") == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "597" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "overlarge png dimensions: " << maOrigSize
.Width() << " x " << maOrigSize.Height() <<
" depth: " << static_cast<int>(mnPngDepth) <<
" couldn't be supplied by file length " << mnStreamSize
<< " at least " << nMinSizeRequired << " needed "
), 0); } else { ::std::ostringstream sal_detail_stream; sal_detail_stream
<< "overlarge png dimensions: " << maOrigSize.Width
() << " x " << maOrigSize.Height() << " depth: "
<< static_cast<int>(mnPngDepth) << " couldn't be supplied by file length "
<< mnStreamSize << " at least " << nMinSizeRequired
<< " needed "; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "597" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
598 return false;
599 }
600
601 mnScansize = static_cast< sal_uInt32 >( nScansize64 );
602
603 maTargetSize.setWidth( (maOrigSize.Width() + mnPreviewMask) >> mnPreviewShift );
604 maTargetSize.setHeight( (maOrigSize.Height() + mnPreviewMask) >> mnPreviewShift );
605
606 //round bits up to nearest multiple of 8 and divide by 8 to get num of bytes per pixel
607 int nBytesPerPixel = ((mnTargetDepth + 7) & ~7)/8;
608
609 //stupidly big, forget about it
610 if (maTargetSize.Width() >= SAL_MAX_INT32((sal_Int32) 0x7FFFFFFF) / nBytesPerPixel / maTargetSize.Height())
611 {
612 SAL_WARN( "vcl.gdi", "overlarge png dimensions: " <<do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl.gdi")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "overlarge png dimensions: "
<< maTargetSize.Width() << " x " << maTargetSize
.Height() << " depth: " << mnTargetDepth) == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi")
, ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "613" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "overlarge png dimensions: " << maTargetSize
.Width() << " x " << maTargetSize.Height() <<
" depth: " << mnTargetDepth), 0); } else { ::std::ostringstream
sal_detail_stream; sal_detail_stream << "overlarge png dimensions: "
<< maTargetSize.Width() << " x " << maTargetSize
.Height() << " depth: " << mnTargetDepth; ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "613" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "overlarge png dimensions: " << maTargetSize
.Width() << " x " << maTargetSize.Height() <<
" depth: " << mnTargetDepth) == 1) { ::sal_detail_log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "613" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "overlarge png dimensions: " << maTargetSize
.Width() << " x " << maTargetSize.Height() <<
" depth: " << mnTargetDepth), 0); } else { ::std::ostringstream
sal_detail_stream; sal_detail_stream << "overlarge png dimensions: "
<< maTargetSize.Width() << " x " << maTargetSize
.Height() << " depth: " << mnTargetDepth; ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "613" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
613 maTargetSize.Width() << " x " << maTargetSize.Height() << " depth: " << mnTargetDepth)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl.gdi")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "overlarge png dimensions: "
<< maTargetSize.Width() << " x " << maTargetSize
.Height() << " depth: " << mnTargetDepth) == 1) {
::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi")
, ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "613" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "overlarge png dimensions: " << maTargetSize
.Width() << " x " << maTargetSize.Height() <<
" depth: " << mnTargetDepth), 0); } else { ::std::ostringstream
sal_detail_stream; sal_detail_stream << "overlarge png dimensions: "
<< maTargetSize.Width() << " x " << maTargetSize
.Height() << " depth: " << mnTargetDepth; ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "613" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "overlarge png dimensions: " << maTargetSize
.Width() << " x " << maTargetSize.Height() <<
" depth: " << mnTargetDepth) == 1) { ::sal_detail_log(
(::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "613" ": "), ::sal::detail::unwrapStream( ::sal::detail::
StreamStart() << "overlarge png dimensions: " << maTargetSize
.Width() << " x " << maTargetSize.Height() <<
" depth: " << mnTargetDepth), 0); } else { ::std::ostringstream
sal_detail_stream; sal_detail_stream << "overlarge png dimensions: "
<< maTargetSize.Width() << " x " << maTargetSize
.Height() << " depth: " << mnTargetDepth; ::sal::
detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "613" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
614 return false;
615 }
616
617 // TODO: switch between both scanlines instead of copying
618 mpInflateInBuf.reset( new (std::nothrow) sal_uInt8[ mnScansize ] );
619 mpScanCurrent = mpInflateInBuf.get();
620 mpScanPrior.reset( new (std::nothrow) sal_uInt8[ mnScansize ] );
621
622 if ( !mpInflateInBuf || !mpScanPrior )
623 return false;
624
625 mpBmp = std::make_unique<Bitmap>( maTargetSize, mnTargetDepth );
626 mxAcc = BitmapScopedWriteAccess(*mpBmp);
627 if (!mxAcc)
628 return false;
629
630 if ( mbAlphaChannel )
631 {
632 mpAlphaMask = std::make_unique<AlphaMask>( maTargetSize );
633 mpAlphaMask->Erase( 128 );
634 mxAlphaAcc = AlphaScopedWriteAccess(*mpAlphaMask);
635 mpMaskAcc = mxAlphaAcc.get();
636 if (!mpMaskAcc)
637 return false;
638 }
639
640 if ( mbGrayScale )
641 ImplGetGrayPalette( mnPngDepth );
642
643 ImplPreparePass();
644
645 return true;
646}
647
648void PNGReaderImpl::ImplGetGrayPalette( sal_uInt16 nBitDepth )
649{
650 if( nBitDepth > 8 )
651 nBitDepth = 8;
652
653 sal_uInt16 nPaletteEntryCount = 1 << nBitDepth;
654 sal_uInt32 nAdd = nBitDepth ? 256 / (nPaletteEntryCount - 1) : 0;
655
656 // no bitdepth==2 available
657 // but bitdepth==4 with two unused bits is close enough
658 if( nBitDepth == 2 )
659 nPaletteEntryCount = 16;
660
661 mxAcc->SetPaletteEntryCount( nPaletteEntryCount );
662 for ( sal_uInt32 i = 0, nStart = 0; nStart < 256; i++, nStart += nAdd )
663 mxAcc->SetPaletteColor( static_cast<sal_uInt16>(i), BitmapColor( mpColorTable[ nStart ],
664 mpColorTable[ nStart ], mpColorTable[ nStart ] ) );
665}
666
667bool PNGReaderImpl::ImplReadPalette()
668{
669 sal_uInt16 nCount = static_cast<sal_uInt16>( mnChunkLen / 3 );
670
671 if ( ( ( mnChunkLen % 3 ) == 0 ) && ( ( 0 < nCount ) && ( nCount <= 256 ) ) && mxAcc )
672 {
673 mbPalette = true;
674 mxAcc->SetPaletteEntryCount( nCount );
675
676 for ( sal_uInt16 i = 0; i < nCount; i++ )
677 {
678 sal_uInt8 nRed = mpColorTable[ *maDataIter++ ];
679 sal_uInt8 nGreen = mpColorTable[ *maDataIter++ ];
680 sal_uInt8 nBlue = mpColorTable[ *maDataIter++ ];
681 mxAcc->SetPaletteColor( i, Color( nRed, nGreen, nBlue ) );
682 }
683 }
684 else
685 mbStatus = false;
686
687 return mbStatus;
688}
689
690bool PNGReaderImpl::ImplReadTransparent()
691{
692 bool bNeedAlpha = false;
693
694 if ( mpTransTab == nullptr )
695 {
696 switch ( mnColorType )
697 {
698 case 0 :
699 {
700 if ( mnChunkLen == 2 )
701 {
702 mpTransTab.reset( new sal_uInt8[ 256 ] );
703 memset( mpTransTab.get(), 0xff, 256);
704 // color type 0 and 4 is always greyscale,
705 // so the return value can be used as index
706 sal_uInt8 nIndex = ImplScaleColor();
707 mpTransTab[ nIndex ] = 0;
708 mbTransparent = true;
709 }
710 }
711 break;
712
713 case 2 :
714 {
715 if ( mnChunkLen == 6 )
716 {
717 mnTransRed = ImplScaleColor();
718 mnTransGreen = ImplScaleColor();
719 mnTransBlue = ImplScaleColor();
720 mbTransparent = true;
721 }
722 }
723 break;
724
725 case 3 :
726 {
727 if ( mnChunkLen <= 256 )
728 {
729 mbTransparent = true;
730 mpTransTab.reset( new sal_uInt8 [ 256 ] );
731 memset( mpTransTab.get(), 0xff, 256 );
732 if (mnChunkLen > 0)
733 {
734 memcpy( mpTransTab.get(), &(*maDataIter), mnChunkLen );
735 maDataIter += mnChunkLen;
736 // need alpha transparency if not on/off masking
737 for( int i = 0; i < mnChunkLen; ++i )
738 bNeedAlpha |= (mpTransTab[i]!=0x00) && (mpTransTab[i]!=0xFF);
739 }
740 }
741 }
742 break;
743 }
744 }
745
746 if( mbTransparent && !mbAlphaChannel && !mpMaskBmp )
747 {
748 if( bNeedAlpha)
749 {
750 mpAlphaMask = std::make_unique<AlphaMask>( maTargetSize );
751 mxAlphaAcc = AlphaScopedWriteAccess(*mpAlphaMask);
752 mpMaskAcc = mxAlphaAcc.get();
753 }
754 else
755 {
756 mpMaskBmp = std::make_unique<Bitmap>( maTargetSize, 1 );
757 mxMaskAcc = BitmapScopedWriteAccess(*mpMaskBmp);
758 mpMaskAcc = mxMaskAcc.get();
759 }
760 mbTransparent = (mpMaskAcc != nullptr);
761 if( !mbTransparent )
762 return false;
763 mpMaskAcc->Erase( Color(0,0,0) );
764 }
765
766 return true;
767}
768
769void PNGReaderImpl::ImplGetGamma()
770{
771 if( mnChunkLen < 4 )
772 return;
773
774 sal_uInt32 nGammaValue = ImplReadsal_uInt32();
775 double fGamma = ( VIEWING_GAMMA2.35 / DISPLAY_GAMMA1.0 ) * ( static_cast<double>(nGammaValue) / 100000 );
776 double fInvGamma = ( fGamma <= 0.0 || fGamma > 10.0 ) ? 1.0 : ( 1.0 / fGamma );
777
778 if ( fInvGamma != 1.0 )
779 {
780 if ( mpColorTable == mpDefaultColorTable )
781 mpColorTable = new sal_uInt8[ 256 ];
782
783 for ( sal_Int32 i = 0; i < 256; i++ )
784 mpColorTable[ i ] = static_cast<sal_uInt8>(pow(static_cast<double>(i)/255.0, fInvGamma) * 255.0 + 0.5);
785
786 if ( mbGrayScale )
787 ImplGetGrayPalette( mnPngDepth );
788 }
789}
790
791void PNGReaderImpl::ImplGetBackground()
792{
793 switch (mnColorType)
794 {
795 case 3:
796 {
797 if (mnChunkLen == 1)
798 {
799 sal_uInt16 nCol = *maDataIter++;
800
801 if (nCol < mxAcc->GetPaletteEntryCount())
802 {
803 mxAcc->Erase(mxAcc->GetPaletteColor(static_cast<sal_uInt8>(nCol)));
804 break;
805 }
806 }
807 }
808 break;
809
810 case 0:
811 case 4:
812 {
813 if (mnChunkLen == 2)
814 {
815 // the color type 0 and 4 is always greyscale,
816 // so the return value can be used as index
817 mxAcc->Erase(mxAcc->GetPaletteColor(ImplScaleColor()));
818 }
819 }
820 break;
821
822 case 2:
823 case 6:
824 {
825 if (mnChunkLen == 6)
826 {
827 sal_uInt8 nRed = ImplScaleColor();
828 sal_uInt8 nGreen = ImplScaleColor();
829 sal_uInt8 nBlue = ImplScaleColor();
830 // ofz#18653 slow and uninteresting
831 if (utl::ConfigManager::IsFuzzing())
832 return;
833 mxAcc->Erase(Color(nRed, nGreen, nBlue));
834 }
835 }
836 break;
837 }
838}
839
840// for color type 0 and 4 (greyscale) the return value is always index to the color
841// 2 and 6 (RGB) the return value is always the 8 bit color component
842sal_uInt8 PNGReaderImpl::ImplScaleColor()
843{
844 sal_uInt32 nMask = ( 1 << mnPngDepth ) - 1;
845 sal_uInt16 nCol = ( *maDataIter++ << 8 );
846
847 nCol += *maDataIter++ & static_cast<sal_uInt16>(nMask);
848
849 if ( mnPngDepth > 8 ) // convert 16bit graphics to 8
850 nCol >>= 8;
851
852 return static_cast<sal_uInt8>(nCol);
853}
854
855// ImplReadIDAT reads as much image data as needed
856
857void PNGReaderImpl::ImplReadIDAT()
858{
859 //when fuzzing with a max len set, max decompress to 250 times that limit
860 static size_t nMaxAllowedDecompression = [](const char* pEnv) { size_t nRet = pEnv ? std::atoi(pEnv) : 0; return nRet * 250; }(std::getenv("FUZZ_MAX_INPUT_LEN"));
861 size_t nTotalDataRead = 0;
862
863 if( mnChunkLen > 0 )
864 {
865 mbIDATStarted = true;
866
867 if ( !mbzCodecInUse )
868 {
869 mbzCodecInUse = true;
870 mpZCodec.BeginCompression( ZCODEC_NO_COMPRESSION0 );
871 }
872 mpZCodec.SetBreak( mnChunkLen );
873 SvMemoryStream aIStrm( &(*maDataIter), mnChunkLen, StreamMode::READ );
874
875 while ( mpZCodec.GetBreak() )
876 {
877 // get bytes needed to fill the current scanline
878 sal_Int32 nToRead = mnScansize - (mpScanCurrent - mpInflateInBuf.get());
879 sal_Int32 nRead = mpZCodec.ReadAsynchron( aIStrm, mpScanCurrent, nToRead );
880 if ( nRead < 0 )
881 {
882 mbStatus = false;
883 break;
884 }
885 nTotalDataRead += nRead;
886 if (nMaxAllowedDecompression && nTotalDataRead > nMaxAllowedDecompression)
887 {
888 mbStatus = false;
889 break;
890 }
891 if ( nRead < nToRead )
892 {
893 mpScanCurrent += nRead; // more ZStream data in the next IDAT chunk
894 break;
895 }
896 else // this scanline is Finished
897 {
898 mpScanCurrent = mpInflateInBuf.get();
899 ImplApplyFilter();
900
901 ImplDrawScanline( mnXStart, mnXAdd );
902 mnYpos += mnYAdd;
903 }
904
905 if ( mnYpos >= o3tl::make_unsigned(maOrigSize.Height()) )
906 {
907 if( (mnPass < 7) && mnInterlaceType )
908 if( ImplPreparePass() )
909 continue;
910 mbIDATComplete = true;
911 break;
912 }
913 }
914 }
915
916 if (mbIDATComplete)
917 {
918 mpZCodec.EndCompression();
919 mbzCodecInUse = false;
920 }
921}
922
923bool PNGReaderImpl::ImplPreparePass()
924{
925 struct InterlaceParams{ int mnXStart, mnYStart, mnXAdd, mnYAdd; };
926 static const InterlaceParams aInterlaceParams[8] =
927 {
928 // non-interlaced
929 { 0, 0, 1, 1 },
930 // Adam7-interlaced
931 { 0, 0, 8, 8 }, // pass 1
932 { 4, 0, 8, 8 }, // pass 2
933 { 0, 4, 4, 8 }, // pass 3
934 { 2, 0, 4, 4 }, // pass 4
935 { 0, 2, 2, 4 }, // pass 5
936 { 1, 0, 2, 2 }, // pass 6
937 { 0, 1, 1, 2 } // pass 7
938 };
939
940 const InterlaceParams* pParam = &aInterlaceParams[ 0 ];
941 if( mnInterlaceType )
942 {
943 while( ++mnPass <= 7 )
944 {
945 pParam = &aInterlaceParams[ mnPass ];
946
947 // skip this pass if the original image is too small for it
948 if( (pParam->mnXStart < maOrigSize.Width())
949 && (pParam->mnYStart < maOrigSize.Height()) )
950 break;
951 }
952 if( mnPass > 7 )
953 return false;
954
955 // skip the last passes if possible (for scaled down target images)
956 if( mnPreviewMask & (pParam->mnXStart | pParam->mnYStart) )
957 return false;
958 }
959
960 mnYpos = pParam->mnYStart;
961 mnXStart = pParam->mnXStart;
962 mnXAdd = pParam->mnXAdd;
963 mnYAdd = pParam->mnYAdd;
964
965 // in Interlace mode the size of scanline is not constant
966 // so first we calculate the number of entries
967 long nScanWidth = (maOrigSize.Width() - mnXStart + mnXAdd - 1) / mnXAdd;
968 mnScansize = nScanWidth;
969
970 if( mbRGBTriple )
971 mnScansize = 3 * nScanWidth;
972
973 if( mbAlphaChannel )
974 mnScansize += nScanWidth;
975
976 // convert to width in bytes
977 mnScansize = ( mnScansize*mnPngDepth + 7 ) >> 3;
978
979 ++mnScansize; // scan size also needs room for the filtertype byte
980 memset( mpScanPrior.get(), 0, mnScansize );
981
982 return true;
983}
984
985// ImplApplyFilter writes the complete Scanline (nY)
986// in interlace mode the parameter nXStart and nXAdd are non-zero
987
988void PNGReaderImpl::ImplApplyFilter()
989{
990 OSL_ASSERT( mnScansize >= mnBPP + 1 )do { if (true && (!(mnScansize >= mnBPP + 1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "990" ": "), "OSL_ASSERT: %s", "mnScansize >= mnBPP + 1"
); } } while (false)
;
991 const sal_uInt8* const pScanEnd = mpInflateInBuf.get() + mnScansize;
992
993 sal_uInt8 nFilterType = mpInflateInBuf[0]; // the filter type may change each scanline
994 switch ( nFilterType )
995 {
996 default: // unknown Scanline Filter Type
997 case 0: // Filter Type "None"
998 // we let the pixels pass and display the data unfiltered
999 break;
1000
1001 case 1: // Scanline Filter Type "Sub"
1002 {
1003 sal_uInt8* p1 = mpInflateInBuf.get() + 1;
1004 const sal_uInt8* p2 = p1;
1005 p1 += mnBPP;
1006
1007 // use left pixels
1008 while (p1 < pScanEnd)
1009 {
1010 *p1 = static_cast<sal_uInt8>( *p1 + *(p2++) );
1011 ++p1;
1012 }
1013 }
1014 break;
1015
1016 case 2: // Scanline Filter Type "Up"
1017 {
1018 sal_uInt8* p1 = mpInflateInBuf.get() + 1;
1019 const sal_uInt8* p2 = mpScanPrior.get() + 1;
1020
1021 // use pixels from prior line
1022 while( p1 < pScanEnd )
1023 {
1024 *p1 = static_cast<sal_uInt8>( *p1 + *(p2++) );
1025 ++p1;
1026 }
1027 }
1028 break;
1029
1030 case 3: // Scanline Filter Type "Average"
1031 {
1032 sal_uInt8* p1 = mpInflateInBuf.get() + 1;
1033 const sal_uInt8* p2 = mpScanPrior.get() + 1;
1034 const sal_uInt8* p3 = p1;
1035
1036 // use one pixel from prior line
1037 for( int n = mnBPP; --n >= 0; ++p1, ++p2)
1038 *p1 = static_cast<sal_uInt8>( *p1 + (*p2 >> 1) );
1039
1040 // predict by averaging the left and prior line pixels
1041 while( p1 < pScanEnd )
1042 {
1043 *p1 = static_cast<sal_uInt8>( *p1 + ((*(p2++) + *(p3++)) >> 1) );
1044 ++p1;
1045 }
1046 }
1047 break;
1048
1049 case 4: // Scanline Filter Type "PathPredictor"
1050 {
1051 sal_uInt8* p1 = mpInflateInBuf.get() + 1;
1052 const sal_uInt8* p2 = mpScanPrior.get() + 1;
1053 const sal_uInt8* p3 = p1;
1054 const sal_uInt8* p4 = p2;
1055
1056 // use one pixel from prior line
1057 for( int n = mnBPP; --n >= 0; ++p1)
1058 *p1 = static_cast<sal_uInt8>( *p1 + *(p2++) );
1059
1060 // predict by using the left and the prior line pixels
1061 while( p1 < pScanEnd )
1062 {
1063 int na = *(p2++);
1064 int nb = *(p3++);
1065 int nc = *(p4++);
1066
1067 int npa = nb - nc;
1068 int npb = na - nc;
1069 int npc = npa + npb;
1070
1071 if( npa < 0 )
1072 npa =-npa;
1073 if( npb < 0 )
1074 npb =-npb;
1075 if( npc < 0 )
1076 npc =-npc;
1077
1078 if( npa > npb )
1079 {
1080 na = nb;
1081 npa = npb;
1082 }
1083 if( npa > npc )
1084 na = nc;
1085
1086 *p1 = static_cast<sal_uInt8>( *p1 + na );
1087 ++p1;
1088 }
1089 }
1090 break;
1091 }
1092
1093 memcpy( mpScanPrior.get(), mpInflateInBuf.get(), mnScansize );
1094}
1095
1096namespace
1097{
1098 sal_uInt8 SanitizePaletteIndex(sal_uInt8 nIndex, sal_uInt16 nPaletteEntryCount)
1099 {
1100 if (nIndex >= nPaletteEntryCount)
1101 {
1102 auto nSanitizedIndex = nIndex % nPaletteEntryCount;
1103 SAL_WARN_IF(nIndex != nSanitizedIndex, "vcl", "invalid colormap index: "do { if (true && (nIndex != nSanitizedIndex)) { switch
(sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) {
case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "invalid colormap index: " << static_cast<
unsigned int>(nIndex) << ", colormap len is: " <<
nPaletteEntryCount) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "1105" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "invalid colormap index: " << static_cast
<unsigned int>(nIndex) << ", colormap len is: " <<
nPaletteEntryCount), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "invalid colormap index: " <<
static_cast<unsigned int>(nIndex) << ", colormap len is: "
<< nPaletteEntryCount; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "1105" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "invalid colormap index: " << static_cast<
unsigned int>(nIndex) << ", colormap len is: " <<
nPaletteEntryCount) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "1105" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "invalid colormap index: " << static_cast
<unsigned int>(nIndex) << ", colormap len is: " <<
nPaletteEntryCount), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "invalid colormap index: " <<
static_cast<unsigned int>(nIndex) << ", colormap len is: "
<< nPaletteEntryCount; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "1105" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
1104 << static_cast<unsigned int>(nIndex) << ", colormap len is: "do { if (true && (nIndex != nSanitizedIndex)) { switch
(sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) {
case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "invalid colormap index: " << static_cast<
unsigned int>(nIndex) << ", colormap len is: " <<
nPaletteEntryCount) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "1105" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "invalid colormap index: " << static_cast
<unsigned int>(nIndex) << ", colormap len is: " <<
nPaletteEntryCount), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "invalid colormap index: " <<
static_cast<unsigned int>(nIndex) << ", colormap len is: "
<< nPaletteEntryCount; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "1105" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "invalid colormap index: " << static_cast<
unsigned int>(nIndex) << ", colormap len is: " <<
nPaletteEntryCount) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "1105" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "invalid colormap index: " << static_cast
<unsigned int>(nIndex) << ", colormap len is: " <<
nPaletteEntryCount), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "invalid colormap index: " <<
static_cast<unsigned int>(nIndex) << ", colormap len is: "
<< nPaletteEntryCount; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "1105" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
1105 << nPaletteEntryCount)do { if (true && (nIndex != nSanitizedIndex)) { switch
(sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN, "vcl")) {
case SAL_DETAIL_LOG_ACTION_IGNORE: break; case SAL_DETAIL_LOG_ACTION_LOG
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "invalid colormap index: " << static_cast<
unsigned int>(nIndex) << ", colormap len is: " <<
nPaletteEntryCount) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "1105" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "invalid colormap index: " << static_cast
<unsigned int>(nIndex) << ", colormap len is: " <<
nPaletteEntryCount), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "invalid colormap index: " <<
static_cast<unsigned int>(nIndex) << ", colormap len is: "
<< nPaletteEntryCount; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "1105" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "invalid colormap index: " << static_cast<
unsigned int>(nIndex) << ", colormap len is: " <<
nPaletteEntryCount) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "1105" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "invalid colormap index: " << static_cast
<unsigned int>(nIndex) << ", colormap len is: " <<
nPaletteEntryCount), 0); } else { ::std::ostringstream sal_detail_stream
; sal_detail_stream << "invalid colormap index: " <<
static_cast<unsigned int>(nIndex) << ", colormap len is: "
<< nPaletteEntryCount; ::sal::detail::log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "1105" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1106 nIndex = nSanitizedIndex;
1107 }
1108 return nIndex;
1109 }
1110
1111 void SanitizePaletteIndexes(sal_uInt8* pEntries, int nLen, const BitmapScopedWriteAccess& rAcc)
1112 {
1113 sal_uInt16 nPaletteEntryCount = rAcc->GetPaletteEntryCount();
19
Calling 'BitmapInfoAccess::GetPaletteEntryCount'
23
Returning from 'BitmapInfoAccess::GetPaletteEntryCount'
24
'nPaletteEntryCount' initialized to 0
1114 for (int nX = 0; nX < nLen; ++nX)
25
Assuming 'nX' is < 'nLen'
26
Loop condition is true. Entering loop body
1115 {
1116 if (pEntries[nX] >= nPaletteEntryCount)
27
Taking true branch
1117 {
1118 SAL_WARN("vcl.gdi", "invalid colormap index: "do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl.gdi")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "invalid colormap index: "
<< static_cast<unsigned int>(pEntries[nX]) <<
", colormap len is: " << nPaletteEntryCount) == 1) { ::
sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"), (
"/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "1120" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "invalid colormap index: " << static_cast
<unsigned int>(pEntries[nX]) << ", colormap len is: "
<< nPaletteEntryCount), 0); } else { ::std::ostringstream
sal_detail_stream; sal_detail_stream << "invalid colormap index: "
<< static_cast<unsigned int>(pEntries[nX]) <<
", colormap len is: " << nPaletteEntryCount; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "1120" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "invalid colormap index: " << static_cast<
unsigned int>(pEntries[nX]) << ", colormap len is: "
<< nPaletteEntryCount) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "1120" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "invalid colormap index: " << static_cast
<unsigned int>(pEntries[nX]) << ", colormap len is: "
<< nPaletteEntryCount), 0); } else { ::std::ostringstream
sal_detail_stream; sal_detail_stream << "invalid colormap index: "
<< static_cast<unsigned int>(pEntries[nX]) <<
", colormap len is: " << nPaletteEntryCount; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "1120" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
28
Taking true branch
29
'Default' branch taken. Execution continues on line 1118
30
Loop condition is false. Exiting loop
1119 << static_cast<unsigned int>(pEntries[nX]) << ", colormap len is: "do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl.gdi")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "invalid colormap index: "
<< static_cast<unsigned int>(pEntries[nX]) <<
", colormap len is: " << nPaletteEntryCount) == 1) { ::
sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"), (
"/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "1120" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "invalid colormap index: " << static_cast
<unsigned int>(pEntries[nX]) << ", colormap len is: "
<< nPaletteEntryCount), 0); } else { ::std::ostringstream
sal_detail_stream; sal_detail_stream << "invalid colormap index: "
<< static_cast<unsigned int>(pEntries[nX]) <<
", colormap len is: " << nPaletteEntryCount; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "1120" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "invalid colormap index: " << static_cast<
unsigned int>(pEntries[nX]) << ", colormap len is: "
<< nPaletteEntryCount) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "1120" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "invalid colormap index: " << static_cast
<unsigned int>(pEntries[nX]) << ", colormap len is: "
<< nPaletteEntryCount), 0); } else { ::std::ostringstream
sal_detail_stream; sal_detail_stream << "invalid colormap index: "
<< static_cast<unsigned int>(pEntries[nX]) <<
", colormap len is: " << nPaletteEntryCount; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "1120" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
1120 << nPaletteEntryCount)do { if (true) { switch (sal_detail_log_report(::SAL_DETAIL_LOG_LEVEL_WARN
, "vcl.gdi")) { case SAL_DETAIL_LOG_ACTION_IGNORE: break; case
SAL_DETAIL_LOG_ACTION_LOG: if (sizeof ::sal::detail::getResult
( ::sal::detail::StreamStart() << "invalid colormap index: "
<< static_cast<unsigned int>(pEntries[nX]) <<
", colormap len is: " << nPaletteEntryCount) == 1) { ::
sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"), (
"/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "1120" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "invalid colormap index: " << static_cast
<unsigned int>(pEntries[nX]) << ", colormap len is: "
<< nPaletteEntryCount), 0); } else { ::std::ostringstream
sal_detail_stream; sal_detail_stream << "invalid colormap index: "
<< static_cast<unsigned int>(pEntries[nX]) <<
", colormap len is: " << nPaletteEntryCount; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "1120" ": "), sal_detail_stream, 0); }; break; case SAL_DETAIL_LOG_ACTION_FATAL
: if (sizeof ::sal::detail::getResult( ::sal::detail::StreamStart
() << "invalid colormap index: " << static_cast<
unsigned int>(pEntries[nX]) << ", colormap len is: "
<< nPaletteEntryCount) == 1) { ::sal_detail_log( (::SAL_DETAIL_LOG_LEVEL_WARN
), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "1120" ": "), ::sal::detail::unwrapStream( ::sal::detail
::StreamStart() << "invalid colormap index: " << static_cast
<unsigned int>(pEntries[nX]) << ", colormap len is: "
<< nPaletteEntryCount), 0); } else { ::std::ostringstream
sal_detail_stream; sal_detail_stream << "invalid colormap index: "
<< static_cast<unsigned int>(pEntries[nX]) <<
", colormap len is: " << nPaletteEntryCount; ::sal::detail
::log( (::SAL_DETAIL_LOG_LEVEL_WARN), ("vcl.gdi"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "1120" ": "), sal_detail_stream, 0); }; std::abort(); break
; } } } while (false)
;
1121 pEntries[nX] = pEntries[nX] % nPaletteEntryCount;
31
Division by zero
1122 }
1123 }
1124 }
1125}
1126
1127// ImplDrawScanlines draws the complete Scanline (nY) into the target bitmap
1128// In interlace mode the parameter nXStart and nXAdd append to the currently used pass
1129
1130void PNGReaderImpl::ImplDrawScanline( sal_uInt32 nXStart, sal_uInt32 nXAdd )
1131{
1132 // optimization for downscaling
1133 if( mnYpos & mnPreviewMask )
1
Assuming the condition is false
2
Taking false branch
1134 return;
1135 if( nXStart & mnPreviewMask )
3
Assuming the condition is false
4
Taking false branch
1136 return;
1137
1138 // convert nY to pixel units in the target image
1139 // => TODO; also do this for nX here instead of in the ImplSet*Pixel() methods
1140 const sal_uInt32 nY = mnYpos >> mnPreviewShift;
1141
1142 sal_uInt8* pTmp = mpInflateInBuf.get() + 1;
1143 if ( mxAcc->HasPalette() ) // alphachannel is not allowed by pictures including palette entries
5
Taking true branch
1144 {
1145 switch ( mxAcc->GetBitCount() )
6
Control jumps to 'case 8:' at line 1274
1146 {
1147 case 1 :
1148 {
1149 if ( mbTransparent )
1150 {
1151 for ( long nX = nXStart, nShift = 0; nX < maOrigSize.Width(); nX += nXAdd )
1152 {
1153 sal_uInt8 nCol;
1154 nShift = (nShift - 1) & 7;
1155 if ( nShift == 0 )
1156 nCol = *(pTmp++);
1157 else
1158 nCol = static_cast<sal_uInt8>( *pTmp >> nShift );
1159 nCol &= 1;
1160
1161 ImplSetAlphaPixel( nY, nX, nCol, mpTransTab[ nCol ] );
1162 }
1163 }
1164 else
1165 { // ScanlineFormat::N1BitMsbPal
1166 for ( long nX = nXStart, nShift = 0; nX < maOrigSize.Width(); nX += nXAdd )
1167 {
1168 nShift = (nShift - 1) & 7;
1169
1170 sal_uInt8 nCol;
1171 if ( nShift == 0 )
1172 nCol = *(pTmp++);
1173 else
1174 nCol = static_cast<sal_uInt8>( *pTmp >> nShift );
1175 nCol &= 1;
1176
1177 ImplSetPixel( nY, nX, nCol );
1178 }
1179 }
1180 }
1181 break;
1182
1183 case 4 :
1184 {
1185 if ( mbTransparent )
1186 {
1187 if ( mnPngDepth == 4 ) // check if source has a two bit pixel format
1188 {
1189 for ( long nX = nXStart, nXIndex = 0; nX < maOrigSize.Width(); nX += nXAdd, ++nXIndex )
1190 {
1191 if( nXIndex & 1 )
1192 {
1193 ImplSetAlphaPixel( nY, nX, *pTmp & 0x0f, mpTransTab[ *pTmp & 0x0f ] );
1194 pTmp++;
1195 }
1196 else
1197 {
1198 ImplSetAlphaPixel( nY, nX, ( *pTmp >> 4 ) & 0x0f, mpTransTab[ *pTmp >> 4 ] );
1199 }
1200 }
1201 }
1202 else // if ( mnPngDepth == 2 )
1203 {
1204 for ( long nX = nXStart, nXIndex = 0; nX < maOrigSize.Width(); nX += nXAdd, nXIndex++ )
1205 {
1206 sal_uInt8 nCol;
1207 switch( nXIndex & 3 )
1208 {
1209 case 0 :
1210 nCol = *pTmp >> 6;
1211 break;
1212
1213 case 1 :
1214 nCol = ( *pTmp >> 4 ) & 0x03 ;
1215 break;
1216
1217 case 2 :
1218 nCol = ( *pTmp >> 2 ) & 0x03;
1219 break;
1220
1221 case 3 :
1222 nCol = ( *pTmp++ ) & 0x03;
1223 break;
1224
1225 default: // get rid of nCol uninitialized warning
1226 nCol = 0;
1227 break;
1228 }
1229
1230 ImplSetAlphaPixel( nY, nX, nCol, mpTransTab[ nCol ] );
1231 }
1232 }
1233 }
1234 else
1235 {
1236 if ( mnPngDepth == 4 ) // maybe the source is a two bitmap graphic
1237 { // ScanlineFormat::N4BitLsnPal
1238 for ( long nX = nXStart, nXIndex = 0; nX < maOrigSize.Width(); nX += nXAdd, nXIndex++ )
1239 {
1240 if( nXIndex & 1 )
1241 ImplSetPixel( nY, nX, *pTmp++ & 0x0f );
1242 else
1243 ImplSetPixel( nY, nX, ( *pTmp >> 4 ) & 0x0f );
1244 }
1245 }
1246 else // if ( mnPngDepth == 2 )
1247 {
1248 for ( long nX = nXStart, nXIndex = 0; nX < maOrigSize.Width(); nX += nXAdd, nXIndex++ )
1249 {
1250 switch( nXIndex & 3 )
1251 {
1252 case 0 :
1253 ImplSetPixel( nY, nX, *pTmp >> 6 );
1254 break;
1255
1256 case 1 :
1257 ImplSetPixel( nY, nX, ( *pTmp >> 4 ) & 0x03 );
1258 break;
1259
1260 case 2 :
1261 ImplSetPixel( nY, nX, ( *pTmp >> 2 ) & 0x03 );
1262 break;
1263
1264 case 3 :
1265 ImplSetPixel( nY, nX, *pTmp++ & 0x03 );
1266 break;
1267 }
1268 }
1269 }
1270 }
1271 }
1272 break;
1273
1274 case 8 :
1275 {
1276 if ( mbAlphaChannel )
7
Assuming field 'mbAlphaChannel' is false
8
Taking false branch
1277 {
1278 if ( mnPngDepth == 8 ) // maybe the source is a 16 bit grayscale
1279 {
1280 for ( long nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 2 )
1281 ImplSetAlphaPixel( nY, nX, pTmp[ 0 ], pTmp[ 1 ] );
1282 }
1283 else
1284 {
1285 assert(mnPngDepth == 16)(static_cast <bool> (mnPngDepth == 16) ? void (0) : __assert_fail
("mnPngDepth == 16", "/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
, 1285, __extension__ __PRETTY_FUNCTION__))
;
1286 for ( long nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 4 )
1287 ImplSetAlphaPixel( nY, nX, pTmp[ 0 ], pTmp[ 2 ] );
1288 }
1289 }
1290 else if ( mbTransparent )
9
Assuming field 'mbTransparent' is false
10
Taking false branch
1291 {
1292 if ( mnPngDepth == 8 ) // maybe the source is a 16 bit grayscale
1293 {
1294 for ( long nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp++ )
1295 ImplSetAlphaPixel( nY, nX, *pTmp, mpTransTab[ *pTmp ] );
1296 }
1297 else if (mnPngDepth == 1 )
1298 {
1299 for ( long nX = nXStart, nShift = 0; nX < maOrigSize.Width(); nX += nXAdd )
1300 {
1301 nShift = (nShift - 1) & 7;
1302
1303 sal_uInt8 nCol;
1304 if ( nShift == 0 )
1305 nCol = *(pTmp++);
1306 else
1307 nCol = static_cast<sal_uInt8>( *pTmp >> nShift );
1308 nCol &= 1;
1309
1310 ImplSetAlphaPixel( nY, nX, nCol, mpTransTab[ nCol ] );
1311 }
1312 }
1313 else
1314 {
1315 for ( long nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 2 )
1316 ImplSetAlphaPixel( nY, nX, *pTmp, mpTransTab[ *pTmp ] );
1317 }
1318 }
1319 else // neither alpha nor transparency
1320 {
1321 if ( mnPngDepth == 8 ) // maybe the source is a 16 bit grayscale or 1 bit indexed
11
Assuming field 'mnPngDepth' is equal to 8
12
Taking true branch
1322 {
1323 if( nXAdd == 1 && mnPreviewShift == 0 ) // copy raw line data if possible
13
Assuming 'nXAdd' is equal to 1
14
Assuming field 'mnPreviewShift' is equal to 0
15
Taking true branch
1324 {
1325 int nLineBytes = maOrigSize.Width();
1326 if (mbPalette)
16
Assuming field 'mbPalette' is true
17
Taking true branch
1327 SanitizePaletteIndexes(pTmp, nLineBytes, mxAcc);
18
Calling 'SanitizePaletteIndexes'
1328 mxAcc->CopyScanline( nY, pTmp, ScanlineFormat::N8BitPal, nLineBytes );
1329 }
1330 else
1331 {
1332 for ( long nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd )
1333 ImplSetPixel( nY, nX, *pTmp++ );
1334 }
1335 }
1336 else if (mnPngDepth == 1 )
1337 {
1338 for ( long nX = nXStart, nShift = 0; nX < maOrigSize.Width(); nX += nXAdd )
1339 {
1340 nShift = (nShift - 1) & 7;
1341
1342 sal_uInt8 nCol;
1343 if ( nShift == 0 )
1344 nCol = *(pTmp++);
1345 else
1346 nCol = static_cast<sal_uInt8>( *pTmp >> nShift );
1347 nCol &= 1;
1348
1349 ImplSetPixel( nY, nX, nCol );
1350 }
1351 }
1352 else
1353 {
1354 for ( long nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 2 )
1355 ImplSetPixel( nY, nX, *pTmp );
1356 }
1357 }
1358 }
1359 break;
1360
1361 default :
1362 mbStatus = false;
1363 break;
1364 }
1365 }
1366 else // no palette => truecolor
1367 {
1368 if( mbAlphaChannel )
1369 {
1370 // has RGB + alpha
1371 if ( mnPngDepth == 8 ) // maybe the source has 16 bit per sample
1372 {
1373 // ScanlineFormat::N32BitTcRgba
1374 // only use DirectScanline when we have no preview shifting stuff and accesses to content and alpha
1375 const bool bDoDirectScanline(
1376 !nXStart && 1 == nXAdd && !mnPreviewShift && mpMaskAcc);
1377 const bool bCustomColorTable(mpColorTable != mpDefaultColorTable);
1378
1379 if(bDoDirectScanline)
1380 {
1381 // allocate scanlines on demand, reused for next line
1382 if(!mpScanline)
1383 {
1384#if OSL_DEBUG_LEVEL1 > 0
1385 mnAllocSizeScanline = maOrigSize.Width() * 3;
1386#endif
1387 mpScanline.reset( new sal_uInt8[maOrigSize.Width() * 3] );
1388 }
1389
1390 if(!mpScanlineAlpha)
1391 {
1392#if OSL_DEBUG_LEVEL1 > 0
1393 mnAllocSizeScanlineAlpha = maOrigSize.Width();
1394#endif
1395 mpScanlineAlpha.reset( new sal_uInt8[maOrigSize.Width()] );
1396 }
1397 }
1398
1399 if(bDoDirectScanline)
1400 {
1401 OSL_ENSURE(mpScanline, "No Scanline allocated (!)")do { if (true && (!(mpScanline))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "1401" ": "), "%s", "No Scanline allocated (!)"); } } while
(false)
;
1402 OSL_ENSURE(mpScanlineAlpha, "No ScanlineAlpha allocated (!)")do { if (true && (!(mpScanlineAlpha))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "1402" ": "), "%s", "No ScanlineAlpha allocated (!)"); }
} while (false)
;
1403#if OSL_DEBUG_LEVEL1 > 0
1404 OSL_ENSURE(mnAllocSizeScanline >= maOrigSize.Width() * 3, "Allocated Scanline too small (!)")do { if (true && (!(mnAllocSizeScanline >= maOrigSize
.Width() * 3))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "1404" ": "), "%s", "Allocated Scanline too small (!)");
} } while (false)
;
1405 OSL_ENSURE(mnAllocSizeScanlineAlpha >= maOrigSize.Width(), "Allocated ScanlineAlpha too small (!)")do { if (true && (!(mnAllocSizeScanlineAlpha >= maOrigSize
.Width()))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "1405" ": "), "%s", "Allocated ScanlineAlpha too small (!)"
); } } while (false)
;
1406#endif
1407 sal_uInt8* pScanline(mpScanline.get());
1408 sal_uInt8* pScanlineAlpha(mpScanlineAlpha.get());
1409
1410 for (long nX(0); nX < maOrigSize.Width(); nX++, pTmp += 4)
1411 {
1412 // prepare content line as BGR by reordering when copying
1413 // do not forget to invert alpha (source is alpha, target is opacity)
1414 if(bCustomColorTable)
1415 {
1416 *pScanline++ = mpColorTable[pTmp[2]];
1417 *pScanline++ = mpColorTable[pTmp[1]];
1418 *pScanline++ = mpColorTable[pTmp[0]];
1419 *pScanlineAlpha++ = ~pTmp[3];
1420 }
1421 else
1422 {
1423 *pScanline++ = pTmp[2];
1424 *pScanline++ = pTmp[1];
1425 *pScanline++ = pTmp[0];
1426 *pScanlineAlpha++ = ~pTmp[3];
1427 }
1428 }
1429
1430 // copy scanlines directly to bitmaps for content and alpha; use the formats which
1431 // are able to copy directly to BitmapBuffer
1432 mxAcc->CopyScanline(nY, mpScanline.get(), ScanlineFormat::N24BitTcBgr, maOrigSize.Width() * 3);
1433 mpMaskAcc->CopyScanline(nY, mpScanlineAlpha.get(), ScanlineFormat::N8BitPal, maOrigSize.Width());
1434 }
1435 else
1436 {
1437 for ( long nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 4 )
1438 {
1439 if(bCustomColorTable)
1440 {
1441 ImplSetAlphaPixel(
1442 nY,
1443 nX,
1444 BitmapColor(
1445 mpColorTable[ pTmp[ 0 ] ],
1446 mpColorTable[ pTmp[ 1 ] ],
1447 mpColorTable[ pTmp[ 2 ] ]),
1448 pTmp[ 3 ]);
1449 }
1450 else
1451 {
1452 ImplSetAlphaPixel(
1453 nY,
1454 nX,
1455 BitmapColor(
1456 pTmp[0],
1457 pTmp[1],
1458 pTmp[2]),
1459 pTmp[3]);
1460 }
1461 }
1462 }
1463 }
1464 else
1465 {
1466 // BMP_FORMAT_64BIT_TC_RGBA
1467 for ( long nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 8 )
1468 {
1469 ImplSetAlphaPixel(
1470 nY,
1471 nX,
1472 BitmapColor(
1473 mpColorTable[ pTmp[ 0 ] ],
1474 mpColorTable[ pTmp[ 2 ] ],
1475 mpColorTable[ pTmp[ 4 ] ]),
1476 pTmp[6]);
1477 }
1478 }
1479 }
1480 else if( mbTransparent ) // has RGB + transparency
1481 {
1482 // ScanlineFormat::N24BitTcRgb
1483 // no support currently for DirectScanline, found no real usages in current PNGs, may be added on demand
1484 if ( mnPngDepth == 8 ) // maybe the source has 16 bit per sample
1485 {
1486 for ( long nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 3 )
1487 {
1488 sal_uInt8 nRed = pTmp[ 0 ];
1489 sal_uInt8 nGreen = pTmp[ 1 ];
1490 sal_uInt8 nBlue = pTmp[ 2 ];
1491 bool bTransparent = ( ( nRed == mnTransRed )
1492 && ( nGreen == mnTransGreen )
1493 && ( nBlue == mnTransBlue ) );
1494
1495 ImplSetTranspPixel( nY, nX, BitmapColor( mpColorTable[ nRed ],
1496 mpColorTable[ nGreen ],
1497 mpColorTable[ nBlue ] ), bTransparent );
1498 }
1499 }
1500 else
1501 {
1502 // BMP_FORMAT_48BIT_TC_RGB
1503 for ( long nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 6 )
1504 {
1505 sal_uInt8 nRed = pTmp[ 0 ];
1506 sal_uInt8 nGreen = pTmp[ 2 ];
1507 sal_uInt8 nBlue = pTmp[ 4 ];
1508 bool bTransparent = ( ( nRed == mnTransRed )
1509 && ( nGreen == mnTransGreen )
1510 && ( nBlue == mnTransBlue ) );
1511
1512 ImplSetTranspPixel( nY, nX, BitmapColor( mpColorTable[ nRed ],
1513 mpColorTable[ nGreen ],
1514 mpColorTable[ nBlue ] ), bTransparent );
1515 }
1516 }
1517 }
1518 else // has RGB but neither alpha nor transparency
1519 {
1520 // ScanlineFormat::N24BitTcRgb
1521 // only use DirectScanline when we have no preview shifting stuff and access to content
1522 const bool bDoDirectScanline(
1523 !nXStart && 1 == nXAdd && !mnPreviewShift);
1524 const bool bCustomColorTable(mpColorTable != mpDefaultColorTable);
1525
1526 if(bDoDirectScanline && !mpScanline)
1527 {
1528 // allocate scanlines on demand, reused for next line
1529#if OSL_DEBUG_LEVEL1 > 0
1530 mnAllocSizeScanline = maOrigSize.Width() * 3;
1531#endif
1532 mpScanline.reset( new sal_uInt8[maOrigSize.Width() * 3] );
1533 }
1534
1535 if ( mnPngDepth == 8 ) // maybe the source has 16 bit per sample
1536 {
1537 if(bDoDirectScanline)
1538 {
1539 OSL_ENSURE(mpScanline, "No Scanline allocated (!)")do { if (true && (!(mpScanline))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "1539" ": "), "%s", "No Scanline allocated (!)"); } } while
(false)
;
1540#if OSL_DEBUG_LEVEL1 > 0
1541 OSL_ENSURE(mnAllocSizeScanline >= maOrigSize.Width() * 3, "Allocated Scanline too small (!)")do { if (true && (!(mnAllocSizeScanline >= maOrigSize
.Width() * 3))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx"
":" "1541" ": "), "%s", "Allocated Scanline too small (!)");
} } while (false)
;
1542#endif
1543 sal_uInt8* pScanline(mpScanline.get());
1544
1545 for (long nX(0); nX < maOrigSize.Width(); nX++, pTmp += 3)
1546 {
1547 // prepare content line as BGR by reordering when copying
1548 if(bCustomColorTable)
1549 {
1550 *pScanline++ = mpColorTable[pTmp[2]];
1551 *pScanline++ = mpColorTable[pTmp[1]];
1552 *pScanline++ = mpColorTable[pTmp[0]];
1553 }
1554 else
1555 {
1556 *pScanline++ = pTmp[2];
1557 *pScanline++ = pTmp[1];
1558 *pScanline++ = pTmp[0];
1559 }
1560 }
1561
1562 // copy scanline directly to bitmap for content; use the format which is able to
1563 // copy directly to BitmapBuffer
1564 mxAcc->CopyScanline(nY, mpScanline.get(), ScanlineFormat::N24BitTcBgr, maOrigSize.Width() * 3);
1565 }
1566 else
1567 {
1568 for ( long nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 3 )
1569 {
1570 if(bCustomColorTable)
1571 {
1572 ImplSetPixel(
1573 nY,
1574 nX,
1575 BitmapColor(
1576 mpColorTable[ pTmp[ 0 ] ],
1577 mpColorTable[ pTmp[ 1 ] ],
1578 mpColorTable[ pTmp[ 2 ] ]));
1579 }
1580 else
1581 {
1582 ImplSetPixel(
1583 nY,
1584 nX,
1585 BitmapColor(
1586 pTmp[0],
1587 pTmp[1],
1588 pTmp[2]));
1589 }
1590 }
1591 }
1592 }
1593 else
1594 {
1595 // BMP_FORMAT_48BIT_TC_RGB
1596 // no support currently for DirectScanline, found no real usages in current PNGs, may be added on demand
1597 for ( long nX = nXStart; nX < maOrigSize.Width(); nX += nXAdd, pTmp += 6 )
1598 {
1599 ImplSetPixel(
1600 nY,
1601 nX,
1602 BitmapColor(
1603 mpColorTable[ pTmp[ 0 ] ],
1604 mpColorTable[ pTmp[ 2 ] ],
1605 mpColorTable[ pTmp[ 4 ] ]));
1606 }
1607 }
1608 }
1609 }
1610}
1611
1612void PNGReaderImpl::ImplSetPixel( sal_uInt32 nY, sal_uInt32 nX, const BitmapColor& rBitmapColor )
1613{
1614 // TODO: get preview mode checks out of inner loop
1615 if( nX & mnPreviewMask )
1616 return;
1617 nX >>= mnPreviewShift;
1618
1619 mxAcc->SetPixel( nY, nX, rBitmapColor );
1620}
1621
1622void PNGReaderImpl::ImplSetPixel( sal_uInt32 nY, sal_uInt32 nX, sal_uInt8 nPalIndex )
1623{
1624 // TODO: get preview mode checks out of inner loop
1625 if( nX & mnPreviewMask )
1626 return;
1627 nX >>= mnPreviewShift;
1628
1629 mxAcc->SetPixelIndex(nY, nX, SanitizePaletteIndex(nPalIndex, mxAcc->GetPaletteEntryCount()));
1630}
1631
1632void PNGReaderImpl::ImplSetTranspPixel( sal_uInt32 nY, sal_uInt32 nX, const BitmapColor& rBitmapColor, bool bTrans )
1633{
1634 // TODO: get preview mode checks out of inner loop
1635 if( nX & mnPreviewMask )
1636 return;
1637 nX >>= mnPreviewShift;
1638
1639 mxAcc->SetPixel( nY, nX, rBitmapColor );
1640
1641 if ( bTrans )
1642 mpMaskAcc->SetPixel( nY, nX, mcTranspColor );
1643 else
1644 mpMaskAcc->SetPixel( nY, nX, mcOpaqueColor );
1645}
1646
1647void PNGReaderImpl::ImplSetAlphaPixel( sal_uInt32 nY, sal_uInt32 nX,
1648 sal_uInt8 nPalIndex, sal_uInt8 nAlpha )
1649{
1650 // TODO: get preview mode checks out of inner loop
1651 if( nX & mnPreviewMask )
1652 return;
1653 nX >>= mnPreviewShift;
1654
1655 mxAcc->SetPixelIndex(nY, nX, SanitizePaletteIndex(nPalIndex, mxAcc->GetPaletteEntryCount()));
1656 mpMaskAcc->SetPixel(nY, nX, BitmapColor(~nAlpha));
1657}
1658
1659void PNGReaderImpl::ImplSetAlphaPixel( sal_uInt32 nY, sal_uInt32 nX,
1660 const BitmapColor& rBitmapColor, sal_uInt8 nAlpha )
1661{
1662 // TODO: get preview mode checks out of inner loop
1663 if( nX & mnPreviewMask )
1664 return;
1665 nX >>= mnPreviewShift;
1666
1667 mxAcc->SetPixel( nY, nX, rBitmapColor );
1668 if (!mpMaskAcc)
1669 return;
1670 mpMaskAcc->SetPixel(nY, nX, BitmapColor(~nAlpha));
1671}
1672
1673sal_uInt32 PNGReaderImpl::ImplReadsal_uInt32()
1674{
1675 sal_uInt32 nRet;
1676 nRet = *maDataIter++;
1677 nRet <<= 8;
1678 nRet |= *maDataIter++;
1679 nRet <<= 8;
1680 nRet |= *maDataIter++;
1681 nRet <<= 8;
1682 nRet |= *maDataIter++;
1683 return nRet;
1684}
1685
1686PNGReader::PNGReader(SvStream& rIStream) :
1687 mpImpl(new vcl::PNGReaderImpl(rIStream))
1688{
1689}
1690
1691PNGReader::~PNGReader()
1692{
1693}
1694
1695BitmapEx PNGReader::Read()
1696{
1697 return mpImpl->GetBitmapEx();
1698}
1699
1700const std::vector< vcl::PNGReader::ChunkData >& PNGReader::GetChunks() const
1701{
1702 return mpImpl->GetAllChunks();
1703}
1704
1705} // namespace vcl
1706
1707/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/vcl/bitmapaccess.hxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#ifndef INCLUDED_VCL_BMPACC_HXX
21#define INCLUDED_VCL_BMPACC_HXX
22
23#include <vcl/dllapi.h>
24#include <vcl/bitmap.hxx>
25#include <vcl/Scanline.hxx>
26#include <vcl/BitmapBuffer.hxx>
27#include <vcl/BitmapColor.hxx>
28#include <vcl/BitmapAccessMode.hxx>
29
30typedef BitmapColor (*FncGetPixel)(ConstScanline pScanline, long nX, const ColorMask& rMask);
31typedef void (*FncSetPixel)(Scanline pScanline, long nX, const BitmapColor& rBitmapColor, const ColorMask& rMask);
32
33class VCL_DLLPUBLIC__attribute__ ((visibility("default"))) BitmapInfoAccess
34{
35 friend class BitmapReadAccess;
36
37public:
38 BitmapInfoAccess(Bitmap& rBitmap, BitmapAccessMode nMode = BitmapAccessMode::Info);
39 virtual ~BitmapInfoAccess();
40
41 bool operator!() const
42 {
43 return mpBuffer == nullptr;
44 }
45
46 long Width() const
47 {
48 return mpBuffer ? mpBuffer->mnWidth : 0L;
49 }
50
51 long Height() const
52 {
53 return mpBuffer ? mpBuffer->mnHeight : 0L;
54 }
55
56 bool IsTopDown() const
57 {
58 assert(mpBuffer && "Access is not valid!")(static_cast <bool> (mpBuffer && "Access is not valid!"
) ? void (0) : __assert_fail ("mpBuffer && \"Access is not valid!\""
, "/home/maarten/src/libreoffice/core/include/vcl/bitmapaccess.hxx"
, 58, __extension__ __PRETTY_FUNCTION__))
;
59
60 return mpBuffer && (mpBuffer->mnFormat & ScanlineFormat::TopDown);
61 }
62
63 bool IsBottomUp() const
64 {
65 return !IsTopDown();
66 }
67
68 ScanlineFormat GetScanlineFormat() const
69 {
70 assert(mpBuffer && "Access is not valid!")(static_cast <bool> (mpBuffer && "Access is not valid!"
) ? void (0) : __assert_fail ("mpBuffer && \"Access is not valid!\""
, "/home/maarten/src/libreoffice/core/include/vcl/bitmapaccess.hxx"
, 70, __extension__ __PRETTY_FUNCTION__))
;
71
72 return mpBuffer ? RemoveScanline(mpBuffer->mnFormat) : ScanlineFormat::NONE;
73 }
74
75 sal_uInt32 GetScanlineSize() const
76 {
77 assert(mpBuffer && "Access is not valid!")(static_cast <bool> (mpBuffer && "Access is not valid!"
) ? void (0) : __assert_fail ("mpBuffer && \"Access is not valid!\""
, "/home/maarten/src/libreoffice/core/include/vcl/bitmapaccess.hxx"
, 77, __extension__ __PRETTY_FUNCTION__))
;
78
79 return mpBuffer ? mpBuffer->mnScanlineSize : 0;
80 }
81
82 sal_uInt16 GetBitCount() const
83 {
84 assert(mpBuffer && "Access is not valid!")(static_cast <bool> (mpBuffer && "Access is not valid!"
) ? void (0) : __assert_fail ("mpBuffer && \"Access is not valid!\""
, "/home/maarten/src/libreoffice/core/include/vcl/bitmapaccess.hxx"
, 84, __extension__ __PRETTY_FUNCTION__))
;
85
86 return mpBuffer ? mpBuffer->mnBitCount : 0;
87 }
88
89 BitmapColor GetBestMatchingColor(const BitmapColor& rBitmapColor)
90 {
91 if (HasPalette())
92 return BitmapColor(static_cast<sal_uInt8>(GetBestPaletteIndex(rBitmapColor)));
93 else
94 return rBitmapColor;
95 }
96
97 bool HasPalette() const
98 {
99 assert(mpBuffer && "Access is not valid!")(static_cast <bool> (mpBuffer && "Access is not valid!"
) ? void (0) : __assert_fail ("mpBuffer && \"Access is not valid!\""
, "/home/maarten/src/libreoffice/core/include/vcl/bitmapaccess.hxx"
, 99, __extension__ __PRETTY_FUNCTION__))
;
100
101 return mpBuffer && !!mpBuffer->maPalette;
102 }
103
104 const BitmapPalette& GetPalette() const
105 {
106 assert(mpBuffer && "Access is not valid!")(static_cast <bool> (mpBuffer && "Access is not valid!"
) ? void (0) : __assert_fail ("mpBuffer && \"Access is not valid!\""
, "/home/maarten/src/libreoffice/core/include/vcl/bitmapaccess.hxx"
, 106, __extension__ __PRETTY_FUNCTION__))
;
107
108 return mpBuffer->maPalette;
109 }
110
111 sal_uInt16 GetPaletteEntryCount() const
112 {
113 assert(HasPalette() && "Bitmap has no palette!")(static_cast <bool> (HasPalette() && "Bitmap has no palette!"
) ? void (0) : __assert_fail ("HasPalette() && \"Bitmap has no palette!\""
, "/home/maarten/src/libreoffice/core/include/vcl/bitmapaccess.hxx"
, 113, __extension__ __PRETTY_FUNCTION__))
;
20
'?' condition is true
114
115 return HasPalette() ? mpBuffer->maPalette.GetEntryCount() : 0;
21
'?' condition is false
22
Returning zero
116 }
117
118 const BitmapColor& GetPaletteColor( sal_uInt16 nColor ) const
119 {
120 assert(mpBuffer && "Access is not valid!")(static_cast <bool> (mpBuffer && "Access is not valid!"
) ? void (0) : __assert_fail ("mpBuffer && \"Access is not valid!\""
, "/home/maarten/src/libreoffice/core/include/vcl/bitmapaccess.hxx"
, 120, __extension__ __PRETTY_FUNCTION__))
;
121 assert(HasPalette() && "Bitmap has no palette!")(static_cast <bool> (HasPalette() && "Bitmap has no palette!"
) ? void (0) : __assert_fail ("HasPalette() && \"Bitmap has no palette!\""
, "/home/maarten/src/libreoffice/core/include/vcl/bitmapaccess.hxx"
, 121, __extension__ __PRETTY_FUNCTION__))
;
122
123 return mpBuffer->maPalette[nColor];
124 }
125
126 const BitmapColor& GetBestPaletteColor(const BitmapColor& rBitmapColor) const
127 {
128 return GetPaletteColor(GetBestPaletteIndex(rBitmapColor));
129 }
130
131 sal_uInt16 GetBestPaletteIndex(const BitmapColor& rBitmapColor) const;
132
133 ColorMask& GetColorMask() const
134 {
135 assert(mpBuffer && "Access is not valid!")(static_cast <bool> (mpBuffer && "Access is not valid!"
) ? void (0) : __assert_fail ("mpBuffer && \"Access is not valid!\""
, "/home/maarten/src/libreoffice/core/include/vcl/bitmapaccess.hxx"
, 135, __extension__ __PRETTY_FUNCTION__))
;
136
137 return mpBuffer->maColorMask;
138 }
139
140private:
141 BitmapInfoAccess(const BitmapInfoAccess&) = delete;
142 BitmapInfoAccess& operator=(const BitmapInfoAccess&) = delete;
143
144protected:
145 Bitmap maBitmap;
146 BitmapBuffer* mpBuffer;
147 ColorMask maColorMask;
148 BitmapAccessMode mnAccessMode;
149};
150
151
152class VCL_DLLPUBLIC__attribute__ ((visibility("default"))) BitmapReadAccess : public BitmapInfoAccess
153{
154 friend class BitmapWriteAccess;
155
156public:
157 BitmapReadAccess(Bitmap& rBitmap, BitmapAccessMode nMode = BitmapAccessMode::Read);
158 virtual ~BitmapReadAccess() override;
159
160 Scanline GetBuffer() const
161 {
162 assert(mpBuffer && "Access is not valid!")(static_cast <bool> (mpBuffer && "Access is not valid!"
) ? void (0) : __assert_fail ("mpBuffer && \"Access is not valid!\""
, "/home/maarten/src/libreoffice/core/include/vcl/bitmapaccess.hxx"
, 162, __extension__ __PRETTY_FUNCTION__))
;
163
164 return mpBuffer ? mpBuffer->mpBits : nullptr;
165 }
166
167 Scanline GetScanline(long nY) const
168 {
169 assert(mpBuffer && "Access is not valid!")(static_cast <bool> (mpBuffer && "Access is not valid!"
) ? void (0) : __assert_fail ("mpBuffer && \"Access is not valid!\""
, "/home/maarten/src/libreoffice/core/include/vcl/bitmapaccess.hxx"
, 169, __extension__ __PRETTY_FUNCTION__))
;
170 assert(nY < mpBuffer->mnHeight && "y-coordinate out of range!")(static_cast <bool> (nY < mpBuffer->mnHeight &&
"y-coordinate out of range!") ? void (0) : __assert_fail ("nY < mpBuffer->mnHeight && \"y-coordinate out of range!\""
, "/home/maarten/src/libreoffice/core/include/vcl/bitmapaccess.hxx"
, 170, __extension__ __PRETTY_FUNCTION__))
;
171
172 if (mpBuffer->mnFormat & ScanlineFormat::TopDown)
173 {
174 return mpBuffer->mpBits + (nY * mpBuffer->mnScanlineSize);
175 }
176 return mpBuffer->mpBits + ((mpBuffer->mnHeight - 1 - nY) * mpBuffer->mnScanlineSize);
177 }
178
179 BitmapColor GetPixelFromData(const sal_uInt8* pData, long nX) const
180 {
181 assert(pData && "Access is not valid!")(static_cast <bool> (pData && "Access is not valid!"
) ? void (0) : __assert_fail ("pData && \"Access is not valid!\""
, "/home/maarten/src/libreoffice/core/include/vcl/bitmapaccess.hxx"
, 181, __extension__ __PRETTY_FUNCTION__))
;
182
183 return mFncGetPixel( pData, nX, maColorMask );
184 }
185
186 sal_uInt8 GetIndexFromData(const sal_uInt8* pData, long nX) const
187 {
188 return GetPixelFromData( pData, nX ).GetIndex();
189 }
190
191 void SetPixelOnData(sal_uInt8* pData, long nX, const BitmapColor& rBitmapColor)
192 {
193 assert(pData && "Access is not valid!")(static_cast <bool> (pData && "Access is not valid!"
) ? void (0) : __assert_fail ("pData && \"Access is not valid!\""
, "/home/maarten/src/libreoffice/core/include/vcl/bitmapaccess.hxx"
, 193, __extension__ __PRETTY_FUNCTION__))
;
194
195 mFncSetPixel(pData, nX, rBitmapColor, maColorMask);
196 }
197
198 BitmapColor GetPixel(long nY, long nX) const
199 {
200 assert(mpBuffer && "Access is not valid!")(static_cast <bool> (mpBuffer && "Access is not valid!"
) ? void (0) : __assert_fail ("mpBuffer && \"Access is not valid!\""
, "/home/maarten/src/libreoffice/core/include/vcl/bitmapaccess.hxx"
, 200, __extension__ __PRETTY_FUNCTION__))
;
201 assert(nX < mpBuffer->mnWidth && "x-coordinate out of range!")(static_cast <bool> (nX < mpBuffer->mnWidth &&
"x-coordinate out of range!") ? void (0) : __assert_fail ("nX < mpBuffer->mnWidth && \"x-coordinate out of range!\""
, "/home/maarten/src/libreoffice/core/include/vcl/bitmapaccess.hxx"
, 201, __extension__ __PRETTY_FUNCTION__))
;
202 assert(nY < mpBuffer->mnHeight && "y-coordinate out of range!")(static_cast <bool> (nY < mpBuffer->mnHeight &&
"y-coordinate out of range!") ? void (0) : __assert_fail ("nY < mpBuffer->mnHeight && \"y-coordinate out of range!\""
, "/home/maarten/src/libreoffice/core/include/vcl/bitmapaccess.hxx"
, 202, __extension__ __PRETTY_FUNCTION__))
;
203
204 return mFncGetPixel(GetScanline(nY), nX, maColorMask );
205 }
206
207 BitmapColor GetColor(long nY, long nX) const
208 {
209 if (HasPalette())
210 return mpBuffer->maPalette[GetPixelIndex(nY, nX)];
211 else
212 return GetPixel(nY, nX);
213 }
214
215 sal_uInt8 GetPixelIndex(long nY, long nX) const
216 {
217 return GetPixel(nY, nX).GetIndex();
218 }
219
220 /** Get the interpolated color at coordinates fY, fX; if outside, return rFallback */
221 BitmapColor GetInterpolatedColorWithFallback( double fY, double fX, const BitmapColor& rFallback ) const;
222
223 /** Get the color at coordinates fY, fX; if outside, return rFallback. Automatically does the correct
224 inside/outside checks, e.g. static_cast< sal_uInt32 >(-0.25) *is* 0, not -1 and has to be outside */
225 BitmapColor GetColorWithFallback( double fY, double fX, const BitmapColor& rFallback ) const;
226
227private:
228 BitmapReadAccess(const BitmapReadAccess&) = delete;
229 BitmapReadAccess& operator=(const BitmapReadAccess&) = delete;
230
231protected:
232 FncGetPixel mFncGetPixel;
233 FncSetPixel mFncSetPixel;
234
235public:
236
237 SAL_DLLPRIVATE__attribute__ ((visibility("hidden"))) BitmapBuffer* ImplGetBitmapBuffer() const
238 {
239 return mpBuffer;
240 }
241
242 static BitmapColor GetPixelForN1BitMsbPal(ConstScanline pScanline, long nX, const ColorMask& rMask);
243 static BitmapColor GetPixelForN1BitLsbPal(ConstScanline pScanline, long nX, const ColorMask& rMask);
244 static BitmapColor GetPixelForN4BitMsnPal(ConstScanline pScanline, long nX, const ColorMask& rMask);
245 static BitmapColor GetPixelForN4BitLsnPal(ConstScanline pScanline, long nX, const ColorMask& rMask);
246 static BitmapColor GetPixelForN8BitPal(ConstScanline pScanline, long nX, const ColorMask& rMask);
247 static BitmapColor GetPixelForN8BitTcMask(ConstScanline pScanline, long nX, const ColorMask& rMask);
248 static BitmapColor GetPixelForN24BitTcBgr(ConstScanline pScanline, long nX, const ColorMask& rMask);
249 static BitmapColor GetPixelForN24BitTcRgb(ConstScanline pScanline, long nX, const ColorMask& rMask);
250 static BitmapColor GetPixelForN32BitTcAbgr(ConstScanline pScanline, long nX, const ColorMask& rMask);
251 static BitmapColor GetPixelForN32BitTcXbgr(ConstScanline pScanline, long nX, const ColorMask& rMask);
252 static BitmapColor GetPixelForN32BitTcArgb(ConstScanline pScanline, long nX, const ColorMask& rMask);
253 static BitmapColor GetPixelForN32BitTcXrgb(ConstScanline pScanline, long nX, const ColorMask& rMask);
254 static BitmapColor GetPixelForN32BitTcBgra(ConstScanline pScanline, long nX, const ColorMask& rMask);
255 static BitmapColor GetPixelForN32BitTcBgrx(ConstScanline pScanline, long nX, const ColorMask& rMask);
256 static BitmapColor GetPixelForN32BitTcRgba(ConstScanline pScanline, long nX, const ColorMask& rMask);
257 static BitmapColor GetPixelForN32BitTcRgbx(ConstScanline pScanline, long nX, const ColorMask& rMask);
258 static BitmapColor GetPixelForN32BitTcMask(ConstScanline pScanline, long nX, const ColorMask& rMask);
259
260 static void SetPixelForN1BitMsbPal(Scanline pScanline, long nX, const BitmapColor& rBitmapColor, const ColorMask& rMask);
261 static void SetPixelForN1BitLsbPal(Scanline pScanline, long nX, const BitmapColor& rBitmapColor, const ColorMask& rMask);
262 static void SetPixelForN4BitMsnPal(Scanline pScanline, long nX, const BitmapColor& rBitmapColor, const ColorMask& rMask);
263 static void SetPixelForN4BitLsnPal(Scanline pScanline, long nX, const BitmapColor& rBitmapColor, const ColorMask& rMask);
264 static void SetPixelForN8BitPal(Scanline pScanline, long nX, const BitmapColor& rBitmapColor, const ColorMask& rMask);
265 static void SetPixelForN8BitTcMask(Scanline pScanline, long nX, const BitmapColor& rBitmapColor, const ColorMask& rMask);
266 static void SetPixelForN24BitTcBgr(Scanline pScanline, long nX, const BitmapColor& rBitmapColor, const ColorMask& rMask);
267 static void SetPixelForN24BitTcRgb(Scanline pScanline, long nX, const BitmapColor& rBitmapColor, const ColorMask& rMask);
268 static void SetPixelForN32BitTcAbgr(Scanline pScanline, long nX, const BitmapColor& rBitmapColor, const ColorMask& rMask);
269 static void SetPixelForN32BitTcXbgr(Scanline pScanline, long nX, const BitmapColor& rBitmapColor, const ColorMask& rMask);
270 static void SetPixelForN32BitTcArgb(Scanline pScanline, long nX, const BitmapColor& rBitmapColor, const ColorMask& rMask);
271 static void SetPixelForN32BitTcXrgb(Scanline pScanline, long nX, const BitmapColor& rBitmapColor, const ColorMask& rMask);
272 static void SetPixelForN32BitTcBgra(Scanline pScanline, long nX, const BitmapColor& rBitmapColor, const ColorMask& rMask);
273 static void SetPixelForN32BitTcBgrx(Scanline pScanline, long nX, const BitmapColor& rBitmapColor, const ColorMask& rMask);
274 static void SetPixelForN32BitTcRgba(Scanline pScanline, long nX, const BitmapColor& rBitmapColor, const ColorMask& rMask);
275 static void SetPixelForN32BitTcRgbx(Scanline pScanline, long nX, const BitmapColor& rBitmapColor, const ColorMask& rMask);
276 static void SetPixelForN32BitTcMask(Scanline pScanline, long nX, const BitmapColor& rBitmapColor, const ColorMask& rMask);
277
278 static FncGetPixel GetPixelFunction( ScanlineFormat nFormat );
279 static FncSetPixel SetPixelFunction( ScanlineFormat nFormat );
280};
281
282
283#endif // INCLUDED_VCL_BMPACC_HXX
284
285/* vim:set shiftwidth=4 softtabstop=4 expandtab: */