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