1 //
2 // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use.
3 //
4 #ifndef CHARLS_PROCESSLINE
5 #define CHARLS_PROCESSLINE
6
7 #include "util.h"
8 #include "publictypes.h"
9 #include <vector>
10 #include <sstream>
11 #include <cstring>
12
13 #ifdef _MSC_VER
14 #pragma warning(disable: 4996) // 'function': was declared deprecated also 'std::<function name>': Function call with parameters that may be unsafe [VS2012]
15 #endif
16
17 // TODO: analyze if template code can be improved
18 #ifdef _MSC_VER
19 #pragma warning(disable: 4127) // conditional expression is constant [VS2013]
20 #endif
21
22
23 //
24 // This file defines the ProcessLine base class, its derivitives and helper functions.
25 // During coding/decoding, CharLS process one line at a time. The different Processline implementations
26 // convert the uncompressed format to and from the internal format for encoding.
27 // Conversions include color transforms, line interleaved vs sample interleaved, masking out unused bits,
28 // accounting for line padding etc.
29 // This mechanism could be used to encode/decode images as they are received.
30 //
31
32 class ProcessLine
33 {
34 public:
35 virtual ~ProcessLine() = default;
36 virtual void NewLineDecoded(const void* pSrc, int pixelCount, int sourceStride) = 0;
37 virtual void NewLineRequested(void* pDest, int pixelCount, int destStride) = 0;
38 };
39
40
41 class PostProcesSingleComponent : public ProcessLine
42 {
43 public:
PostProcesSingleComponent(void * rawData,const JlsParameters & params,int bytesPerPixel)44 PostProcesSingleComponent(void* rawData, const JlsParameters& params, int bytesPerPixel) :
45 _rawData(static_cast<uint8_t*>(rawData)),
46 _bytesPerPixel(bytesPerPixel),
47 _bytesPerLine(params.stride)
48 {
49 }
50
NewLineRequested(void * dest,int pixelCount,int)51 void NewLineRequested(void* dest, int pixelCount, int /*byteStride*/) override
52 {
53 ::memcpy(dest, _rawData, pixelCount * _bytesPerPixel);
54 _rawData += _bytesPerLine;
55 }
56
NewLineDecoded(const void * pSrc,int pixelCount,int)57 void NewLineDecoded(const void* pSrc, int pixelCount, int /*sourceStride*/) override
58 {
59 ::memcpy(_rawData, pSrc, pixelCount * _bytesPerPixel);
60 _rawData += _bytesPerLine;
61 }
62
63 private:
64 uint8_t* _rawData;
65 int _bytesPerPixel;
66 int _bytesPerLine;
67 };
68
69
ByteSwap(unsigned char * data,int count)70 inline void ByteSwap(unsigned char* data, int count)
71 {
72 if (count & 1)
73 {
74 std::ostringstream message;
75 message << "An odd number of bytes (" << count << ") cannot be swapped.";
76 throw CreateSystemError(charls::ApiResult::InvalidJlsParameters, message.str());
77 }
78
79 unsigned int* data32 = reinterpret_cast<unsigned int*>(data);
80 for(int i = 0; i < count / 4; i++)
81 {
82 unsigned int value = data32[i];
83 data32[i] = ((value >> 8) & 0x00FF00FF) | ((value & 0x00FF00FF) << 8);
84 }
85
86 if ((count % 4) != 0)
87 {
88 std::swap(data[count-2], data[count-1]);
89 }
90 }
91
92 class PostProcesSingleStream : public ProcessLine
93 {
94 public:
PostProcesSingleStream(std::basic_streambuf<char> * rawData,const JlsParameters & params,int bytesPerPixel)95 PostProcesSingleStream(std::basic_streambuf<char>* rawData, const JlsParameters& params, int bytesPerPixel) :
96 _rawData(rawData),
97 _bytesPerPixel(bytesPerPixel),
98 _bytesPerLine(params.stride)
99 {
100 }
101
NewLineRequested(void * dest,int pixelCount,int)102 void NewLineRequested(void* dest, int pixelCount, int /*destStride*/) override
103 {
104 std::size_t bytesToRead = pixelCount * _bytesPerPixel;
105 while (bytesToRead != 0)
106 {
107 std::streamsize bytesRead = _rawData->sgetn(static_cast<char*>(dest), bytesToRead);
108 if (bytesRead == 0)
109 throw std::system_error(static_cast<int>(charls::ApiResult::UncompressedBufferTooSmall), CharLSCategoryInstance());
110
111 bytesToRead = static_cast<std::size_t>(bytesToRead - bytesRead);
112 }
113
114 if (_bytesPerPixel == 2 )
115 {
116 ByteSwap(static_cast<unsigned char*>(dest), 2 * pixelCount);
117 }
118
119 if (_bytesPerLine - pixelCount * _bytesPerPixel > 0)
120 {
121 _rawData->pubseekoff(std::streamoff(_bytesPerLine - bytesToRead), std::ios_base::cur);
122 }
123 }
124
NewLineDecoded(const void * pSrc,int pixelCount,int)125 void NewLineDecoded(const void* pSrc, int pixelCount, int /*sourceStride*/) override
126 {
127 int bytesToWrite = pixelCount * _bytesPerPixel;
128 std::streamsize bytesWritten = _rawData->sputn(static_cast<const char*>(pSrc), bytesToWrite);
129 if (bytesWritten != bytesToWrite)
130 throw std::system_error(static_cast<int>(charls::ApiResult::UncompressedBufferTooSmall), CharLSCategoryInstance());
131 }
132
133 private:
134 std::basic_streambuf<char>* _rawData;
135 int _bytesPerPixel;
136 int _bytesPerLine;
137 };
138
139
140 template<typename TRANSFORM, typename SAMPLE>
TransformLineToQuad(const SAMPLE * ptypeInput,int32_t pixelStrideIn,Quad<SAMPLE> * pbyteBuffer,int32_t pixelStride,TRANSFORM & transform)141 void TransformLineToQuad(const SAMPLE* ptypeInput, int32_t pixelStrideIn, Quad<SAMPLE>* pbyteBuffer, int32_t pixelStride, TRANSFORM& transform)
142 {
143 int cpixel = MIN(pixelStride, pixelStrideIn);
144 Quad<SAMPLE>* ptypeBuffer = pbyteBuffer;
145
146 for (int x = 0; x < cpixel; ++x)
147 {
148 Quad<SAMPLE> pixel(transform(ptypeInput[x], ptypeInput[x + pixelStrideIn], ptypeInput[x + 2*pixelStrideIn]),ptypeInput[x + 3*pixelStrideIn]) ;
149
150 ptypeBuffer[x] = pixel;
151 }
152 }
153
154
155 template<typename TRANSFORM, typename SAMPLE>
TransformQuadToLine(const Quad<SAMPLE> * pbyteInput,int32_t pixelStrideIn,SAMPLE * ptypeBuffer,int32_t pixelStride,TRANSFORM & transform)156 void TransformQuadToLine(const Quad<SAMPLE>* pbyteInput, int32_t pixelStrideIn, SAMPLE* ptypeBuffer, int32_t pixelStride, TRANSFORM& transform)
157 {
158 int cpixel = MIN(pixelStride, pixelStrideIn);
159 const Quad<SAMPLE>* ptypeBufferIn = pbyteInput;
160
161 for (int x = 0; x < cpixel; ++x)
162 {
163 Quad<SAMPLE> color = ptypeBufferIn[x];
164 Quad<SAMPLE> colorTranformed(transform(color.v1, color.v2, color.v3), color.v4);
165
166 ptypeBuffer[x] = colorTranformed.v1;
167 ptypeBuffer[x + pixelStride] = colorTranformed.v2;
168 ptypeBuffer[x + 2 * pixelStride] = colorTranformed.v3;
169 ptypeBuffer[x + 3 * pixelStride] = colorTranformed.v4;
170 }
171 }
172
173
174 template<typename SAMPLE>
TransformRgbToBgr(SAMPLE * pDest,int samplesPerPixel,int pixelCount)175 void TransformRgbToBgr(SAMPLE* pDest, int samplesPerPixel, int pixelCount)
176 {
177 for (int i = 0; i < pixelCount; ++i)
178 {
179 std::swap(pDest[0], pDest[2]);
180 pDest += samplesPerPixel;
181 }
182 }
183
184
185 template<typename TRANSFORM, typename SAMPLE>
TransformLine(Triplet<SAMPLE> * pDest,const Triplet<SAMPLE> * pSrc,int pixelCount,TRANSFORM & transform)186 void TransformLine(Triplet<SAMPLE>* pDest, const Triplet<SAMPLE>* pSrc, int pixelCount, TRANSFORM& transform)
187 {
188 for (int i = 0; i < pixelCount; ++i)
189 {
190 pDest[i] = transform(pSrc[i].v1, pSrc[i].v2, pSrc[i].v3);
191 }
192 }
193
194
195 template<typename TRANSFORM, typename SAMPLE>
TransformLineToTriplet(const SAMPLE * ptypeInput,int32_t pixelStrideIn,Triplet<SAMPLE> * pbyteBuffer,int32_t pixelStride,TRANSFORM & transform)196 void TransformLineToTriplet(const SAMPLE* ptypeInput, int32_t pixelStrideIn, Triplet<SAMPLE>* pbyteBuffer, int32_t pixelStride, TRANSFORM& transform)
197 {
198 int cpixel = MIN(pixelStride, pixelStrideIn);
199 Triplet<SAMPLE>* ptypeBuffer = pbyteBuffer;
200
201 for (int x = 0; x < cpixel; ++x)
202 {
203 ptypeBuffer[x] = transform(ptypeInput[x], ptypeInput[x + pixelStrideIn], ptypeInput[x + 2*pixelStrideIn]);
204 }
205 }
206
207
208 template<typename TRANSFORM, typename SAMPLE>
TransformTripletToLine(const Triplet<SAMPLE> * pbyteInput,int32_t pixelStrideIn,SAMPLE * ptypeBuffer,int32_t pixelStride,TRANSFORM & transform)209 void TransformTripletToLine(const Triplet<SAMPLE>* pbyteInput, int32_t pixelStrideIn, SAMPLE* ptypeBuffer, int32_t pixelStride, TRANSFORM& transform)
210 {
211 int cpixel = MIN(pixelStride, pixelStrideIn);
212 const Triplet<SAMPLE>* ptypeBufferIn = pbyteInput;
213
214 for (int x = 0; x < cpixel; ++x)
215 {
216 Triplet<SAMPLE> color = ptypeBufferIn[x];
217 Triplet<SAMPLE> colorTranformed = transform(color.v1, color.v2, color.v3);
218
219 ptypeBuffer[x] = colorTranformed.v1;
220 ptypeBuffer[x + pixelStride] = colorTranformed.v2;
221 ptypeBuffer[x + 2 *pixelStride] = colorTranformed.v3;
222 }
223 }
224
225
226 template<typename TRANSFORM>
227 class ProcessTransformed : public ProcessLine
228 {
229 typedef typename TRANSFORM::SAMPLE SAMPLE;
230
231 public:
ProcessTransformed(ByteStreamInfo rawStream,const JlsParameters & info,TRANSFORM transform)232 ProcessTransformed(ByteStreamInfo rawStream, const JlsParameters& info, TRANSFORM transform) :
233 _params(info),
234 _templine(info.width * info.components),
235 _buffer(info.width * info.components * sizeof(SAMPLE)),
236 _transform(transform),
237 _inverseTransform(transform),
238 _rawPixels(rawStream)
239 {
240 }
241
NewLineRequested(void * dest,int pixelCount,int destStride)242 void NewLineRequested(void* dest, int pixelCount, int destStride) override
243 {
244 if (!_rawPixels.rawStream)
245 {
246 Transform(_rawPixels.rawData, dest, pixelCount, destStride);
247 _rawPixels.rawData += _params.stride;
248 return;
249 }
250
251 Transform(_rawPixels.rawStream, dest, pixelCount, destStride);
252 }
253
Transform(std::basic_streambuf<char> * rawStream,void * dest,int pixelCount,int destStride)254 void Transform(std::basic_streambuf<char>* rawStream, void* dest, int pixelCount, int destStride)
255 {
256 std::streamsize bytesToRead = pixelCount * _params.components * sizeof(SAMPLE);
257 while (bytesToRead != 0)
258 {
259 std::streamsize read = rawStream->sgetn(reinterpret_cast<char*>(&_buffer[0]), bytesToRead);
260 if (read == 0)
261 {
262 std::ostringstream message;
263 message << "No more bytes available in input buffer, still neededing " << read;
264 throw CreateSystemError(charls::ApiResult::UncompressedBufferTooSmall, message.str());
265 }
266
267 bytesToRead -= read;
268 }
269 if (sizeof(SAMPLE) == 2 && _params.colorTransformation == charls::ColorTransformation::BigEndian)
270 {
271 ByteSwap(&_buffer[0], _params.components * sizeof(SAMPLE) * pixelCount);
272 }
273 Transform(&_buffer[0], dest, pixelCount, destStride);
274 }
275
Transform(const void * source,void * dest,int pixelCount,int destStride)276 void Transform(const void* source, void* dest, int pixelCount, int destStride)
277 {
278 if (_params.outputBgr)
279 {
280 memcpy(&_templine[0], source, sizeof(Triplet<SAMPLE>) * pixelCount);
281 TransformRgbToBgr(static_cast<SAMPLE*>(&_templine[0]), _params.components, pixelCount);
282 source = &_templine[0];
283 }
284
285 if (_params.components == 3)
286 {
287 if (_params.interleaveMode == charls::InterleaveMode::Sample)
288 {
289 TransformLine(static_cast<Triplet<SAMPLE>*>(dest), static_cast<const Triplet<SAMPLE>*>(source), pixelCount, _transform);
290 }
291 else
292 {
293 TransformTripletToLine(static_cast<const Triplet<SAMPLE>*>(source), pixelCount, static_cast<SAMPLE*>(dest), destStride, _transform);
294 }
295 }
296 else if (_params.components == 4 && _params.interleaveMode == charls::InterleaveMode::Line)
297 {
298 TransformQuadToLine(static_cast<const Quad<SAMPLE>*>(source), pixelCount, static_cast<SAMPLE*>(dest), destStride, _transform);
299 }
300 }
301
DecodeTransform(const void * pSrc,void * rawData,int pixelCount,int byteStride)302 void DecodeTransform(const void* pSrc, void* rawData, int pixelCount, int byteStride)
303 {
304 if (_params.components == 3)
305 {
306 if (_params.interleaveMode == charls::InterleaveMode::Sample)
307 {
308 TransformLine(static_cast<Triplet<SAMPLE>*>(rawData), static_cast<const Triplet<SAMPLE>*>(pSrc), pixelCount, _inverseTransform);
309 }
310 else
311 {
312 TransformLineToTriplet(static_cast<const SAMPLE*>(pSrc), byteStride, static_cast<Triplet<SAMPLE>*>(rawData), pixelCount, _inverseTransform);
313 }
314 }
315 else if (_params.components == 4 && _params.interleaveMode == charls::InterleaveMode::Line)
316 {
317 TransformLineToQuad(static_cast<const SAMPLE*>(pSrc), byteStride, static_cast<Quad<SAMPLE>*>(rawData), pixelCount, _inverseTransform);
318 }
319
320 if (_params.outputBgr)
321 {
322 TransformRgbToBgr(static_cast<SAMPLE*>(rawData), _params.components, pixelCount);
323 }
324 }
325
NewLineDecoded(const void * pSrc,int pixelCount,int sourceStride)326 void NewLineDecoded(const void* pSrc, int pixelCount, int sourceStride) override
327 {
328 if (_rawPixels.rawStream)
329 {
330 std::streamsize bytesToWrite = pixelCount * _params.components * sizeof(SAMPLE);
331 DecodeTransform(pSrc, &_buffer[0], pixelCount, sourceStride);
332
333 if (sizeof(SAMPLE) == 2 && _params.colorTransformation == charls::ColorTransformation::BigEndian)
334 {
335 ByteSwap(&_buffer[0], _params.components * sizeof(SAMPLE) * pixelCount);
336 }
337
338 std::streamsize bytesWritten = _rawPixels.rawStream->sputn(reinterpret_cast<char*>(&_buffer[0]), bytesToWrite);
339 if (bytesWritten != bytesToWrite)
340 throw std::system_error(static_cast<int>(charls::ApiResult::UncompressedBufferTooSmall), CharLSCategoryInstance());
341 }
342 else
343 {
344 DecodeTransform(pSrc, _rawPixels.rawData, pixelCount, sourceStride);
345 _rawPixels.rawData += _params.stride;
346 }
347 }
348
349 private:
350 const JlsParameters& _params;
351 std::vector<SAMPLE> _templine;
352 std::vector<uint8_t> _buffer;
353 TRANSFORM _transform;
354 typename TRANSFORM::INVERSE _inverseTransform;
355 ByteStreamInfo _rawPixels;
356 };
357
358
359 #endif
360