File: | home/maarten/src/libreoffice/core/vcl/source/filter/png/pngread.cxx |
Warning: | line 1102, column 43 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
| ||||
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: */ |