Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / filter / source / graphicfilter / ipcd / ipcd.cxx
blobf76ba225def7edd4975e8311917fc7a46c29b57c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <rtl/alloc.h>
22 #include <vcl/graph.hxx>
23 #include <vcl/BitmapTools.hxx>
24 #include <vcl/svapp.hxx>
25 #include <vcl/fltcall.hxx>
26 #include <svl/solar.hrc>
27 #include <vcl/FilterConfigItem.hxx>
28 #include <tools/stream.hxx>
30 //============================ PCDReader ==================================
32 // these resolutions are contained in a PCD file:
33 enum PCDResolution {
34 PCDRES_BASE16, // 192 x 128
35 PCDRES_BASE4, // 384 x 256
36 PCDRES_BASE, // 768 x 512
37 // the following ones are compressed
38 // and CANNOT be read by us
39 PCDRES_4BASE, // 1536 x 1024
40 PCDRES_16BASE // 3072 x 3072
43 class PCDReader {
45 private:
47 bool bStatus;
49 SvStream &m_rPCD;
50 std::unique_ptr<vcl::bitmap::RawBitmap> mpBitmap;
52 sal_uInt8 nOrientation; // orientation of the picture within the PCD file:
53 // 0 - spire point up
54 // 1 - spire points to the right
55 // 2 - spire points down
56 // 3 - spire points to the left
58 PCDResolution eResolution; // which resolution we want
60 sal_uLong nWidth; // width of the PCD picture
61 sal_uLong nHeight; // height of the PCD picture
62 sal_uLong nImagePos; // position of the picture within the PCD file
64 // temporary lLue-Green-Red-Bitmap
65 sal_uLong nBMPWidth;
66 sal_uLong nBMPHeight;
68 void CheckPCDImagePacFile();
69 // checks whether it's a Photo-CD file with 'Image Pac'
71 void ReadOrientation();
72 // reads the orientation and sets nOrientation
74 void ReadImage();
76 public:
78 explicit PCDReader(SvStream &rStream)
79 : bStatus(false)
80 , m_rPCD(rStream)
81 , nOrientation(0)
82 , eResolution(PCDRES_BASE16)
83 , nWidth(0)
84 , nHeight(0)
85 , nImagePos(0)
86 , nBMPWidth(0)
87 , nBMPHeight(0)
91 bool ReadPCD( Graphic & rGraphic, FilterConfigItem* pConfigItem );
94 //=================== Methods of PCDReader ==============================
96 bool PCDReader::ReadPCD( Graphic & rGraphic, FilterConfigItem* pConfigItem )
98 bStatus = true;
100 // is it a PCD file with a picture? ( sets bStatus == sal_False, if that's not the case):
101 CheckPCDImagePacFile();
103 // read orientation of the picture:
104 ReadOrientation();
106 // which resolution do we want?:
107 eResolution = PCDRES_BASE;
108 if ( pConfigItem )
110 sal_Int32 nResolution = pConfigItem->ReadInt32( "Resolution", 2 );
111 if ( nResolution == 1 )
112 eResolution = PCDRES_BASE4;
113 else if ( nResolution == 0 )
114 eResolution = PCDRES_BASE16;
116 // determine size and position (position within the PCD file) of the picture:
117 switch (eResolution)
119 case PCDRES_BASE16 :
120 nWidth = 192;
121 nHeight = 128;
122 nImagePos = 8192;
123 break;
125 case PCDRES_BASE4 :
126 nWidth = 384;
127 nHeight = 256;
128 nImagePos = 47104;
129 break;
131 case PCDRES_BASE :
132 nWidth = 768;
133 nHeight = 512;
134 nImagePos = 196608;
135 break;
137 default:
138 bStatus = false;
140 if ( bStatus )
142 if ( ( nOrientation & 0x01 ) == 0 )
144 nBMPWidth = nWidth;
145 nBMPHeight = nHeight;
147 else
149 nBMPWidth = nHeight;
150 nBMPHeight = nWidth;
152 mpBitmap.reset(new vcl::bitmap::RawBitmap( Size( nBMPWidth, nBMPHeight ), 24 ));
154 ReadImage();
156 rGraphic = vcl::bitmap::CreateFromData(std::move(*mpBitmap));
158 return bStatus;
162 void PCDReader::CheckPCDImagePacFile()
164 char Buf[ 8 ];
166 m_rPCD.Seek( 2048 );
167 m_rPCD.ReadBytes(Buf, 7);
168 Buf[ 7 ] = 0;
169 if (OString(Buf) != "PCD_IPI")
170 bStatus = false;
174 void PCDReader::ReadOrientation()
176 if ( !bStatus )
177 return;
178 m_rPCD.Seek( 194635 );
179 m_rPCD.ReadUChar( nOrientation );
180 nOrientation &= 0x03;
184 void PCDReader::ReadImage()
186 sal_uLong nx,ny,nW2,nH2,nYPair,ndy,nXPair;
187 long nL,nCb,nCr,nRed,nGreen,nBlue;
188 sal_uInt8 * pt;
189 sal_uInt8 * pL0; // luminance for each pixel of the 1st row of the current pair of rows
190 sal_uInt8 * pL1; // luminance for each pixel of the 2nd row of the current pair of rows
191 sal_uInt8 * pCb; // blue chrominance for each 2x2 pixel of the current pair of rows
192 sal_uInt8 * pCr; // red chrominance for each 2x2 pixel of the current pair of rows
193 sal_uInt8 * pL0N, * pL1N, * pCbN, * pCrN; // like above, but for the next pair of rows
195 if ( !bStatus )
196 return;
198 nW2=nWidth>>1;
199 nH2=nHeight>>1;
201 pL0 =static_cast<sal_uInt8*>(std::malloc( nWidth ));
202 pL1 =static_cast<sal_uInt8*>(std::malloc( nWidth ));
203 pCb =static_cast<sal_uInt8*>(std::malloc( nW2+1 ));
204 pCr =static_cast<sal_uInt8*>(std::malloc( nW2+1 ));
205 pL0N=static_cast<sal_uInt8*>(std::malloc( nWidth ));
206 pL1N=static_cast<sal_uInt8*>(std::malloc( nWidth ));
207 pCbN=static_cast<sal_uInt8*>(std::malloc( nW2+1 ));
208 pCrN=static_cast<sal_uInt8*>(std::malloc( nW2+1 ));
210 if ( pL0 == nullptr || pL1 == nullptr || pCb == nullptr || pCr == nullptr ||
211 pL0N == nullptr || pL1N == nullptr || pCbN == nullptr || pCrN == nullptr)
213 std::free(static_cast<void*>(pL0) );
214 std::free(static_cast<void*>(pL1) );
215 std::free(static_cast<void*>(pCb) );
216 std::free(static_cast<void*>(pCr) );
217 std::free(static_cast<void*>(pL0N));
218 std::free(static_cast<void*>(pL1N));
219 std::free(static_cast<void*>(pCbN));
220 std::free(static_cast<void*>(pCrN));
221 bStatus = false;
222 return;
225 m_rPCD.Seek( nImagePos );
227 // next pair of rows := first pair of rows:
228 m_rPCD.ReadBytes( pL0N, nWidth );
229 m_rPCD.ReadBytes( pL1N, nWidth );
230 m_rPCD.ReadBytes( pCbN, nW2 );
231 m_rPCD.ReadBytes( pCrN, nW2 );
232 pCbN[ nW2 ] = pCbN[ nW2 - 1 ];
233 pCrN[ nW2 ] = pCrN[ nW2 - 1 ];
235 for ( nYPair = 0; nYPair < nH2; nYPair++ )
237 // current pair of rows := next pair of rows:
238 pt=pL0; pL0=pL0N; pL0N=pt;
239 pt=pL1; pL1=pL1N; pL1N=pt;
240 pt=pCb; pCb=pCbN; pCbN=pt;
241 pt=pCr; pCr=pCrN; pCrN=pt;
243 // get the next pair of rows:
244 if ( nYPair < nH2 - 1 )
246 m_rPCD.ReadBytes( pL0N, nWidth );
247 m_rPCD.ReadBytes( pL1N, nWidth );
248 m_rPCD.ReadBytes( pCbN, nW2 );
249 m_rPCD.ReadBytes( pCrN, nW2 );
250 pCbN[nW2]=pCbN[ nW2 - 1 ];
251 pCrN[nW2]=pCrN[ nW2 - 1 ];
253 else
255 for ( nXPair = 0; nXPair < nW2; nXPair++ )
257 pCbN[ nXPair ] = pCb[ nXPair ];
258 pCrN[ nXPair ] = pCr[ nXPair ];
262 // loop through both rows of the pair of rows:
263 for ( ndy = 0; ndy < 2; ndy++ )
265 ny = ( nYPair << 1 ) + ndy;
267 // loop through X:
268 for ( nx = 0; nx < nWidth; nx++ )
270 // get/calculate nL,nCb,nCr for the pixel nx,ny:
271 nXPair = nx >> 1;
272 if ( ndy == 0 )
274 nL = static_cast<long>(pL0[ nx ]);
275 if (( nx & 1 ) == 0 )
277 nCb = static_cast<long>(pCb[ nXPair ]);
278 nCr = static_cast<long>(pCr[ nXPair ]);
280 else
282 nCb = ( static_cast<long>(pCb[ nXPair ]) + static_cast<long>(pCb[ nXPair + 1 ]) ) >> 1;
283 nCr = ( static_cast<long>(pCr[ nXPair ]) + static_cast<long>(pCr[ nXPair + 1 ]) ) >> 1;
286 else {
287 nL = pL1[ nx ];
288 if ( ( nx & 1 ) == 0 )
290 nCb = ( static_cast<long>(pCb[ nXPair ]) + static_cast<long>(pCbN[ nXPair ]) ) >> 1;
291 nCr = ( static_cast<long>(pCr[ nXPair ]) + static_cast<long>(pCrN[ nXPair ]) ) >> 1;
293 else
295 nCb = ( static_cast<long>(pCb[ nXPair ]) + static_cast<long>(pCb[ nXPair + 1 ]) +
296 static_cast<long>(pCbN[ nXPair ]) + static_cast<long>(pCbN[ nXPair + 1 ]) ) >> 2;
297 nCr = ( static_cast<long>(pCr[ nXPair ]) + static_cast<long>(pCr[ nXPair + 1]) +
298 static_cast<long>(pCrN[ nXPair ]) + static_cast<long>(pCrN[ nXPair + 1 ]) ) >> 2;
301 // conversion of nL,nCb,nCr in nRed,nGreen,nBlue:
302 nL *= 89024;
303 nCb -= 156;
304 nCr -= 137;
305 nRed = ( nL + nCr * 119374 + 0x8000 ) >> 16;
306 if ( nRed < 0 )
307 nRed = 0;
308 if ( nRed > 255)
309 nRed = 255;
310 nGreen = ( nL - nCb * 28198 - nCr * 60761 + 0x8000 ) >> 16;
311 if ( nGreen < 0 )
312 nGreen = 0;
313 if ( nGreen > 255 )
314 nGreen = 255;
315 nBlue = ( nL + nCb * 145352 + 0x8000 ) >> 16;
316 if ( nBlue < 0 )
317 nBlue = 0;
318 if ( nBlue > 255 )
319 nBlue = 255;
321 // register color value in pBMPMap:
322 if ( nOrientation < 2 )
324 if ( nOrientation == 0 )
325 mpBitmap->SetPixel( ny, nx, Color( static_cast<sal_uInt8>(nRed), static_cast<sal_uInt8>(nGreen), static_cast<sal_uInt8>(nBlue) ) );
326 else
327 mpBitmap->SetPixel( nWidth - 1 - nx, ny, Color( static_cast<sal_uInt8>(nRed), static_cast<sal_uInt8>(nGreen), static_cast<sal_uInt8>(nBlue) ) );
329 else
331 if ( nOrientation == 2 )
332 mpBitmap->SetPixel( nHeight - 1 - ny, ( nWidth - 1 - nx ), Color( static_cast<sal_uInt8>(nRed), static_cast<sal_uInt8>(nGreen), static_cast<sal_uInt8>(nBlue) ) );
333 else
334 mpBitmap->SetPixel( nx, ( nHeight - 1 - ny ), Color( static_cast<sal_uInt8>(nRed), static_cast<sal_uInt8>(nGreen), static_cast<sal_uInt8>(nBlue) ) );
339 if ( m_rPCD.GetError() )
340 bStatus = false;
341 if ( !bStatus )
342 break;
344 std::free(static_cast<void*>(pL0) );
345 std::free(static_cast<void*>(pL1) );
346 std::free(static_cast<void*>(pCb) );
347 std::free(static_cast<void*>(pCr) );
348 std::free(static_cast<void*>(pL0N));
349 std::free(static_cast<void*>(pL1N));
350 std::free(static_cast<void*>(pCbN));
351 std::free(static_cast<void*>(pCrN));
354 //================== GraphicImport - the exported Function ================
356 extern "C" SAL_DLLPUBLIC_EXPORT bool
357 icdGraphicImport( SvStream & rStream, Graphic & rGraphic, FilterConfigItem* pConfigItem )
359 PCDReader aPCDReader(rStream);
360 return aPCDReader.ReadPCD(rGraphic, pConfigItem);
363 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */