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>
27#include <tools/stream.hxx>
28#include <filter/PcdReader.hxx>
29
30//============================ PCDReader ==================================
31
32namespace {
33
34// these resolutions are contained in a PCD file:
35enum PCDResolution {
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
45class PCDReader {
46
47private:
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
78public:
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
100bool 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
165void 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
176void PCDReader::ReadOrientation()
177{
178 if ( !bStatus )
179 return;
180 m_rPCD.Seek( 194635 );
181 m_rPCD.ReadUChar( nOrientation );
182 nOrientation &= 0x03;
183}
184
185void 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
346bool 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: */
FPDF_BITMAP mpBitmap
double ny
double nx
sal_Int32 ReadInt32(const OUString &rKey, sal_Int32 nDefault)
Intended to be used to feed into CreateFromData to create a BitmapEx.
Definition: RawBitmap.hxx:22
bool ImportPcdGraphic(SvStream &rStream, Graphic &rGraphic, FilterConfigItem *pConfigItem)
Definition: ipcd.cxx:346
long Long
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.
unsigned char sal_uInt8