mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-15 04:24:28 +00:00
jpg_loader: support multi-thread and header reading in prior to decoding.
revise the code to support async loading of the static jpeg_loader, also support header reading in prior to decoding.
This commit is contained in:
parent
babb10b7f3
commit
a4494919ac
6 changed files with 135 additions and 76 deletions
|
@ -20,7 +20,7 @@
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "tvgJpgd.h"
|
#include <memory.h>
|
||||||
#include "tvgLoader.h"
|
#include "tvgLoader.h"
|
||||||
#include "tvgJpgLoader.h"
|
#include "tvgJpgLoader.h"
|
||||||
|
|
||||||
|
@ -28,6 +28,15 @@
|
||||||
/* Internal Class Implementation */
|
/* Internal Class Implementation */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
||||||
|
void JpgLoader::clear()
|
||||||
|
{
|
||||||
|
jpgdDelete(decoder);
|
||||||
|
if (freeData) free(data);
|
||||||
|
decoder = nullptr;
|
||||||
|
data = nullptr;
|
||||||
|
freeData = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
/* External Class Implementation */
|
/* External Class Implementation */
|
||||||
|
@ -36,48 +45,79 @@
|
||||||
|
|
||||||
JpgLoader::~JpgLoader()
|
JpgLoader::~JpgLoader()
|
||||||
{
|
{
|
||||||
free(image);
|
jpgdDelete(decoder);
|
||||||
image = NULL;
|
if (freeData) free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool JpgLoader::open(const string& path)
|
bool JpgLoader::open(const string& path)
|
||||||
{
|
{
|
||||||
int width, height, actual_comps;
|
clear();
|
||||||
image = decompress_jpeg_image_from_file(path.c_str(), &width, &height, &actual_comps, 4);
|
|
||||||
if (!image) return false;
|
|
||||||
|
|
||||||
vw = w = static_cast<float>(width);
|
int width, height;
|
||||||
vh = h = static_cast<float>(height);
|
decoder = jpgdHeader(path.c_str(), &width, &height);
|
||||||
|
if (!decoder) return false;
|
||||||
|
|
||||||
|
w = static_cast<float>(width);
|
||||||
|
h = static_cast<float>(height);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool JpgLoader::open(const char* data, uint32_t size, bool copy)
|
bool JpgLoader::open(const char* data, uint32_t size, bool copy)
|
||||||
{
|
{
|
||||||
int width, height, actual_comps;
|
clear();
|
||||||
image = decompress_jpeg_image_from_memory((const unsigned char *)data, size, &width, &height, &actual_comps, 4);
|
|
||||||
if (!image) return false;
|
|
||||||
|
|
||||||
vw = w = static_cast<float>(width);
|
if (copy) {
|
||||||
vh = h = static_cast<float>(height);
|
this->data = (char *) malloc(size);
|
||||||
|
if (!this->data) return false;
|
||||||
|
memcpy((char *)this->data, data, size);
|
||||||
|
freeData = true;
|
||||||
|
} else {
|
||||||
|
this->data = (char *) data;
|
||||||
|
freeData = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int width, height;
|
||||||
|
decoder = jpgdHeader(this->data, size, &width, &height);
|
||||||
|
if (!decoder) return false;
|
||||||
|
|
||||||
|
w = static_cast<float>(width);
|
||||||
|
h = static_cast<float>(height);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool JpgLoader::read()
|
bool JpgLoader::read()
|
||||||
{
|
{
|
||||||
|
if (!decoder || w <= 0 || h <= 0) return false;
|
||||||
|
|
||||||
|
TaskScheduler::request(this);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool JpgLoader::close()
|
bool JpgLoader::close()
|
||||||
{
|
{
|
||||||
|
this->done();
|
||||||
|
clear();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const uint32_t* JpgLoader::pixels()
|
const uint32_t* JpgLoader::pixels()
|
||||||
{
|
{
|
||||||
|
this->done();
|
||||||
|
|
||||||
return (const uint32_t*)image;
|
return (const uint32_t*)image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void JpgLoader::run(unsigned tid)
|
||||||
|
{
|
||||||
|
image = jpgdDecompress(decoder);
|
||||||
|
}
|
|
@ -22,9 +22,19 @@
|
||||||
#ifndef _TVG_JPG_LOADER_H_
|
#ifndef _TVG_JPG_LOADER_H_
|
||||||
#define _TVG_JPG_LOADER_H_
|
#define _TVG_JPG_LOADER_H_
|
||||||
|
|
||||||
//TODO: Use Task?
|
#include "tvgTaskScheduler.h"
|
||||||
class JpgLoader : public LoadModule
|
#include "tvgJpgd.h"
|
||||||
|
|
||||||
|
class JpgLoader : public LoadModule, public Task
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
jpeg_decoder* decoder = nullptr;
|
||||||
|
char* data = nullptr;
|
||||||
|
unsigned char *image = nullptr;
|
||||||
|
bool freeData = false;
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~JpgLoader();
|
~JpgLoader();
|
||||||
|
|
||||||
|
@ -35,9 +45,7 @@ public:
|
||||||
bool close() override;
|
bool close() override;
|
||||||
|
|
||||||
const uint32_t* pixels() override;
|
const uint32_t* pixels() override;
|
||||||
|
void run(unsigned tid) override;
|
||||||
private:
|
|
||||||
unsigned char *image = nullptr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //_TVG_JPG_LOADER_H_
|
#endif //_TVG_JPG_LOADER_H_
|
||||||
|
|
|
@ -110,11 +110,12 @@ class jpeg_decoder_file_stream : public jpeg_decoder_stream
|
||||||
jpeg_decoder_file_stream(const jpeg_decoder_file_stream &);
|
jpeg_decoder_file_stream(const jpeg_decoder_file_stream &);
|
||||||
jpeg_decoder_file_stream &operator =(const jpeg_decoder_file_stream &);
|
jpeg_decoder_file_stream &operator =(const jpeg_decoder_file_stream &);
|
||||||
|
|
||||||
FILE *m_pFile;
|
FILE *m_pFile = nullptr;
|
||||||
bool m_eof_flag, m_error_flag;
|
bool m_eof_flag = false;
|
||||||
|
bool m_error_flag = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
jpeg_decoder_file_stream();
|
jpeg_decoder_file_stream() {}
|
||||||
virtual ~jpeg_decoder_file_stream();
|
virtual ~jpeg_decoder_file_stream();
|
||||||
bool open(const char *Pfilename);
|
bool open(const char *Pfilename);
|
||||||
void close();
|
void close();
|
||||||
|
@ -2814,14 +2815,7 @@ int jpeg_decoder::begin_decoding()
|
||||||
jpeg_decoder::~jpeg_decoder()
|
jpeg_decoder::~jpeg_decoder()
|
||||||
{
|
{
|
||||||
free_all_blocks();
|
free_all_blocks();
|
||||||
}
|
delete(m_pStream);
|
||||||
|
|
||||||
|
|
||||||
jpeg_decoder_file_stream::jpeg_decoder_file_stream()
|
|
||||||
{
|
|
||||||
m_pFile = nullptr;
|
|
||||||
m_eof_flag = false;
|
|
||||||
m_error_flag = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2910,23 +2904,62 @@ int jpeg_decoder_mem_stream::read(uint8_t *pBuf, int max_bytes_to_read, bool *pE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned char *decompress_jpeg_image_from_stream(jpeg_decoder_stream *pStream, int *width, int *height, int *actual_comps, int req_comps)
|
/************************************************************************/
|
||||||
{
|
/* External Class Implementation */
|
||||||
if (!actual_comps) return nullptr;
|
/************************************************************************/
|
||||||
*actual_comps = 0;
|
|
||||||
|
|
||||||
if ((!pStream) || (!width) || (!height) || (!req_comps)) return nullptr;
|
|
||||||
|
jpeg_decoder* jpgdHeader(const char* data, int size, int* width, int* height)
|
||||||
|
{
|
||||||
|
auto decoder = new jpeg_decoder(new jpeg_decoder_mem_stream((const uint8_t*)data, size));
|
||||||
|
if (decoder->get_error_code() != JPGD_SUCCESS) {
|
||||||
|
delete(decoder);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width) *width = decoder->get_width();
|
||||||
|
if (height) *height = decoder->get_height();
|
||||||
|
|
||||||
|
return decoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
jpeg_decoder* jpgdHeader(const char* filename, int* width, int* height)
|
||||||
|
{
|
||||||
|
auto fileStream = new jpeg_decoder_file_stream();
|
||||||
|
if (!fileStream->open(filename)) return nullptr;
|
||||||
|
|
||||||
|
auto decoder = new jpeg_decoder(fileStream);
|
||||||
|
if (decoder->get_error_code() != JPGD_SUCCESS) {
|
||||||
|
delete(decoder);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width) *width = decoder->get_width();
|
||||||
|
if (height) *height = decoder->get_height();
|
||||||
|
|
||||||
|
return decoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void jpgdDelete(jpeg_decoder* decoder)
|
||||||
|
{
|
||||||
|
delete(decoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned char* jpgdDecompress(jpeg_decoder* decoder)
|
||||||
|
{
|
||||||
|
if (!decoder) return nullptr;
|
||||||
|
|
||||||
|
int req_comps = 4; //TODO: fixed 4 channel components now?
|
||||||
if ((req_comps != 1) && (req_comps != 3) && (req_comps != 4)) return nullptr;
|
if ((req_comps != 1) && (req_comps != 3) && (req_comps != 4)) return nullptr;
|
||||||
|
|
||||||
jpeg_decoder decoder(pStream);
|
auto image_width = decoder->get_width();
|
||||||
if (decoder.get_error_code() != JPGD_SUCCESS) return nullptr;
|
auto image_height = decoder->get_height();
|
||||||
|
//auto actual_comps = decoder->get_num_components();
|
||||||
|
|
||||||
const int image_width = decoder.get_width(), image_height = decoder.get_height();
|
if (decoder->begin_decoding() != JPGD_SUCCESS) return nullptr;
|
||||||
*width = image_width;
|
|
||||||
*height = image_height;
|
|
||||||
*actual_comps = decoder.get_num_components();
|
|
||||||
|
|
||||||
if (decoder.begin_decoding() != JPGD_SUCCESS) return nullptr;
|
|
||||||
|
|
||||||
const int dst_bpl = image_width * req_comps;
|
const int dst_bpl = image_width * req_comps;
|
||||||
uint8_t *pImage_data = (uint8_t*)malloc(dst_bpl * image_height);
|
uint8_t *pImage_data = (uint8_t*)malloc(dst_bpl * image_height);
|
||||||
|
@ -2935,7 +2968,7 @@ unsigned char *decompress_jpeg_image_from_stream(jpeg_decoder_stream *pStream, i
|
||||||
for (int y = 0; y < image_height; y++) {
|
for (int y = 0; y < image_height; y++) {
|
||||||
const uint8_t* pScan_line;
|
const uint8_t* pScan_line;
|
||||||
uint32_t scan_line_len;
|
uint32_t scan_line_len;
|
||||||
if (decoder.decode((const void**)&pScan_line, &scan_line_len) != JPGD_SUCCESS) {
|
if (decoder->decode((const void**)&pScan_line, &scan_line_len) != JPGD_SUCCESS) {
|
||||||
free(pImage_data);
|
free(pImage_data);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -2943,17 +2976,17 @@ unsigned char *decompress_jpeg_image_from_stream(jpeg_decoder_stream *pStream, i
|
||||||
uint8_t *pDst = pImage_data + y * dst_bpl;
|
uint8_t *pDst = pImage_data + y * dst_bpl;
|
||||||
|
|
||||||
//Return as BGRA
|
//Return as BGRA
|
||||||
if ((req_comps == 4) && (decoder.get_num_components() == 3)) {
|
if ((req_comps == 4) && (decoder->get_num_components() == 3)) {
|
||||||
for (int x = 0; x < image_width; x++) {
|
for (int x = 0; x < image_width; x++) {
|
||||||
pDst[0] = pScan_line[x*4+2];
|
pDst[0] = pScan_line[x*4+2];
|
||||||
pDst[1] = pScan_line[x*4+1];
|
pDst[1] = pScan_line[x*4+1];
|
||||||
pDst[2] = pScan_line[x*4+0];
|
pDst[2] = pScan_line[x*4+0];
|
||||||
pDst[3] = 255;
|
pDst[3] = 255;
|
||||||
pDst += 4;
|
pDst += 4;
|
||||||
}
|
}
|
||||||
} else if (((req_comps == 1) && (decoder.get_num_components() == 1)) || ((req_comps == 4) && (decoder.get_num_components() == 3))) {
|
} else if (((req_comps == 1) && (decoder->get_num_components() == 1)) || ((req_comps == 4) && (decoder->get_num_components() == 3))) {
|
||||||
memcpy(pDst, pScan_line, dst_bpl);
|
memcpy(pDst, pScan_line, dst_bpl);
|
||||||
} else if (decoder.get_num_components() == 1) {
|
} else if (decoder->get_num_components() == 1) {
|
||||||
if (req_comps == 3) {
|
if (req_comps == 3) {
|
||||||
for (int x = 0; x < image_width; x++) {
|
for (int x = 0; x < image_width; x++) {
|
||||||
uint8_t luma = pScan_line[x];
|
uint8_t luma = pScan_line[x];
|
||||||
|
@ -2972,7 +3005,7 @@ unsigned char *decompress_jpeg_image_from_stream(jpeg_decoder_stream *pStream, i
|
||||||
pDst += 4;
|
pDst += 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (decoder.get_num_components() == 3) {
|
} else if (decoder->get_num_components() == 3) {
|
||||||
if (req_comps == 1) {
|
if (req_comps == 1) {
|
||||||
const int YR = 19595, YG = 38470, YB = 7471;
|
const int YR = 19595, YG = 38470, YB = 7471;
|
||||||
for (int x = 0; x < image_width; x++) {
|
for (int x = 0; x < image_width; x++) {
|
||||||
|
@ -2992,23 +3025,4 @@ unsigned char *decompress_jpeg_image_from_stream(jpeg_decoder_stream *pStream, i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return pImage_data;
|
return pImage_data;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/************************************************************************/
|
|
||||||
/* External Class Implementation */
|
|
||||||
/************************************************************************/
|
|
||||||
|
|
||||||
unsigned char *decompress_jpeg_image_from_memory(const unsigned char *pSrc_data, int src_data_size, int *width, int *height, int *actual_comps, int req_comps)
|
|
||||||
{
|
|
||||||
jpeg_decoder_mem_stream mem_stream(pSrc_data, src_data_size);
|
|
||||||
return decompress_jpeg_image_from_stream(&mem_stream, width, height, actual_comps, req_comps);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
unsigned char *decompress_jpeg_image_from_file(const char *pSrc_filename, int *width, int *height, int *actual_comps, int req_comps)
|
|
||||||
{
|
|
||||||
jpeg_decoder_file_stream file_stream;
|
|
||||||
if (!file_stream.open(pSrc_filename)) return nullptr;
|
|
||||||
return decompress_jpeg_image_from_stream(&file_stream, width, height, actual_comps, req_comps);
|
|
||||||
}
|
}
|
|
@ -25,12 +25,11 @@
|
||||||
#ifndef _TVG_JPGD_H_
|
#ifndef _TVG_JPGD_H_
|
||||||
#define _TVG_JPGD_H_
|
#define _TVG_JPGD_H_
|
||||||
|
|
||||||
// Loads a JPEG image from a memory buffer or a file.
|
class jpeg_decoder;
|
||||||
// req_comps can be 1 (grayscale), 3 (RGB), or 4 (RGBA).
|
|
||||||
// On return, width/height will be set to the image's dimensions, and actual_comps will be set to the either 1 (grayscale) or 3 (RGB).
|
jpeg_decoder* jpgdHeader(const char* data, int size, int* width, int* height);
|
||||||
// Notes: For more control over where and how the source data is read, see the decompress_jpeg_image_from_stream() function below, or call the jpeg_decoder class directly.
|
jpeg_decoder* jpgdHeader(const char* filename, int* width, int* height);
|
||||||
// Requesting a 8 or 32bpp image is currently a little faster than 24bpp because the jpeg_decoder class itself currently always unpacks to either 8 or 32bpp.
|
unsigned char* jpgdDecompress(jpeg_decoder* decoder);
|
||||||
unsigned char *decompress_jpeg_image_from_memory(const unsigned char *pSrc_data, int src_data_size, int *width, int *height, int *actual_comps, int req_comps);
|
void jpgdDelete(jpeg_decoder* decoder);
|
||||||
unsigned char *decompress_jpeg_image_from_file(const char *pSrc_filename, int *width, int *height, int *actual_comps, int req_comps);
|
|
||||||
|
|
||||||
#endif //_TVG_JPGD_H_
|
#endif //_TVG_JPGD_H_
|
||||||
|
|
|
@ -136,7 +136,6 @@ bool PngLoader::read()
|
||||||
bool PngLoader::close()
|
bool PngLoader::close()
|
||||||
{
|
{
|
||||||
this->done();
|
this->done();
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,6 @@ public:
|
||||||
bool close() override;
|
bool close() override;
|
||||||
|
|
||||||
const uint32_t* pixels() override;
|
const uint32_t* pixels() override;
|
||||||
|
|
||||||
void run(unsigned tid) override;
|
void run(unsigned tid) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue