// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #include "charls.h" #include "util.h" #include "jpegstreamreader.h" #include "jpegstreamwriter.h" #include "jpegmarkersegment.h" #include using namespace std; using namespace charls; static void VerifyInput(const ByteStreamInfo& uncompressedStream, const JlsParameters& parameters) { if (!uncompressedStream.rawStream && !uncompressedStream.rawData) throw CreateSystemError(ApiResult::InvalidJlsParameters, "rawStream or rawData needs to reference to something"); if (parameters.width < 1 || parameters.width > 65535) throw CreateSystemError(ApiResult::InvalidJlsParameters, "width needs to be in the range [1, 65535]"); if (parameters.height < 1 || parameters.height > 65535) throw CreateSystemError(ApiResult::InvalidJlsParameters, "height needs to be in the range [1, 65535]"); if (parameters.bitsPerSample < 2 || parameters.bitsPerSample > 16) throw CreateSystemError(ApiResult::InvalidJlsParameters, "bitspersample needs to be in the range [2, 16]"); if (!(parameters.interleaveMode == InterleaveMode::None || parameters.interleaveMode == InterleaveMode::Sample || parameters.interleaveMode == InterleaveMode::Line)) throw CreateSystemError(ApiResult::InvalidJlsParameters, "interleaveMode needs to be set to a value of {None, Sample, Line}"); if (parameters.components < 1 || parameters.components > 255) throw CreateSystemError(ApiResult::InvalidJlsParameters, "components needs to be in the range [1, 255]"); if (uncompressedStream.rawData) { if (uncompressedStream.count < size_t(parameters.height * parameters.width * parameters.components * (parameters.bitsPerSample > 8 ? 2 : 1))) throw CreateSystemError(ApiResult::InvalidJlsParameters, "uncompressed size does not match with the other parameters"); } switch (parameters.components) { case 3: break; case 4: if (parameters.interleaveMode == InterleaveMode::Sample) throw CreateSystemError(ApiResult::InvalidJlsParameters, "interleaveMode cannot be set to Sample in combination with components = 4"); break; default: if (parameters.interleaveMode != InterleaveMode::None) throw CreateSystemError(ApiResult::InvalidJlsParameters, "interleaveMode can only be set to None in combination with components = 1"); break; } } static ApiResult SystemErrorToCharLSError(const system_error& e) { return e.code().category() == CharLSCategoryInstance() ? static_cast(e.code().value()) : ApiResult::UnspecifiedFailure; } static void ClearErrorMessage(char* errorMessage) { if (errorMessage) { errorMessage[0] = 0; } } static void CopyWhatTextToErrorMessage(const system_error& e, char* errorMessage) { if (!errorMessage) return; if (e.code().category() == CharLSCategoryInstance()) { ASSERT(strlen(e.what()) < ErrorMessageSize); strcpy(errorMessage, e.what()); } else { errorMessage[0] = 0; } } CHARLS_IMEXPORT(ApiResult) JpegLsEncodeStream(ByteStreamInfo compressedStreamInfo, size_t& pcbyteWritten, ByteStreamInfo rawStreamInfo, const struct JlsParameters& params, char* errorMessage) { try { VerifyInput(rawStreamInfo, params); JlsParameters info = params; if (info.stride == 0) { info.stride = info.width * ((info.bitsPerSample + 7)/8); if (info.interleaveMode != InterleaveMode::None) { info.stride *= info.components; } } JpegStreamWriter writer; if (info.jfif.version) { writer.AddSegment(JpegMarkerSegment::CreateJpegFileInterchangeFormatSegment(info.jfif)); } writer.AddSegment(JpegMarkerSegment::CreateStartOfFrameSegment(info.width, info.height, info.bitsPerSample, info.components)); if (info.colorTransformation != ColorTransformation::None) { writer.AddColorTransform(info.colorTransformation); } if (info.interleaveMode == InterleaveMode::None) { int32_t cbyteComp = info.width * info.height * ((info.bitsPerSample + 7) / 8); for (int32_t component = 0; component < info.components; ++component) { writer.AddScan(rawStreamInfo, info); SkipBytes(rawStreamInfo, cbyteComp); } } else { writer.AddScan(rawStreamInfo, info); } writer.Write(compressedStreamInfo); pcbyteWritten = writer.GetBytesWritten(); ClearErrorMessage(errorMessage); return ApiResult::OK; } catch (const system_error& e) { CopyWhatTextToErrorMessage(e, errorMessage); return SystemErrorToCharLSError(e); } catch (...) { ClearErrorMessage(errorMessage); return ApiResult::UnexpectedFailure; } } CHARLS_IMEXPORT(ApiResult) JpegLsDecodeStream(ByteStreamInfo rawStream, ByteStreamInfo compressedStream, const JlsParameters* info, char* errorMessage) { try { JpegStreamReader reader(compressedStream); if (info) { reader.SetInfo(*info); } reader.Read(rawStream); ClearErrorMessage(errorMessage); return ApiResult::OK; } catch (const system_error& e) { CopyWhatTextToErrorMessage(e, errorMessage); return SystemErrorToCharLSError(e); } catch (...) { ClearErrorMessage(errorMessage); return ApiResult::UnexpectedFailure; } } CHARLS_IMEXPORT(ApiResult) JpegLsReadHeaderStream(ByteStreamInfo rawStreamInfo, JlsParameters* params, char* errorMessage) { try { JpegStreamReader reader(rawStreamInfo); reader.ReadHeader(); reader.ReadStartOfScan(true); *params = reader.GetMetadata(); ClearErrorMessage(errorMessage); return ApiResult::OK; } catch (const std::system_error& e) { CopyWhatTextToErrorMessage(e, errorMessage); return SystemErrorToCharLSError(e); } catch (...) { ClearErrorMessage(errorMessage); return ApiResult::UnexpectedFailure; } } extern "C" { CHARLS_IMEXPORT(ApiResult) JpegLsEncode(void* destination, size_t destinationLength, size_t* bytesWritten, const void* source, size_t sourceLength, const struct JlsParameters* params, char* errorMessage) { if (!destination || !bytesWritten || !source || !params) return ApiResult::InvalidJlsParameters; ByteStreamInfo rawStreamInfo = FromByteArray(source, sourceLength); ByteStreamInfo compressedStreamInfo = FromByteArray(destination, destinationLength); return JpegLsEncodeStream(compressedStreamInfo, *bytesWritten, rawStreamInfo, *params, errorMessage); } CHARLS_IMEXPORT(ApiResult) JpegLsReadHeader(const void* compressedData, size_t compressedLength, JlsParameters* params, char* errorMessage) { return JpegLsReadHeaderStream(FromByteArray(compressedData, compressedLength), params, errorMessage); } CHARLS_IMEXPORT(ApiResult) JpegLsDecode(void* destination, size_t destinationLength, const void* source, size_t sourceLength, const struct JlsParameters* params, char* errorMessage) { ByteStreamInfo compressedStream = FromByteArray(source, sourceLength); ByteStreamInfo rawStreamInfo = FromByteArray(destination, destinationLength); return JpegLsDecodeStream(rawStreamInfo, compressedStream, params, errorMessage); } CHARLS_IMEXPORT(ApiResult) JpegLsVerifyEncode(const void* uncompressedData, size_t uncompressedLength, const void* compressedData, size_t compressedLength, char* errorMessage) { try { JlsParameters info = JlsParameters(); auto error = JpegLsReadHeader(compressedData, compressedLength, &info, errorMessage); if (error != ApiResult::OK) return error; ByteStreamInfo rawStreamInfo = FromByteArray(uncompressedData, uncompressedLength); VerifyInput(rawStreamInfo, info); JpegStreamWriter writer; if (info.jfif.version) { writer.AddSegment(JpegMarkerSegment::CreateJpegFileInterchangeFormatSegment(info.jfif)); } writer.AddSegment(JpegMarkerSegment::CreateStartOfFrameSegment(info.width, info.height, info.bitsPerSample, info.components)); if (info.interleaveMode == InterleaveMode::None) { int32_t fieldLength = info.width * info.height * ((info.bitsPerSample + 7) / 8); for (int32_t component = 0; component < info.components; ++component) { writer.AddScan(rawStreamInfo, info); SkipBytes(rawStreamInfo, fieldLength); } } else { writer.AddScan(rawStreamInfo, info); } vector rgbyteCompressed(compressedLength + 16); memcpy(&rgbyteCompressed[0], compressedData, compressedLength); writer.EnableCompare(true); writer.Write(FromByteArray(&rgbyteCompressed[0], rgbyteCompressed.size())); ClearErrorMessage(errorMessage); return ApiResult::OK; } catch (const system_error& e) { CopyWhatTextToErrorMessage(e, errorMessage); return SystemErrorToCharLSError(e); } catch (...) { ClearErrorMessage(errorMessage); return ApiResult::UnexpectedFailure; } } CHARLS_IMEXPORT(ApiResult) JpegLsDecodeRect(void* uncompressedData, size_t uncompressedLength, const void* compressedData, size_t compressedLength, JlsRect roi, JlsParameters* info, char* errorMessage) { try { ByteStreamInfo compressedStream = FromByteArray(compressedData, compressedLength); JpegStreamReader reader(compressedStream); ByteStreamInfo rawStreamInfo = FromByteArray(uncompressedData, uncompressedLength); if (info) { reader.SetInfo(*info); } reader.SetRect(roi); reader.Read(rawStreamInfo); ClearErrorMessage(errorMessage); return ApiResult::OK; } catch (const system_error& e) { CopyWhatTextToErrorMessage(e, errorMessage); return SystemErrorToCharLSError(e); } catch (...) { ClearErrorMessage(errorMessage); return ApiResult::UnexpectedFailure; } } }