LibreOffice Module vcl (master)  1
ipcd.cxx
Go to the documentation of this file.
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 
21 #include <vcl/graph.hxx>
22 #include <vcl/BitmapTools.hxx>
23 #include <vcl/FilterConfigItem.hxx>
24 #include <tools/stream.hxx>
25 #include <filter/PcdReader.hxx>
26 
27 //============================ PCDReader ==================================
28 
29 namespace {
30 
31 // these resolutions are contained in a PCD file:
33  PCDRES_BASE16, // 192 x 128
34  PCDRES_BASE4, // 384 x 256
35  PCDRES_BASE, // 768 x 512
36  // the following ones are compressed
37  // and CANNOT be read by us
38  PCDRES_4BASE, // 1536 x 1024
39  PCDRES_16BASE // 3072 x 3072
40 };
41 
42 class PCDReader {
43 
44 private:
45 
46  bool bStatus;
47 
48  SvStream &m_rPCD;
49  std::unique_ptr<vcl::bitmap::RawBitmap> mpBitmap;
50 
51  sal_uInt8 nOrientation; // orientation of the picture within the PCD file:
52  // 0 - spire point up
53  // 1 - spire points to the right
54  // 2 - spire points down
55  // 3 - spire points to the left
56 
57  PCDResolution eResolution; // which resolution we want
58 
59  sal_uInt32 nWidth; // width of the PCD picture
60  sal_uInt32 nHeight; // height of the PCD picture
61  sal_uInt32 nImagePos; // position of the picture within the PCD file
62 
63  // temporary lLue-Green-Red-Bitmap
64  sal_uInt32 nBMPWidth;
65  sal_uInt32 nBMPHeight;
66 
67  void CheckPCDImagePacFile();
68  // checks whether it's a Photo-CD file with 'Image Pac'
69 
70  void ReadOrientation();
71  // reads the orientation and sets nOrientation
72 
73  void ReadImage();
74 
75 public:
76 
77  explicit PCDReader(SvStream &rStream)
78  : bStatus(false)
79  , m_rPCD(rStream)
80  , nOrientation(0)
81  , eResolution(PCDRES_BASE16)
82  , nWidth(0)
83  , nHeight(0)
84  , nImagePos(0)
85  , nBMPWidth(0)
86  , nBMPHeight(0)
87  {
88  }
89 
90  bool ReadPCD( Graphic & rGraphic, FilterConfigItem* pConfigItem );
91 };
92 
93 }
94 
95 //=================== Methods of PCDReader ==============================
96 
97 bool PCDReader::ReadPCD( Graphic & rGraphic, FilterConfigItem* pConfigItem )
98 {
99  bStatus = true;
100 
101  // is it a PCD file with a picture? ( sets bStatus == sal_False, if that's not the case):
102  CheckPCDImagePacFile();
103 
104  // read orientation of the picture:
105  ReadOrientation();
106 
107  // which resolution do we want?:
108  eResolution = PCDRES_BASE;
109  if ( pConfigItem )
110  {
111  sal_Int32 nResolution = pConfigItem->ReadInt32( "Resolution", 2 );
112  if ( nResolution == 1 )
113  eResolution = PCDRES_BASE4;
114  else if ( nResolution == 0 )
115  eResolution = PCDRES_BASE16;
116  }
117  // determine size and position (position within the PCD file) of the picture:
118  switch (eResolution)
119  {
120  case PCDRES_BASE16 :
121  nWidth = 192;
122  nHeight = 128;
123  nImagePos = 8192;
124  break;
125 
126  case PCDRES_BASE4 :
127  nWidth = 384;
128  nHeight = 256;
129  nImagePos = 47104;
130  break;
131 
132  case PCDRES_BASE :
133  nWidth = 768;
134  nHeight = 512;
135  nImagePos = 196608;
136  break;
137 
138  default:
139  bStatus = false;
140  }
141  if ( bStatus )
142  {
143  if ( ( nOrientation & 0x01 ) == 0 )
144  {
145  nBMPWidth = nWidth;
146  nBMPHeight = nHeight;
147  }
148  else
149  {
150  nBMPWidth = nHeight;
151  nBMPHeight = nWidth;
152  }
153  mpBitmap.reset(new vcl::bitmap::RawBitmap( Size( nBMPWidth, nBMPHeight ), 24 ));
154 
155  ReadImage();
156 
157  rGraphic = vcl::bitmap::CreateFromData(std::move(*mpBitmap));
158  }
159  return bStatus;
160 }
161 
162 
163 void PCDReader::CheckPCDImagePacFile()
164 {
165  char Buf[ 8 ];
166 
167  m_rPCD.Seek( 2048 );
168  m_rPCD.ReadBytes(Buf, 7);
169  Buf[ 7 ] = 0;
170  if (OString(Buf) != "PCD_IPI")
171  bStatus = false;
172 }
173 
174 
175 void PCDReader::ReadOrientation()
176 {
177  if ( !bStatus )
178  return;
179  m_rPCD.Seek( 194635 );
180  m_rPCD.ReadUChar( nOrientation );
181  nOrientation &= 0x03;
182 }
183 
184 
185 void PCDReader::ReadImage()
186 {
187  sal_uInt32 nx,ny,nW2,nH2,nYPair,ndy,nXPair;
188  tools::Long nL,nCb,nCr,nRed,nGreen,nBlue;
189  sal_uInt8 * pt;
190  sal_uInt8 * pL0; // luminance for each pixel of the 1st row of the current pair of rows
191  sal_uInt8 * pL1; // luminance for each pixel of the 2nd row of the current pair of rows
192  sal_uInt8 * pCb; // blue chrominance for each 2x2 pixel of the current pair of rows
193  sal_uInt8 * pCr; // red chrominance for each 2x2 pixel of the current pair of rows
194  sal_uInt8 * pL0N, * pL1N, * pCbN, * pCrN; // like above, but for the next pair of rows
195 
196  if ( !bStatus )
197  return;
198 
199  nW2=nWidth>>1;
200  nH2=nHeight>>1;
201 
202  pL0 =static_cast<sal_uInt8*>(std::malloc( nWidth ));
203  pL1 =static_cast<sal_uInt8*>(std::malloc( nWidth ));
204  pCb =static_cast<sal_uInt8*>(std::malloc( nW2+1 ));
205  pCr =static_cast<sal_uInt8*>(std::malloc( nW2+1 ));
206  pL0N=static_cast<sal_uInt8*>(std::malloc( nWidth ));
207  pL1N=static_cast<sal_uInt8*>(std::malloc( nWidth ));
208  pCbN=static_cast<sal_uInt8*>(std::malloc( nW2+1 ));
209  pCrN=static_cast<sal_uInt8*>(std::malloc( nW2+1 ));
210 
211  if ( pL0 == nullptr || pL1 == nullptr || pCb == nullptr || pCr == nullptr ||
212  pL0N == nullptr || pL1N == nullptr || pCbN == nullptr || pCrN == nullptr)
213  {
214  std::free(static_cast<void*>(pL0) );
215  std::free(static_cast<void*>(pL1) );
216  std::free(static_cast<void*>(pCb) );
217  std::free(static_cast<void*>(pCr) );
218  std::free(static_cast<void*>(pL0N));
219  std::free(static_cast<void*>(pL1N));
220  std::free(static_cast<void*>(pCbN));
221  std::free(static_cast<void*>(pCrN));
222  bStatus = false;
223  return;
224  }
225 
226  m_rPCD.Seek( nImagePos );
227 
228  // next pair of rows := first pair of rows:
229  m_rPCD.ReadBytes( pL0N, nWidth );
230  m_rPCD.ReadBytes( pL1N, nWidth );
231  m_rPCD.ReadBytes( pCbN, nW2 );
232  m_rPCD.ReadBytes( pCrN, nW2 );
233  pCbN[ nW2 ] = pCbN[ nW2 - 1 ];
234  pCrN[ nW2 ] = pCrN[ nW2 - 1 ];
235 
236  for ( nYPair = 0; nYPair < nH2; nYPair++ )
237  {
238  // current pair of rows := next pair of rows:
239  pt=pL0; pL0=pL0N; pL0N=pt;
240  pt=pL1; pL1=pL1N; pL1N=pt;
241  pt=pCb; pCb=pCbN; pCbN=pt;
242  pt=pCr; pCr=pCrN; pCrN=pt;
243 
244  // get the next pair of rows:
245  if ( nYPair < nH2 - 1 )
246  {
247  m_rPCD.ReadBytes( pL0N, nWidth );
248  m_rPCD.ReadBytes( pL1N, nWidth );
249  m_rPCD.ReadBytes( pCbN, nW2 );
250  m_rPCD.ReadBytes( pCrN, nW2 );
251  pCbN[nW2]=pCbN[ nW2 - 1 ];
252  pCrN[nW2]=pCrN[ nW2 - 1 ];
253  }
254  else
255  {
256  for ( nXPair = 0; nXPair < nW2; nXPair++ )
257  {
258  pCbN[ nXPair ] = pCb[ nXPair ];
259  pCrN[ nXPair ] = pCr[ nXPair ];
260  }
261  }
262 
263  // loop through both rows of the pair of rows:
264  for ( ndy = 0; ndy < 2; ndy++ )
265  {
266  ny = ( nYPair << 1 ) + ndy;
267 
268  // loop through X:
269  for ( nx = 0; nx < nWidth; nx++ )
270  {
271  // get/calculate nL,nCb,nCr for the pixel nx,ny:
272  nXPair = nx >> 1;
273  if ( ndy == 0 )
274  {
275  nL = static_cast<tools::Long>(pL0[ nx ]);
276  if (( nx & 1 ) == 0 )
277  {
278  nCb = static_cast<tools::Long>(pCb[ nXPair ]);
279  nCr = static_cast<tools::Long>(pCr[ nXPair ]);
280  }
281  else
282  {
283  nCb = ( static_cast<tools::Long>(pCb[ nXPair ]) + static_cast<tools::Long>(pCb[ nXPair + 1 ]) ) >> 1;
284  nCr = ( static_cast<tools::Long>(pCr[ nXPair ]) + static_cast<tools::Long>(pCr[ nXPair + 1 ]) ) >> 1;
285  }
286  }
287  else {
288  nL = pL1[ nx ];
289  if ( ( nx & 1 ) == 0 )
290  {
291  nCb = ( static_cast<tools::Long>(pCb[ nXPair ]) + static_cast<tools::Long>(pCbN[ nXPair ]) ) >> 1;
292  nCr = ( static_cast<tools::Long>(pCr[ nXPair ]) + static_cast<tools::Long>(pCrN[ nXPair ]) ) >> 1;
293  }
294  else
295  {
296  nCb = ( static_cast<tools::Long>(pCb[ nXPair ]) + static_cast<tools::Long>(pCb[ nXPair + 1 ]) +
297  static_cast<tools::Long>(pCbN[ nXPair ]) + static_cast<tools::Long>(pCbN[ nXPair + 1 ]) ) >> 2;
298  nCr = ( static_cast<tools::Long>(pCr[ nXPair ]) + static_cast<tools::Long>(pCr[ nXPair + 1]) +
299  static_cast<tools::Long>(pCrN[ nXPair ]) + static_cast<tools::Long>(pCrN[ nXPair + 1 ]) ) >> 2;
300  }
301  }
302  // conversion of nL,nCb,nCr in nRed,nGreen,nBlue:
303  nL *= 89024;
304  nCb -= 156;
305  nCr -= 137;
306  nRed = ( nL + nCr * 119374 + 0x8000 ) >> 16;
307  if ( nRed < 0 )
308  nRed = 0;
309  if ( nRed > 255)
310  nRed = 255;
311  nGreen = ( nL - nCb * 28198 - nCr * 60761 + 0x8000 ) >> 16;
312  if ( nGreen < 0 )
313  nGreen = 0;
314  if ( nGreen > 255 )
315  nGreen = 255;
316  nBlue = ( nL + nCb * 145352 + 0x8000 ) >> 16;
317  if ( nBlue < 0 )
318  nBlue = 0;
319  if ( nBlue > 255 )
320  nBlue = 255;
321 
322  // register color value in pBMPMap:
323  if ( nOrientation < 2 )
324  {
325  if ( nOrientation == 0 )
326  mpBitmap->SetPixel( ny, nx, Color( static_cast<sal_uInt8>(nRed), static_cast<sal_uInt8>(nGreen), static_cast<sal_uInt8>(nBlue) ) );
327  else
328  mpBitmap->SetPixel( nWidth - 1 - nx, ny, Color( static_cast<sal_uInt8>(nRed), static_cast<sal_uInt8>(nGreen), static_cast<sal_uInt8>(nBlue) ) );
329  }
330  else
331  {
332  if ( nOrientation == 2 )
333  mpBitmap->SetPixel( nHeight - 1 - ny, ( nWidth - 1 - nx ), Color( static_cast<sal_uInt8>(nRed), static_cast<sal_uInt8>(nGreen), static_cast<sal_uInt8>(nBlue) ) );
334  else
335  mpBitmap->SetPixel( nx, ( nHeight - 1 - ny ), Color( static_cast<sal_uInt8>(nRed), static_cast<sal_uInt8>(nGreen), static_cast<sal_uInt8>(nBlue) ) );
336  }
337  }
338  }
339 
340  if ( m_rPCD.GetError() )
341  bStatus = false;
342  if ( !bStatus )
343  break;
344  }
345  std::free(static_cast<void*>(pL0) );
346  std::free(static_cast<void*>(pL1) );
347  std::free(static_cast<void*>(pCb) );
348  std::free(static_cast<void*>(pCr) );
349  std::free(static_cast<void*>(pL0N));
350  std::free(static_cast<void*>(pL1N));
351  std::free(static_cast<void*>(pCbN));
352  std::free(static_cast<void*>(pCrN));
353 }
354 
355 //================== GraphicImport - the exported Function ================
356 
357 bool ImportPcdGraphic(SvStream & rStream, Graphic & rGraphic, FilterConfigItem* pConfigItem)
358 {
359  PCDReader aPCDReader(rStream);
360  return aPCDReader.ReadPCD(rGraphic, pConfigItem);
361 }
362 
363 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
double ny
long Long
bool ImportPcdGraphic(SvStream &rStream, Graphic &rGraphic, FilterConfigItem *pConfigItem)
Definition: ipcd.cxx:357
BitmapEx CreateFromData(sal_uInt8 const *pData, sal_Int32 nWidth, sal_Int32 nHeight, sal_Int32 nStride, vcl::PixelFormat ePixelFormat)
Copy block of image data into the bitmap.
FPDF_BITMAP mpBitmap
PCDResolution
Definition: ipcd.cxx:32
sal_Int32 ReadInt32(const OUString &rKey, sal_Int32 nDefault)
Intended to be used to feed into CreateFromData to create a BitmapEx.
Definition: RawBitmap.hxx:21
double nx
unsigned char sal_uInt8