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