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 <tools/stream.hxx>
22 #include "giflzwc.hxx"
23 #include <array>
24
25
26 class GIFImageDataOutputStream
27 {
28 private:
29
30 void FlushBlockBuf();
31 inline void FlushBitsBufsFullBytes();
32
33 SvStream& rStream;
34 std::array<sal_uInt8, 255>
35 pBlockBuf;
36 sal_uInt8 nBlockBufSize;
37 sal_uInt32 nBitsBuf;
38 sal_uInt16 nBitsBufSize;
39
40 public:
41
42 GIFImageDataOutputStream( SvStream & rGIF, sal_uInt8 nLZWDataSize );
43 ~GIFImageDataOutputStream();
44
45 inline void WriteBits( sal_uInt16 nCode, sal_uInt16 nCodeLen );
46 };
47
48
FlushBitsBufsFullBytes()49 inline void GIFImageDataOutputStream::FlushBitsBufsFullBytes()
50 {
51 while (nBitsBufSize>=8)
52 {
53 if( nBlockBufSize==255 )
54 FlushBlockBuf();
55
56 pBlockBuf[nBlockBufSize++] = static_cast<sal_uInt8>(nBitsBuf);
57 nBitsBuf >>= 8;
58 nBitsBufSize -= 8;
59 }
60 }
61
62
WriteBits(sal_uInt16 nCode,sal_uInt16 nCodeLen)63 inline void GIFImageDataOutputStream::WriteBits( sal_uInt16 nCode, sal_uInt16 nCodeLen )
64 {
65 if( nBitsBufSize+nCodeLen>32 )
66 FlushBitsBufsFullBytes();
67
68 nBitsBuf |= static_cast<sal_uInt32>(nCode) << nBitsBufSize;
69 nBitsBufSize = nBitsBufSize + nCodeLen;
70 }
71
72
GIFImageDataOutputStream(SvStream & rGIF,sal_uInt8 nLZWDataSize)73 GIFImageDataOutputStream::GIFImageDataOutputStream( SvStream & rGIF, sal_uInt8 nLZWDataSize ) :
74 rStream(rGIF)
75 {
76 nBlockBufSize = 0;
77 nBitsBufSize = 0;
78 nBitsBuf = 0;
79 rStream.WriteUChar( nLZWDataSize );
80 }
81
82
~GIFImageDataOutputStream()83 GIFImageDataOutputStream::~GIFImageDataOutputStream()
84 {
85 WriteBits(0,7);
86 FlushBitsBufsFullBytes();
87 FlushBlockBuf();
88 rStream.WriteUChar( 0 );
89 }
90
91
FlushBlockBuf()92 void GIFImageDataOutputStream::FlushBlockBuf()
93 {
94 if( nBlockBufSize )
95 {
96 rStream.WriteUChar( nBlockBufSize );
97 rStream.WriteBytes(pBlockBuf.data(), nBlockBufSize);
98 nBlockBufSize = 0;
99 }
100 }
101
102
103 struct GIFLZWCTreeNode
104 {
105
106 GIFLZWCTreeNode* pBrother; // next node which has the same father
107 GIFLZWCTreeNode* pFirstChild; // first
108 sal_uInt16 nCode; // the code for the string of pixel values which comes about
109 sal_uInt16 nValue; // the pixel value
110 };
111
112
GIFLZWCompressor()113 GIFLZWCompressor::GIFLZWCompressor()
114 : pPrefix(nullptr), nDataSize(0), nClearCode(0),
115 nEOICode(0), nTableSize(0), nCodeSize(0)
116 {
117 }
118
119
~GIFLZWCompressor()120 GIFLZWCompressor::~GIFLZWCompressor()
121 {
122 if (pIDOS!=nullptr) EndCompression();
123 }
124
125
StartCompression(SvStream & rGIF,sal_uInt16 nPixelSize)126 void GIFLZWCompressor::StartCompression( SvStream& rGIF, sal_uInt16 nPixelSize )
127 {
128 if( !pIDOS )
129 {
130 sal_uInt16 i;
131
132 nDataSize = nPixelSize;
133
134 if( nDataSize < 2 )
135 nDataSize=2;
136
137 nClearCode=1<<nDataSize;
138 nEOICode=nClearCode+1;
139 nTableSize=nEOICode+1;
140 nCodeSize=nDataSize+1;
141
142 pIDOS.reset(new GIFImageDataOutputStream(rGIF,static_cast<sal_uInt8>(nDataSize)));
143 pTable.reset(new GIFLZWCTreeNode[4096]);
144
145 for (i=0; i<4096; i++)
146 {
147 pTable[i].pBrother = pTable[i].pFirstChild = nullptr;
148 pTable[i].nCode = i;
149 pTable[i].nValue = static_cast<sal_uInt8>( i );
150 }
151
152 pPrefix = nullptr;
153 pIDOS->WriteBits( nClearCode,nCodeSize );
154 }
155 }
156
Compress(sal_uInt8 * pSrc,sal_uInt32 nSize)157 void GIFLZWCompressor::Compress(sal_uInt8* pSrc, sal_uInt32 nSize)
158 {
159 if( pIDOS )
160 {
161 GIFLZWCTreeNode* p;
162 sal_uInt16 i;
163 sal_uInt8 nV;
164
165 if( !pPrefix && nSize )
166 {
167 pPrefix=&pTable[*pSrc++];
168 nSize--;
169 }
170
171 while( nSize )
172 {
173 nSize--;
174 nV=*pSrc++;
175 for( p=pPrefix->pFirstChild; p!=nullptr; p=p->pBrother )
176 {
177 if (p->nValue==nV)
178 break;
179 }
180
181 if( p)
182 pPrefix=p;
183 else
184 {
185 pIDOS->WriteBits(pPrefix->nCode,nCodeSize);
186
187 if (nTableSize==4096)
188 {
189 pIDOS->WriteBits(nClearCode,nCodeSize);
190
191 for (i=0; i<nClearCode; i++)
192 pTable[i].pFirstChild=nullptr;
193
194 nCodeSize=nDataSize+1;
195 nTableSize=nEOICode+1;
196 }
197 else
198 {
199 if(nTableSize==static_cast<sal_uInt16>(1<<nCodeSize))
200 nCodeSize++;
201
202 p=&pTable[nTableSize++];
203 p->pBrother=pPrefix->pFirstChild;
204 pPrefix->pFirstChild=p;
205 p->nValue=nV;
206 p->pFirstChild=nullptr;
207 }
208
209 pPrefix=&pTable[nV];
210 }
211 }
212 }
213 }
214
EndCompression()215 void GIFLZWCompressor::EndCompression()
216 {
217 if( pIDOS )
218 {
219 if( pPrefix )
220 pIDOS->WriteBits(pPrefix->nCode,nCodeSize);
221
222 pIDOS->WriteBits( nEOICode,nCodeSize );
223 pTable.reset();
224 pIDOS.reset();
225 }
226 }
227
228 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
229