From 0435f29f11c0c5c01aa43b6b8594e29f835f7b44 Mon Sep 17 00:00:00 2001 From: Michal Maciola Date: Fri, 2 Jul 2021 09:23:57 +0200 Subject: [PATCH] jpg_loader: introduced jpg decode using libjpeg-turbo This patch introduces a jpg loader. For decoding the image, libjpeg-turbo library is used. Library was found to be fast (SIMD instructions accelerated) and portable. @issue: #517 --- meson.build | 4 ++ meson_options.txt | 2 +- src/lib/tvgLoaderMgr.cpp | 15 +++++ src/lib/tvgLoaderMgr.h | 2 +- src/loaders/jpg/meson.build | 18 ++++++ src/loaders/jpg/tvgJpgLoader.cpp | 102 +++++++++++++++++++++++++++++++ src/loaders/jpg/tvgJpgLoader.h | 47 ++++++++++++++ src/loaders/meson.build | 5 ++ 8 files changed, 193 insertions(+), 2 deletions(-) create mode 100755 src/loaders/jpg/meson.build create mode 100755 src/loaders/jpg/tvgJpgLoader.cpp create mode 100755 src/loaders/jpg/tvgJpgLoader.h diff --git a/meson.build b/meson.build index 294dbf3e..7e56c4cf 100644 --- a/meson.build +++ b/meson.build @@ -28,6 +28,10 @@ if get_option('loaders').contains('png') == true config_h.set10('THORVG_PNG_LOADER_SUPPORT', true) endif +if get_option('loaders').contains('jpg') == true + config_h.set10('THORVG_JPG_LOADER_SUPPORT', true) +endif + if get_option('vectors').contains('avx') == true config_h.set10('THORVG_AVX_VECTOR_SUPPORT', true) endif diff --git a/meson_options.txt b/meson_options.txt index 66304c0f..d09b6b3f 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -6,7 +6,7 @@ option('engines', option('loaders', type: 'array', - choices: ['', 'svg', 'tvg', 'png'], + choices: ['', 'svg', 'tvg', 'png', 'jpg'], value: ['svg'], description: 'Enable File Loaders in thorvg') diff --git a/src/lib/tvgLoaderMgr.cpp b/src/lib/tvgLoaderMgr.cpp index c55553b5..d0fa6186 100644 --- a/src/lib/tvgLoaderMgr.cpp +++ b/src/lib/tvgLoaderMgr.cpp @@ -33,6 +33,10 @@ #include "tvgTvgLoader.h" #endif +#ifdef THORVG_JPG_LOADER_SUPPORT + #include "tvgJpgLoader.h" +#endif + #include "tvgRawLoader.h" /************************************************************************/ @@ -61,6 +65,12 @@ static Loader* _find(FileType type) case FileType::Tvg: { #ifdef THORVG_TVG_LOADER_SUPPORT return new TvgLoader; +#endif + break; + } + case FileType::Jpg: { +#ifdef THORVG_JPG_LOADER_SUPPORT + return new JpgLoader; #endif break; } @@ -88,6 +98,10 @@ static Loader* _find(FileType type) format = "TVG"; break; } + case FileType::Jpg: { + format = "JPG"; + break; + } default: { format = "???"; break; @@ -106,6 +120,7 @@ static Loader* _find(const string& path) if (!ext.compare("svg")) return _find(FileType::Svg); if (!ext.compare("png")) return _find(FileType::Png); if (!ext.compare("tvg")) return _find(FileType::Tvg); + if (!ext.compare("jpg")) return _find(FileType::Jpg); return nullptr; } diff --git a/src/lib/tvgLoaderMgr.h b/src/lib/tvgLoaderMgr.h index 665bf2f9..18a8e8ae 100644 --- a/src/lib/tvgLoaderMgr.h +++ b/src/lib/tvgLoaderMgr.h @@ -24,7 +24,7 @@ #include "tvgLoader.h" -enum class FileType { Tvg = 0, Svg, Raw, Png, Unknown }; +enum class FileType { Tvg = 0, Svg, Raw, Png, Jpg, Unknown }; struct LoaderMgr { diff --git a/src/loaders/jpg/meson.build b/src/loaders/jpg/meson.build new file mode 100755 index 00000000..f76d03f3 --- /dev/null +++ b/src/loaders/jpg/meson.build @@ -0,0 +1,18 @@ +source_file = [ + 'tvgJpgLoader.h', + 'tvgJpgLoader.cpp', +] + +jpg_dep = dependency('libturbojpeg', required: false) +if not jpg_dep.found() + jpg_dep = cc.find_library('turbojpeg', required: false) +endif +if not jpg_dep.found() + error('JPEG image loading requires libturbojpeg or turbojpeg, neither was found.') +endif + +subloader_dep += [declare_dependency( + include_directories : include_directories('.'), + dependencies : jpg_dep, + sources : source_file +)] diff --git a/src/loaders/jpg/tvgJpgLoader.cpp b/src/loaders/jpg/tvgJpgLoader.cpp new file mode 100755 index 00000000..09cac89b --- /dev/null +++ b/src/loaders/jpg/tvgJpgLoader.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "tvgLoaderMgr.h" +#include "tvgJpgLoader.h" + +JpgLoader::JpgLoader() +{ + jpegDecompressor = tjInitDecompress(); +} + +JpgLoader::~JpgLoader() +{ + tjDestroy(jpegDecompressor); + tjFree(image); + image = NULL; +} + +bool JpgLoader::open(const string& path) +{ + bool success = false; + FILE *jpegFile = NULL; + if ((jpegFile = fopen(path.c_str(), "rb")) == NULL) return false; + + //determine size + if (fseek(jpegFile, 0, SEEK_END) < 0) goto finalize; + if (((size = ftell(jpegFile)) < 1)) goto finalize; + if (fseek(jpegFile, 0, SEEK_SET)) goto finalize; + + if (data) tjFree(data); + data = (unsigned char *) tjAlloc(size); + if (!data) goto finalize; + + if (fread(data, size, 1, jpegFile) < 1) goto failure; + + success = true; + goto finalize; + +failure: + tjFree(data); + data = NULL; + +finalize: + fclose(jpegFile); + return success; +} + +bool JpgLoader::read() +{ + int width, height; + + //decompress header + int inSubsamp, inColorspace; + if (tjDecompressHeader3(jpegDecompressor, data, size, &width, &height, &inSubsamp, &inColorspace) < 0) return false; + + //alloc image buffer + if (image) tjFree(image); + image = (unsigned char *)tjAlloc(width * height * tjPixelSize[TJPF_BGRX]); + if (!image) return false; + + //decompress jpg image + if (tjDecompress2(jpegDecompressor, data, size, image, width, 0, height, TJPF_BGRX, 0) < 0) { + tjFree(image); + data = NULL; + return false; + } + + vw = w = width; + vh = h = height; + return true; +} + +bool JpgLoader::close() +{ + tjFree(data); + data = NULL; + return true; +} + +const uint32_t* JpgLoader::pixels() +{ + return (const uint32_t*)image; +} diff --git a/src/loaders/jpg/tvgJpgLoader.h b/src/loaders/jpg/tvgJpgLoader.h new file mode 100755 index 00000000..ba17b879 --- /dev/null +++ b/src/loaders/jpg/tvgJpgLoader.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef _TVG_JPG_LOADER_H_ +#define _TVG_JPG_LOADER_H_ + +#include + +class JpgLoader : public Loader +{ +public: + JpgLoader(); + ~JpgLoader(); + + using Loader::open; + bool open(const string& path) override; + bool read() override; + bool close() override; + + const uint32_t* pixels() override; + +private: + tjhandle jpegDecompressor; + unsigned char* data = nullptr; + unsigned long size = 0; + unsigned char *image = nullptr; +}; + +#endif //_TVG_JPG_LOADER_H_ diff --git a/src/loaders/meson.build b/src/loaders/meson.build index f2e5b550..0e580b9f 100644 --- a/src/loaders/meson.build +++ b/src/loaders/meson.build @@ -12,6 +12,11 @@ if get_option('loaders').contains('tvg') == true subdir('tvg') endif +if get_option('loaders').contains('jpg') == true + subdir('jpg') + message('Enable JPG Loader') +endif + subdir('raw') loader_dep = declare_dependency(