File: | home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx |
Warning: | line 1121, column 45 Division by zero |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | ||||
38 | namespace 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 | ||||
54 | const 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 | ||||
73 | class PNGReaderImpl | |||
74 | { | |||
75 | private: | |||
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 | ||||
169 | public: | |||
170 | ||||
171 | explicit PNGReaderImpl( SvStream& ); | |||
172 | ~PNGReaderImpl(); | |||
173 | ||||
174 | BitmapEx GetBitmapEx(); | |||
175 | const std::vector<vcl::PNGReader::ChunkData>& GetAllChunks(); | |||
176 | }; | |||
177 | ||||
178 | PNGReaderImpl::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 | ||||
241 | PNGReaderImpl::~PNGReaderImpl() | |||
242 | { | |||
243 | mrPNGStream.SetEndian( mnOrigStreamMode ); | |||
244 | ||||
245 | if ( mbzCodecInUse ) | |||
246 | mpZCodec.EndCompression(); | |||
247 | ||||
248 | if( mpColorTable != mpDefaultColorTable ) | |||
249 | delete[] mpColorTable; | |||
250 | } | |||
251 | ||||
252 | bool 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 | ||||
318 | const std::vector< vcl::PNGReader::ChunkData >& PNGReaderImpl::GetAllChunks() | |||
319 | { | |||
320 | // read the remaining chunks from mrPNGStream | |||
321 | while( ReadNextChunk() ) ; | |||
322 | return maChunkSeq; | |||
323 | } | |||
324 | ||||
325 | BitmapEx 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 | ||||
442 | bool 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 | ||||
648 | void 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 | ||||
667 | bool 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 | ||||
690 | bool 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 | ||||
769 | void 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 | ||||
791 | void 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 | |||
842 | sal_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 | ||||
857 | void 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 | ||||
923 | bool 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 | ||||
988 | void 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 | ||||
1096 | namespace | |||
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(); | |||
1114 | for (int nX = 0; nX < nLen; ++nX) | |||
1115 | { | |||
1116 | if (pEntries[nX] >= nPaletteEntryCount) | |||
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) | |||
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; | |||
| ||||
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 | ||||
1130 | void PNGReaderImpl::ImplDrawScanline( sal_uInt32 nXStart, sal_uInt32 nXAdd ) | |||
1131 | { | |||
1132 | // optimization for downscaling | |||
1133 | if( mnYpos & mnPreviewMask ) | |||
| ||||
1134 | return; | |||
1135 | if( nXStart & mnPreviewMask ) | |||
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 | |||
1144 | { | |||
1145 | switch ( mxAcc->GetBitCount() ) | |||
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 ) | |||
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 ) | |||
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 | |||
1322 | { | |||
1323 | if( nXAdd == 1 && mnPreviewShift == 0 ) // copy raw line data if possible | |||
1324 | { | |||
1325 | int nLineBytes = maOrigSize.Width(); | |||
1326 | if (mbPalette) | |||
1327 | SanitizePaletteIndexes(pTmp, nLineBytes, mxAcc); | |||
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 | ||||
1612 | void 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 | ||||
1622 | void 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 | ||||
1632 | void 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 | ||||
1647 | void 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 | ||||
1659 | void 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 | ||||
1673 | sal_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 | ||||
1686 | PNGReader::PNGReader(SvStream& rIStream) : | |||
1687 | mpImpl(new vcl::PNGReaderImpl(rIStream)) | |||
1688 | { | |||
1689 | } | |||
1690 | ||||
1691 | PNGReader::~PNGReader() | |||
1692 | { | |||
1693 | } | |||
1694 | ||||
1695 | BitmapEx PNGReader::Read() | |||
1696 | { | |||
1697 | return mpImpl->GetBitmapEx(); | |||
1698 | } | |||
1699 | ||||
1700 | const 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: */ |
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 | |
30 | typedef BitmapColor (*FncGetPixel)(ConstScanline pScanline, long nX, const ColorMask& rMask); |
31 | typedef void (*FncSetPixel)(Scanline pScanline, long nX, const BitmapColor& rBitmapColor, const ColorMask& rMask); |
32 | |
33 | class VCL_DLLPUBLIC__attribute__ ((visibility("default"))) BitmapInfoAccess |
34 | { |
35 | friend class BitmapReadAccess; |
36 | |
37 | public: |
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__)); |
114 | |
115 | return HasPalette() ? mpBuffer->maPalette.GetEntryCount() : 0; |
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 | |
140 | private: |
141 | BitmapInfoAccess(const BitmapInfoAccess&) = delete; |
142 | BitmapInfoAccess& operator=(const BitmapInfoAccess&) = delete; |
143 | |
144 | protected: |
145 | Bitmap maBitmap; |
146 | BitmapBuffer* mpBuffer; |
147 | ColorMask maColorMask; |
148 | BitmapAccessMode mnAccessMode; |
149 | }; |
150 | |
151 | |
152 | class VCL_DLLPUBLIC__attribute__ ((visibility("default"))) BitmapReadAccess : public BitmapInfoAccess |
153 | { |
154 | friend class BitmapWriteAccess; |
155 | |
156 | public: |
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 | |
227 | private: |
228 | BitmapReadAccess(const BitmapReadAccess&) = delete; |
229 | BitmapReadAccess& operator=(const BitmapReadAccess&) = delete; |
230 | |
231 | protected: |
232 | FncGetPixel mFncGetPixel; |
233 | FncSetPixel mFncSetPixel; |
234 | |
235 | public: |
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: */ |