build fix: no comphelper/profilezone.hxx in this branch
[LibreOffice.git] / vcl / source / filter / sgfbram.cxx
blob468c18cf52dc389cd79380ca6caf12d17dd24126
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 .
20 #include <string.h>
21 #include <osl/endian.h>
22 #include <tools/stream.hxx>
23 #include <tools/fract.hxx>
24 #include <vcl/gdimtf.hxx>
25 #include <tools/color.hxx>
26 #include <vcl/virdev.hxx>
27 #include "sgffilt.hxx"
28 #include "sgfbram.hxx"
29 #include <memory>
31 SgfHeader::SgfHeader()
33 memset( this, 0, sizeof( SgfHeader ) );
36 SvStream& ReadSgfHeader(SvStream& rIStream, SgfHeader& rHead)
38 #if !defined NDEBUG
39 sal_uInt64 const nOldPos(rIStream.Tell());
40 #endif
41 rIStream.ReadUInt16(rHead.Magic);
42 rIStream.ReadUInt16(rHead.Version);
43 rIStream.ReadUInt16(rHead.Typ);
44 rIStream.ReadUInt16(rHead.Xsize);
45 rIStream.ReadUInt16(rHead.Ysize);
46 rIStream.ReadInt16(rHead.Xoffs);
47 rIStream.ReadInt16(rHead.Yoffs);
48 rIStream.ReadUInt16(rHead.Planes);
49 rIStream.ReadUInt16(rHead.SwGrCol);
50 rIStream.ReadBytes(&rHead.Autor, 10);
51 rIStream.ReadBytes(&rHead.Programm, 10);
52 rIStream.ReadUInt16(rHead.OfsLo);
53 rIStream.ReadUInt16(rHead.OfsHi);
54 assert(rIStream.GetError() || rIStream.Tell() == nOldPos + SgfHeaderSize);
55 return rIStream;
58 bool SgfHeader::ChkMagic()
59 { return Magic=='J'*256+'J'; }
61 sal_uInt32 SgfHeader::GetOffset()
62 { return sal_uInt32(OfsLo)+0x00010000*sal_uInt32(OfsHi); }
64 SgfEntry::SgfEntry()
66 memset( this, 0, sizeof( SgfEntry ) );
69 SvStream& ReadSgfEntry(SvStream& rIStream, SgfEntry& rEntr)
71 #if !defined NDEBUG
72 sal_uInt64 const nOldPos(rIStream.Tell());
73 #endif
74 rIStream.ReadUInt16(rEntr.Typ);
75 rIStream.ReadUInt16(rEntr.iFrei);
76 rIStream.ReadUInt16(rEntr.lFreiLo);
77 rIStream.ReadUInt16(rEntr.lFreiHi);
78 rIStream.ReadBytes(&rEntr.cFrei, 10);
79 rIStream.ReadUInt16(rEntr.OfsLo);
80 rIStream.ReadUInt16(rEntr.OfsHi);
81 assert(rIStream.GetError() || rIStream.Tell() == nOldPos + SgfEntrySize);
82 return rIStream;
85 sal_uInt32 SgfEntry::GetOffset()
86 { return sal_uInt32(OfsLo)+0x00010000*sal_uInt32(OfsHi); }
88 SvStream& ReadSgfVector(SvStream& rIStream, SgfVector& rVect)
90 #if !defined NDEBUG
91 sal_uInt64 const nOldPos(rIStream.Tell());
92 #endif
93 rIStream.ReadUInt16(rVect.Flag);
94 rIStream.ReadInt16(rVect.x);
95 rIStream.ReadInt16(rVect.y);
96 rIStream.ReadUInt16(rVect.OfsLo);
97 rIStream.ReadUInt16(rVect.OfsHi);
98 assert(rIStream.GetError() || rIStream.Tell() == nOldPos + SgfVectorSize);
99 return rIStream;
102 SvStream& WriteBmpFileHeader(SvStream& rOStream, BmpFileHeader& rHead)
104 #if !defined NDEBUG
105 sal_uInt64 const nOldPos(rOStream.Tell());
106 #endif
107 rOStream.WriteUInt16(rHead.Typ);
108 rOStream.WriteUInt16(rHead.SizeLo);
109 rOStream.WriteUInt16(rHead.SizeHi);
110 rOStream.WriteUInt16(rHead.Reserve1);
111 rOStream.WriteUInt16(rHead.Reserve2);
112 rOStream.WriteUInt16(rHead.OfsLo);
113 rOStream.WriteUInt16(rHead.OfsHi);
114 assert(rOStream.GetError() || rOStream.Tell() == nOldPos + BmpFileHeaderSize);
115 return rOStream;
118 void BmpFileHeader::SetSize(sal_uInt32 Size)
120 SizeLo=sal_uInt16(Size & 0x0000FFFF);
121 SizeHi=sal_uInt16((Size & 0xFFFF0000)>>16);
124 void BmpFileHeader::SetOfs(sal_uInt32 Ofs)
126 OfsLo=sal_uInt16(Ofs & 0x0000FFFF);
127 OfsHi=sal_uInt16((Ofs & 0xFFFF0000)>>16);
130 sal_uInt32 BmpFileHeader::GetOfs()
132 return sal_uInt32(OfsLo)+0x00010000*sal_uInt32(OfsHi);
135 SvStream& WriteBmpInfoHeader(SvStream& rOStream, BmpInfoHeader& rInfo)
137 #if !defined NDEBUG
138 sal_uInt64 const nOldPos(rOStream.Tell());
139 #endif
140 rOStream.WriteUInt32(rInfo.Size);
141 rOStream.WriteInt32(rInfo.Width);
142 rOStream.WriteInt32(rInfo.Hight);
143 rOStream.WriteUInt16(rInfo.Planes);
144 rOStream.WriteUInt16(rInfo.PixBits);
145 rOStream.WriteUInt32(rInfo.Compress);
146 rOStream.WriteUInt32(rInfo.ImgSize);
147 rOStream.WriteInt32(rInfo.xDpmm);
148 rOStream.WriteInt32(rInfo.yDpmm);
149 rOStream.WriteUInt32(rInfo.ColUsed);
150 rOStream.WriteUInt32(rInfo.ColMust);
151 assert(rOStream.GetError() || rOStream.Tell() == nOldPos + BmpInfoHeaderSize);
152 return rOStream;
155 SvStream& WriteRGBQuad(SvStream& rOStream, const RGBQuad& rQuad)
157 rOStream.WriteBytes(&rQuad, sizeof(rQuad));
158 return rOStream;
161 class PcxExpand
163 private:
164 sal_uInt16 Count;
165 sal_uInt8 Data;
166 public:
167 PcxExpand()
168 : Count(0)
169 , Data(0)
171 sal_uInt8 GetByte(SvStream& rInp);
174 sal_uInt8 PcxExpand::GetByte(SvStream& rInp)
176 if (Count>0) {
177 Count--;
178 } else {
179 rInp.ReadBytes(&Data, 1);
180 if ((Data & 0xC0) == 0xC0) {
181 Count=(Data & 0x3F) -1;
182 rInp.ReadBytes(&Data, 1);
185 return Data;
188 bool SgfFilterBMap(SvStream& rInp, SvStream& rOut, SgfHeader& rHead, SgfEntry&)
190 BmpFileHeader aBmpHead;
191 BmpInfoHeader aBmpInfo;
192 sal_uInt16 nWdtInp=(rHead.Xsize+7)/8; // width of input bitmap in bytes
193 sal_uInt16 nWdtOut; // width of output bitmap in bytes
194 sal_uInt16 nColors; // color count (1, 16, 256)
195 sal_uInt16 nColBits; // number of bits per pixel (2, 4, 8)
196 sal_uInt16 i,j,k; // column/row/plane counter
197 sal_uInt16 a,b; // helper variables
198 sal_uInt8 pl1 = 0; // masks for the planes
199 std::unique_ptr<sal_uInt8[]> pBuf; // buffer for a pixel row
200 PcxExpand aPcx;
201 sal_uLong nOfs;
202 sal_uInt8 cRGB[4];
204 if (rHead.Planes<=1) nColBits=1; else nColBits=4; if (rHead.Typ==4) nColBits=8;
205 nColors=1<<nColBits;
206 nWdtOut=((rHead.Xsize*nColBits+31)/32)*4;
207 aBmpHead.Typ='B'+'M'*256;
208 aBmpHead.SetOfs(sizeof(aBmpHead)+sizeof(aBmpInfo)+nColors*4);
209 aBmpHead.SetSize(aBmpHead.GetOfs()+nWdtOut*rHead.Ysize);
210 aBmpHead.Reserve1=0;
211 aBmpHead.Reserve2=0;
212 aBmpInfo.Size=sizeof(aBmpInfo);
213 aBmpInfo.Width=rHead.Xsize;
214 aBmpInfo.Hight=rHead.Ysize;
215 aBmpInfo.Planes=1;
216 aBmpInfo.PixBits=nColBits;
217 aBmpInfo.Compress=0;
218 aBmpInfo.ImgSize=0;
219 aBmpInfo.xDpmm=0;
220 aBmpInfo.yDpmm=0;
221 aBmpInfo.ColUsed=0;
222 aBmpInfo.ColMust=0;
223 pBuf.reset(new sal_uInt8[nWdtOut]);
224 if (!pBuf) return false; // error: no more memory available
225 WriteBmpFileHeader( rOut, aBmpHead );
226 WriteBmpInfoHeader( rOut, aBmpInfo );
227 memset(pBuf.get(),0,nWdtOut); // fill buffer with zeroes
229 if (nColors==2)
232 WriteRGBQuad( rOut, RGBQuad(0x00,0x00,0x00) ); // black
233 WriteRGBQuad( rOut, RGBQuad(0xFF,0xFF,0xFF) ); // white
234 nOfs=rOut.Tell();
235 for (j=0;j<rHead.Ysize;j++)
236 rOut.WriteBytes(pBuf.get(), nWdtOut); // fill file with zeroes
237 for (j=0;j<rHead.Ysize;j++) {
238 for(i=0;i<nWdtInp;i++) {
239 pBuf[i]=aPcx.GetByte(rInp);
241 for(i=nWdtInp;i<nWdtOut;i++) pBuf[i]=0; // up to 3 bytes
242 rOut.Seek(nOfs+((sal_uLong)rHead.Ysize-j-1L)*(sal_uLong)nWdtOut); // write backwards
243 rOut.WriteBytes(pBuf.get(), nWdtOut);
245 } else if (nColors==16) {
246 sal_uInt8 pl2= 0; // planes' masks
248 WriteRGBQuad( rOut, RGBQuad(0x00,0x00,0x00) ); // black
249 WriteRGBQuad( rOut, RGBQuad(0x24,0x24,0x24) ); // gray 80%
250 WriteRGBQuad( rOut, RGBQuad(0x49,0x49,0x49) ); // gray 60%
251 WriteRGBQuad( rOut, RGBQuad(0x92,0x92,0x92) ); // gray 40%
252 WriteRGBQuad( rOut, RGBQuad(0x6D,0x6D,0x6D) ); // gray 30%
253 WriteRGBQuad( rOut, RGBQuad(0xB6,0xB6,0xB6) ); // gray 20%
254 WriteRGBQuad( rOut, RGBQuad(0xDA,0xDA,0xDA) ); // gray 10%
255 WriteRGBQuad( rOut, RGBQuad(0xFF,0xFF,0xFF) ); // white
256 WriteRGBQuad( rOut, RGBQuad(0x00,0x00,0x00) ); // black
257 WriteRGBQuad( rOut, RGBQuad(0xFF,0x00,0x00) ); // red
258 WriteRGBQuad( rOut, RGBQuad(0x00,0x00,0xFF) ); // blue
259 WriteRGBQuad( rOut, RGBQuad(0xFF,0x00,0xFF) ); // magenta
260 WriteRGBQuad( rOut, RGBQuad(0x00,0xFF,0x00) ); // green
261 WriteRGBQuad( rOut, RGBQuad(0xFF,0xFF,0x00) ); // yellow
262 WriteRGBQuad( rOut, RGBQuad(0x00,0xFF,0xFF) ); // cyan
263 WriteRGBQuad( rOut, RGBQuad(0xFF,0xFF,0xFF) ); // white
265 nOfs=rOut.Tell();
266 for (j=0;j<rHead.Ysize;j++)
267 rOut.WriteBytes(pBuf.get(), nWdtOut); // fill file with zeroes
268 for (j=0;j<rHead.Ysize;j++) {
269 memset(pBuf.get(),0,nWdtOut);
270 for(k=0;k<4;k++) {
271 if (k==0) {
272 pl1=0x10; pl2=0x01;
273 } else {
274 pl1<<=1; pl2<<=1;
276 for(i=0;i<nWdtInp;i++) {
277 a=i*4;
278 b=aPcx.GetByte(rInp);
279 if (b & 0x80) pBuf[a ]|=pl1;
280 if (b & 0x40) pBuf[a ]|=pl2;
281 if (b & 0x20) pBuf[a+1]|=pl1;
282 if (b & 0x10) pBuf[a+1]|=pl2;
283 if (b & 0x08) pBuf[a+2]|=pl1;
284 if (b & 0x04) pBuf[a+2]|=pl2;
285 if (b & 0x02) pBuf[a+3]|=pl1;
286 if (b & 0x01) pBuf[a+3]|=pl2;
289 for(i=nWdtInp*4;i<nWdtOut;i++) pBuf[i]=0; // up to 3 bytes
290 rOut.Seek(nOfs+((sal_uLong)rHead.Ysize-j-1L)*(sal_uLong)nWdtOut); // write backwards
291 rOut.WriteBytes(pBuf.get(), nWdtOut);
293 } else if (nColors==256) {
294 cRGB[3]=0; // fourth palette entry for BMP
295 for (i=0;i<256;i++) { // copy palette
296 rInp.ReadBytes(cRGB, 3);
297 pl1=cRGB[0]; // switch red and blue
298 cRGB[0]=cRGB[2];
299 cRGB[2]=pl1;
300 rOut.WriteBytes(cRGB, 4);
303 nOfs=rOut.Tell();
304 for (j=0;j<rHead.Ysize;j++)
305 rOut.WriteBytes(pBuf.get(), nWdtOut); // fill file with zeroes
306 for (j=0;j<rHead.Ysize;j++) {
307 for(i=0;i<rHead.Xsize;i++)
308 pBuf[i]=aPcx.GetByte(rInp);
309 for(i=rHead.Xsize;i<nWdtOut;i++) pBuf[i]=0; // up to 3 bytes
310 rOut.Seek(nOfs+((sal_uLong)rHead.Ysize-j-1L)*(sal_uLong)nWdtOut); // write backwards
311 rOut.WriteBytes(pBuf.get(), nWdtOut);
314 return true;
317 bool SgfBMapFilter(SvStream& rInp, SvStream& rOut)
319 sal_uLong nFileStart; // offset of SgfHeaders. Usually 0.
320 SgfHeader aHead;
321 SgfEntry aEntr;
322 sal_uLong nNext;
323 bool bRet=false; // return value
325 nFileStart=rInp.Tell();
326 ReadSgfHeader( rInp, aHead );
327 if (aHead.ChkMagic() && (aHead.Typ==SgfBitImag0 || aHead.Typ==SgfBitImag1 ||
328 aHead.Typ==SgfBitImag2 || aHead.Typ==SgfBitImgMo))
330 bool bRdFlag = false; // read graphics entry?
331 nNext = aHead.GetOffset();
332 while (nNext && !bRdFlag && !rInp.GetError() && !rOut.GetError()) {
333 rInp.Seek(nFileStart+nNext);
334 ReadSgfEntry( rInp, aEntr );
335 nNext=aEntr.GetOffset();
336 if (aEntr.Typ==aHead.Typ) {
337 bRdFlag=true;
338 switch(aEntr.Typ) {
339 case SgfBitImag0:
340 case SgfBitImag1:
341 case SgfBitImag2:
342 case SgfBitImgMo: bRet=SgfFilterBMap(rInp,rOut,aHead,aEntr); break;
345 } // while(nNext)
347 if (rInp.GetError()) bRet=false;
348 return bRet;
351 // for StarDraw embedded SGF vector
352 long SgfVectXofs=0;
353 long SgfVectYofs=0;
354 long SgfVectXmul=0;
355 long SgfVectYmul=0;
356 long SgfVectXdiv=0;
357 long SgfVectYdiv=0;
358 bool SgfVectScal=false;
360 Color Hpgl2SvFarbe( sal_uInt8 nFarb )
362 sal_uLong nColor = COL_BLACK;
364 switch (nFarb & 0x07) {
365 case 0: nColor=COL_WHITE; break;
366 case 1: nColor=COL_YELLOW; break;
367 case 2: nColor=COL_LIGHTMAGENTA; break;
368 case 3: nColor=COL_LIGHTRED; break;
369 case 4: nColor=COL_LIGHTCYAN; break;
370 case 5: nColor=COL_LIGHTGREEN; break;
371 case 6: nColor=COL_LIGHTBLUE; break;
372 case 7: nColor=COL_BLACK; break;
374 Color aColor( nColor );
375 return aColor;
378 bool SgfFilterVect(SvStream& rInp, SgfHeader& rHead, SgfEntry&, GDIMetaFile& rMtf)
380 ScopedVclPtrInstance< VirtualDevice > aOutDev;
381 SgfVector aVect;
382 sal_uInt8 nFarb;
383 sal_uInt8 nFrb0=7;
384 sal_uInt8 nLTyp;
385 sal_uInt8 nOTyp;
386 bool bEoDt=false;
387 Point aP0(0,0);
388 Point aP1(0,0);
389 sal_uInt16 RecNr=0;
391 rMtf.Record(aOutDev.get());
392 aOutDev->SetLineColor(Color(COL_BLACK));
393 aOutDev->SetFillColor(Color(COL_BLACK));
395 while (!bEoDt && !rInp.GetError()) {
396 ReadSgfVector( rInp, aVect ); RecNr++;
397 nFarb=(sal_uInt8) (aVect.Flag & 0x000F);
398 nLTyp=(sal_uInt8)((aVect.Flag & 0x00F0) >>4);
399 nOTyp=(sal_uInt8)((aVect.Flag & 0x0F00) >>8);
400 bEoDt=(aVect.Flag & 0x4000) !=0;
401 bool bPDwn=(aVect.Flag & 0x8000) !=0;
403 long x=aVect.x-rHead.Xoffs;
404 long y=rHead.Ysize-(aVect.y-rHead.Yoffs);
405 if (SgfVectScal) {
406 if (SgfVectXdiv==0) SgfVectXdiv=rHead.Xsize;
407 if (SgfVectYdiv==0) SgfVectYdiv=rHead.Ysize;
408 if (SgfVectXdiv==0) SgfVectXdiv=1;
409 if (SgfVectYdiv==0) SgfVectYdiv=1;
410 x=SgfVectXofs+ x *SgfVectXmul /SgfVectXdiv;
411 y=SgfVectYofs+ y *SgfVectXmul /SgfVectYdiv;
413 aP1=Point(x,y);
414 if (!bEoDt && !rInp.GetError()) {
415 if (bPDwn && nLTyp<=6) {
416 switch(nOTyp) {
417 case 1: if (nFarb!=nFrb0) {
418 switch(rHead.SwGrCol) {
419 case SgfVectFarb: aOutDev->SetLineColor(Hpgl2SvFarbe(nFarb)); break;
420 case SgfVectGray: break;
421 case SgfVectWdth: break;
424 aOutDev->DrawLine(aP0,aP1); break; // line
425 case 2: break; // circle
426 case 3: break; // text
427 case 5: aOutDev->DrawRect(Rectangle(aP0,aP1)); break; // rectangle (solid)
430 aP0=aP1;
431 nFrb0=nFarb;
434 rMtf.Stop();
435 rMtf.WindStart();
436 MapMode aMap( MapUnit::Map10thMM, Point(),
437 Fraction( 1, 4 ), Fraction( 1, 4 ) );
438 rMtf.SetPrefMapMode( aMap );
439 rMtf.SetPrefSize( Size( (short)rHead.Xsize, (short)rHead.Ysize ) );
440 return true;
443 bool SgfVectFilter(SvStream& rInp, GDIMetaFile& rMtf)
445 sal_uLong nFileStart; // offset of SgfHeaders. Usually 0.
446 SgfHeader aHead;
447 SgfEntry aEntr;
448 sal_uLong nNext;
449 bool bRet=false; // return value
451 nFileStart=rInp.Tell();
452 ReadSgfHeader( rInp, aHead );
453 if (aHead.ChkMagic() && aHead.Typ==SGF_SIMPVECT) {
454 nNext=aHead.GetOffset();
455 while (nNext && !rInp.GetError()) {
456 rInp.Seek(nFileStart+nNext);
457 ReadSgfEntry( rInp, aEntr );
458 nNext=aEntr.GetOffset();
459 if (aEntr.Typ==aHead.Typ) {
460 bRet=SgfFilterVect(rInp,aHead,aEntr,rMtf);
462 } // while(nNext)
464 return bRet;
467 /*************************************************************************
469 |* CheckSgfTyp()
471 |* Description determine which kind of SGF/SGV it is
473 *************************************************************************/
474 sal_uInt8 CheckSgfTyp(SvStream& rInp, sal_uInt16& nVersion)
476 #if OSL_DEBUG_LEVEL > 1 // check record size, new Compiler had different alignment!
477 if (sizeof(SgfHeader)!=SgfHeaderSize ||
478 sizeof(SgfEntry) !=SgfEntrySize ||
479 sizeof(SgfVector)!=SgfVectorSize ||
480 sizeof(BmpFileHeader)!=BmpFileHeaderSize ||
481 sizeof(BmpInfoHeader)!=BmpInfoHeaderSize ||
482 sizeof(RGBQuad )!=RGBQuadSize ) return SGF_DONTKNOW;
483 #endif
485 sal_uLong nPos;
486 SgfHeader aHead;
487 nVersion=0;
488 nPos=rInp.Tell();
489 ReadSgfHeader( rInp, aHead );
490 rInp.Seek(nPos);
491 if (aHead.ChkMagic()) {
492 nVersion=aHead.Version;
493 switch(aHead.Typ) {
494 case SgfBitImag0:
495 case SgfBitImag1:
496 case SgfBitImag2:
497 case SgfBitImgMo: return SGF_BITIMAGE;
498 case SgfSimpVect: return SGF_SIMPVECT;
499 case SgfPostScrp: return SGF_POSTSCRP;
500 case SgfStarDraw: return SGF_STARDRAW;
501 default : return SGF_DONTKNOW;
503 } else {
504 return SGF_DONTKNOW;
508 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */