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