1 //
2 // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use.
3 //
4 
5 
6 #include "charls.h"
7 #include "util.h"
8 #include "jpegstreamreader.h"
9 #include "jpegstreamwriter.h"
10 #include "jpegmarkersegment.h"
11 #include <cstring>
12 
13 using namespace std;
14 using namespace charls;
15 
16 
VerifyInput(const ByteStreamInfo & uncompressedStream,const JlsParameters & parameters)17 static void VerifyInput(const ByteStreamInfo& uncompressedStream, const JlsParameters& parameters)
18 {
19     if (!uncompressedStream.rawStream && !uncompressedStream.rawData)
20         throw CreateSystemError(ApiResult::InvalidJlsParameters, "rawStream or rawData needs to reference to something");
21 
22     if (parameters.width < 1 || parameters.width > 65535)
23         throw CreateSystemError(ApiResult::InvalidJlsParameters, "width needs to be in the range [1, 65535]");
24 
25     if (parameters.height < 1 || parameters.height > 65535)
26         throw CreateSystemError(ApiResult::InvalidJlsParameters, "height needs to be in the range [1, 65535]");
27 
28     if (parameters.bitsPerSample < 2 || parameters.bitsPerSample > 16)
29         throw CreateSystemError(ApiResult::InvalidJlsParameters, "bitspersample needs to be in the range [2, 16]");
30 
31     if (!(parameters.interleaveMode == InterleaveMode::None || parameters.interleaveMode == InterleaveMode::Sample || parameters.interleaveMode == InterleaveMode::Line))
32         throw CreateSystemError(ApiResult::InvalidJlsParameters, "interleaveMode needs to be set to a value of {None, Sample, Line}");
33 
34     if (parameters.components < 1 || parameters.components > 255)
35         throw CreateSystemError(ApiResult::InvalidJlsParameters, "components needs to be in the range [1, 255]");
36 
37     if (uncompressedStream.rawData)
38     {
39         if (uncompressedStream.count < size_t(parameters.height * parameters.width * parameters.components * (parameters.bitsPerSample > 8 ? 2 : 1)))
40             throw CreateSystemError(ApiResult::InvalidJlsParameters, "uncompressed size does not match with the other parameters");
41     }
42 
43     switch (parameters.components)
44     {
45     case 3:
46         break;
47     case 4:
48         if (parameters.interleaveMode == InterleaveMode::Sample)
49             throw CreateSystemError(ApiResult::InvalidJlsParameters, "interleaveMode cannot be set to Sample in combination with components = 4");
50         break;
51     default:
52         if (parameters.interleaveMode != InterleaveMode::None)
53             throw CreateSystemError(ApiResult::InvalidJlsParameters, "interleaveMode can only be set to None in combination with components = 1");
54         break;
55     }
56 }
57 
58 
SystemErrorToCharLSError(const system_error & e)59 static ApiResult SystemErrorToCharLSError(const system_error& e)
60 {
61     return e.code().category() == CharLSCategoryInstance() ? static_cast<ApiResult>(e.code().value()) : ApiResult::UnspecifiedFailure;
62 }
63 
64 
ClearErrorMessage(char * errorMessage)65 static void ClearErrorMessage(char* errorMessage)
66 {
67     if (errorMessage)
68     {
69         errorMessage[0] = 0;
70     }
71 }
72 
73 
CopyWhatTextToErrorMessage(const system_error & e,char * errorMessage)74 static void CopyWhatTextToErrorMessage(const system_error& e, char* errorMessage)
75 {
76     if (!errorMessage)
77         return;
78 
79     if (e.code().category() == CharLSCategoryInstance())
80     {
81         ASSERT(strlen(e.what()) < ErrorMessageSize);
82         strcpy(errorMessage, e.what());
83     }
84     else
85     {
86         errorMessage[0] = 0;
87     }
88 }
89 
90 
JpegLsEncodeStream(ByteStreamInfo compressedStreamInfo,size_t & pcbyteWritten,ByteStreamInfo rawStreamInfo,const struct JlsParameters & params,char * errorMessage)91 CHARLS_IMEXPORT(ApiResult) JpegLsEncodeStream(ByteStreamInfo compressedStreamInfo, size_t& pcbyteWritten,
92     ByteStreamInfo rawStreamInfo, const struct JlsParameters& params, char* errorMessage)
93 {
94     try
95     {
96         VerifyInput(rawStreamInfo, params);
97 
98         JlsParameters info = params;
99         if (info.stride == 0)
100         {
101             info.stride = info.width * ((info.bitsPerSample + 7)/8);
102             if (info.interleaveMode != InterleaveMode::None)
103             {
104                 info.stride *= info.components;
105             }
106         }
107 
108         JpegStreamWriter writer;
109         if (info.jfif.version)
110         {
111             writer.AddSegment(JpegMarkerSegment::CreateJpegFileInterchangeFormatSegment(info.jfif));
112         }
113 
114         writer.AddSegment(JpegMarkerSegment::CreateStartOfFrameSegment(info.width, info.height, info.bitsPerSample, info.components));
115 
116 
117         if (info.colorTransformation != ColorTransformation::None)
118         {
119             writer.AddColorTransform(info.colorTransformation);
120         }
121 
122         if (info.interleaveMode == InterleaveMode::None)
123         {
124             int32_t cbyteComp = info.width * info.height * ((info.bitsPerSample + 7) / 8);
125             for (int32_t component = 0; component < info.components; ++component)
126             {
127                 writer.AddScan(rawStreamInfo, info);
128                 SkipBytes(rawStreamInfo, cbyteComp);
129             }
130         }
131         else
132         {
133             writer.AddScan(rawStreamInfo, info);
134         }
135 
136         writer.Write(compressedStreamInfo);
137         pcbyteWritten = writer.GetBytesWritten();
138 
139         ClearErrorMessage(errorMessage);
140         return ApiResult::OK;
141     }
142     catch (const system_error& e)
143     {
144         CopyWhatTextToErrorMessage(e, errorMessage);
145         return SystemErrorToCharLSError(e);
146     }
147     catch (...)
148     {
149         ClearErrorMessage(errorMessage);
150         return ApiResult::UnexpectedFailure;
151     }
152 }
153 
154 
JpegLsDecodeStream(ByteStreamInfo rawStream,ByteStreamInfo compressedStream,const JlsParameters * info,char * errorMessage)155 CHARLS_IMEXPORT(ApiResult) JpegLsDecodeStream(ByteStreamInfo rawStream, ByteStreamInfo compressedStream, const JlsParameters* info, char* errorMessage)
156 {
157     try
158     {
159         JpegStreamReader reader(compressedStream);
160 
161         if (info)
162         {
163             reader.SetInfo(*info);
164         }
165 
166         reader.Read(rawStream);
167 
168         ClearErrorMessage(errorMessage);
169         return ApiResult::OK;
170     }
171     catch (const system_error& e)
172     {
173         CopyWhatTextToErrorMessage(e, errorMessage);
174         return SystemErrorToCharLSError(e);
175     }
176     catch (...)
177     {
178         ClearErrorMessage(errorMessage);
179         return ApiResult::UnexpectedFailure;
180     }
181 }
182 
183 
JpegLsReadHeaderStream(ByteStreamInfo rawStreamInfo,JlsParameters * params,char * errorMessage)184 CHARLS_IMEXPORT(ApiResult) JpegLsReadHeaderStream(ByteStreamInfo rawStreamInfo, JlsParameters* params, char* errorMessage)
185 {
186     try
187     {
188         JpegStreamReader reader(rawStreamInfo);
189         reader.ReadHeader();
190         reader.ReadStartOfScan(true);
191         *params = reader.GetMetadata();
192 
193         ClearErrorMessage(errorMessage);
194         return ApiResult::OK;
195     }
196     catch (const std::system_error& e)
197     {
198         CopyWhatTextToErrorMessage(e, errorMessage);
199         return SystemErrorToCharLSError(e);
200     }
201     catch (...)
202     {
203         ClearErrorMessage(errorMessage);
204         return ApiResult::UnexpectedFailure;
205     }
206 }
207 
208 extern "C"
209 {
JpegLsEncode(void * destination,size_t destinationLength,size_t * bytesWritten,const void * source,size_t sourceLength,const struct JlsParameters * params,char * errorMessage)210     CHARLS_IMEXPORT(ApiResult) JpegLsEncode(void* destination, size_t destinationLength, size_t* bytesWritten, const void* source, size_t sourceLength, const struct JlsParameters* params, char* errorMessage)
211     {
212         if (!destination || !bytesWritten || !source || !params)
213             return ApiResult::InvalidJlsParameters;
214 
215         ByteStreamInfo rawStreamInfo = FromByteArray(source, sourceLength);
216         ByteStreamInfo compressedStreamInfo = FromByteArray(destination, destinationLength);
217 
218         return JpegLsEncodeStream(compressedStreamInfo, *bytesWritten, rawStreamInfo, *params, errorMessage);
219     }
220 
221 
JpegLsReadHeader(const void * compressedData,size_t compressedLength,JlsParameters * params,char * errorMessage)222     CHARLS_IMEXPORT(ApiResult) JpegLsReadHeader(const void* compressedData, size_t compressedLength, JlsParameters* params, char* errorMessage)
223     {
224         return JpegLsReadHeaderStream(FromByteArray(compressedData, compressedLength), params, errorMessage);
225     }
226 
227 
JpegLsDecode(void * destination,size_t destinationLength,const void * source,size_t sourceLength,const struct JlsParameters * params,char * errorMessage)228     CHARLS_IMEXPORT(ApiResult) JpegLsDecode(void* destination, size_t destinationLength, const void* source, size_t sourceLength, const struct JlsParameters* params, char* errorMessage)
229     {
230         ByteStreamInfo compressedStream = FromByteArray(source, sourceLength);
231         ByteStreamInfo rawStreamInfo = FromByteArray(destination, destinationLength);
232 
233         return JpegLsDecodeStream(rawStreamInfo, compressedStream, params, errorMessage);
234     }
235 
236 
JpegLsVerifyEncode(const void * uncompressedData,size_t uncompressedLength,const void * compressedData,size_t compressedLength,char * errorMessage)237     CHARLS_IMEXPORT(ApiResult) JpegLsVerifyEncode(const void* uncompressedData, size_t uncompressedLength, const void* compressedData, size_t compressedLength, char* errorMessage)
238     {
239         try
240         {
241             JlsParameters info = JlsParameters();
242 
243             auto error = JpegLsReadHeader(compressedData, compressedLength, &info, errorMessage);
244             if (error != ApiResult::OK)
245                 return error;
246 
247             ByteStreamInfo rawStreamInfo = FromByteArray(uncompressedData, uncompressedLength);
248 
249             VerifyInput(rawStreamInfo, info);
250 
251             JpegStreamWriter writer;
252             if (info.jfif.version)
253             {
254                 writer.AddSegment(JpegMarkerSegment::CreateJpegFileInterchangeFormatSegment(info.jfif));
255             }
256 
257             writer.AddSegment(JpegMarkerSegment::CreateStartOfFrameSegment(info.width, info.height, info.bitsPerSample, info.components));
258 
259             if (info.interleaveMode == InterleaveMode::None)
260             {
261                 int32_t fieldLength = info.width * info.height * ((info.bitsPerSample + 7) / 8);
262                 for (int32_t component = 0; component < info.components; ++component)
263                 {
264                     writer.AddScan(rawStreamInfo, info);
265                     SkipBytes(rawStreamInfo, fieldLength);
266                 }
267             }
268             else
269             {
270                 writer.AddScan(rawStreamInfo, info);
271             }
272 
273             vector<uint8_t> rgbyteCompressed(compressedLength + 16);
274 
275             memcpy(&rgbyteCompressed[0], compressedData, compressedLength);
276 
277             writer.EnableCompare(true);
278             writer.Write(FromByteArray(&rgbyteCompressed[0], rgbyteCompressed.size()));
279             ClearErrorMessage(errorMessage);
280             return ApiResult::OK;
281         }
282         catch (const system_error& e)
283         {
284             CopyWhatTextToErrorMessage(e, errorMessage);
285             return SystemErrorToCharLSError(e);
286         }
287         catch (...)
288         {
289             ClearErrorMessage(errorMessage);
290             return ApiResult::UnexpectedFailure;
291         }
292     }
293 
294 
JpegLsDecodeRect(void * uncompressedData,size_t uncompressedLength,const void * compressedData,size_t compressedLength,JlsRect roi,JlsParameters * info,char * errorMessage)295     CHARLS_IMEXPORT(ApiResult) JpegLsDecodeRect(void* uncompressedData, size_t uncompressedLength, const void* compressedData, size_t compressedLength,
296         JlsRect roi, JlsParameters* info, char* errorMessage)
297     {
298         try
299         {
300             ByteStreamInfo compressedStream = FromByteArray(compressedData, compressedLength);
301             JpegStreamReader reader(compressedStream);
302 
303             ByteStreamInfo rawStreamInfo = FromByteArray(uncompressedData, uncompressedLength);
304 
305             if (info)
306             {
307                 reader.SetInfo(*info);
308             }
309 
310             reader.SetRect(roi);
311             reader.Read(rawStreamInfo);
312 
313             ClearErrorMessage(errorMessage);
314             return ApiResult::OK;
315         }
316         catch (const system_error& e)
317         {
318             CopyWhatTextToErrorMessage(e, errorMessage);
319             return SystemErrorToCharLSError(e);
320         }
321         catch (...)
322         {
323             ClearErrorMessage(errorMessage);
324             return ApiResult::UnexpectedFailure;
325         }
326     }
327 }
328