windows 10上源码编译libjpeg-turbo和使用教程 | compile and use libjpeg-turbo on windows 10
本文首发于个人博客https://kezunlin.me/post/83828674/,欢迎阅读!
compile and use libjpeg-turbo on windows 10
Series
Guide
build requirements
Build Requirements
- cmake 2.8
- NASM 2.13
- Visual Studio 2015
- libjpeg-turbo 1.5.4
(1) If using
NASM
, 2.05 or later is required for an x86-64 build.
(2)
nasm.exe/yasm.exe
should be in your PATH.
download
git clone https://github.com/libjpeg-turbo/libjpeg-turbo.git
# or
wget https://codeload.github.com/libjpeg-turbo/libjpeg-turbo/zip/master
install nasm
wget http://www.nasm.us/pub/nasm/releasebuilds/2.13.03rc1/win64/nasm-2.13.03rc1-installer-x64.exe
add C:\Program Files\NASM
to env path.
compile libjpeg
cmake-gui
CMAKE_BUILD_TYPE = Release
ENABLE_SHARED = ON
CMAKE_INSTALL_PREFIX = d:/libjpeg-turbo64
NASM = C:/Program Files/NASM/nasm.exe
configure and generate sln
, compile with visual studio 2015
and install.
usage with cmake
libjpegturbo-config.cmake
set(LIBJPEGTURBO_FOUND TRUE) # auto
set(LIBJPEGTURBO_ROOT_DIR "d:/libjpeg-turbo64")
find_path(LIBJPEGTURBO_INCLUDE_DIR NAMES jpeglib.h turbojpeg.h PATHS "${LIBJPEGTURBO_ROOT_DIR}/include")
mark_as_advanced(LIBJPEGTURBO_INCLUDE_DIR) # show entry in cmake-gui
find_library(LIBJPEGTURBO_JPEG_LIBRARY NAMES jpeg.lib PATHS "${LIBJPEGTURBO_ROOT_DIR}/lib")
mark_as_advanced(LIBJPEGTURBO_JPEG_LIBRARY) # show entry in cmake-gui
find_library(LIBJPEGTURBO_TURBOJPEG_LIBRARY NAMES turbojpeg.lib PATHS "${LIBJPEGTURBO_ROOT_DIR}/lib")
mark_as_advanced(LIBJPEGTURBO_TURBOJPEG_LIBRARY) # show entry in cmake-gui
# use xxx_INCLUDE_DIRS and xxx_LIBRARIES in CMakeLists.txt
set(LIBJPEGTURBO_INCLUDE_DIRS ${LIBJPEGTURBO_INCLUDE_DIR} )
set(LIBJPEGTURBO_LIBRARIES ${LIBJPEGTURBO_JPEG_LIBRARY} ${LIBJPEGTURBO_TURBOJPEG_LIBRARY} )
message( "libjpegturbo-config.cmake " ${LIBJPEGTURBO_ROOT_DIR})
CMakeLists.txt
find_package(LIBJPEGTURBO REQUIRED)
include_directories(${LIBJPEGTURBO_INCLUDE_DIRS})
add_executable (example_jpeg
${CMAKE_CURRENT_SOURCE_DIR}/src/example/example_jpeg.cpp
)
target_link_libraries (example_jpeg
${LIBJPEGTURBO_LIBRARIES}
)
add_executable (example_turbojpeg
${CMAKE_CURRENT_SOURCE_DIR}/src/example/example_turbojpeg.cpp
)
target_link_libraries (example_turbojpeg
${LIBJPEGTURBO_LIBRARIES}
)
Example Code
jpeglib vs turbojpeg
jpeglib
- include:
#include "jpeglib.h"
- lib:
jpeg.lib
- dll:
jpeg62.dll
turbojpeg
- include:
#include "turbojpeg.h"
- lib:
turbojpeg.lib
- dll:
turbojpeg.dll
turbojpeg is (3-5x) faster than jpeglib.
jpeglib
#include <iostream>
#include <fstream>
#include <ctime>
#include "jpeglib.h"
typedef unsigned char BYTE;
bool CompressJPEG(
/*IN*/BYTE *src, int width, int height, int depth,
/*OUT*/BYTE **dst, unsigned long *dstLen
)
{
// NOTICE: dst space must be created outside before passing in.
struct jpeg_compress_struct jcs;
struct jpeg_error_mgr jem;
jcs.err = jpeg_std_error(&jem);
jpeg_create_compress(&jcs);
jpeg_mem_dest(&jcs, dst, dstLen);
jcs.image_width = width;
jcs.image_height = height;
jcs.input_components = depth;
jcs.in_color_space = JCS_RGB;
jpeg_set_defaults(&jcs);
jpeg_set_quality(&jcs, 80, true);
jcs.jpeg_color_space = JCS_YCbCr;
jcs.comp_info[0].h_samp_factor = 2;
jcs.comp_info[0].v_samp_factor = 2;
jpeg_start_compress(&jcs, TRUE);
JSAMPROW row_pointer[1];
int row_stride = jcs.image_width*jcs.num_components;
while (jcs.next_scanline<jcs.image_height)
{
row_pointer[0] = &src[jcs.next_scanline*row_stride];
jpeg_write_scanlines(&jcs, row_pointer, 1);
}
jpeg_finish_compress(&jcs);
jpeg_destroy_compress(&jcs);
return true;
}
bool DeompressJPEG(
/*IN*/BYTE *src, unsigned long srcLen,
/*OUT*/BYTE **dst, unsigned long *dstLen, int *width, int *height, int *depth
)
{
// NOTICE: dst space will be created inside.
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
cinfo.err=jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
jpeg_mem_src(&cinfo,src,srcLen);
jpeg_read_header(&cinfo,TRUE);
jpeg_start_decompress(&cinfo);
(*width) = cinfo.output_width;
(*height) = cinfo.output_height;
(*depth) = cinfo.num_components;
(*dstLen) = (*width)*(*height)*(*depth);
BYTE *tmp_dst = new BYTE[*dstLen];
JSAMPROW row_pointer[1];
int row_stride = cinfo.image_width*cinfo.num_components;
while (cinfo.output_scanline<cinfo.output_height)
{
row_pointer[0] = &tmp_dst[cinfo.output_scanline*row_stride];
jpeg_read_scanlines(&cinfo,row_pointer,1);
}
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
*dst = tmp_dst;
return true;
}
void compress_jpeg_to_file(
/*IN*/BYTE *src,int width, int height, int components, int color_space,int quality,
/*OUT*/char *dst_filename
)
{
/* This struct contains the JPEG compression parameters and pointers to
* working space (which is allocated as needed by the JPEG library).
* It is possible to have several such structures, representing multiple
* compression/decompression processes, in existence at once. We refer
* to any one struct (and its associated working data) as a "JPEG object".
*/
struct jpeg_compress_struct cinfo;
/* This struct represents a JPEG error handler. It is declared separately
* because applications often want to supply a specialized error handler
* (see the second half of this file for an example). But here we just
* take the easy way out and use the standard error handler, which will
* print a message on stderr and call exit() if compression fails.
* Note that this struct must live as long as the main JPEG parameter
* struct, to avoid dangling-pointer problems.
*/
struct jpeg_error_mgr jerr;
/* More stuff */
FILE *outfile; /* target file */
JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
int row_stride; /* physical row width in image buffer */
/* Step 1: allocate and initialize JPEG compression object */
/* We have to set up the error handler first, in case the initialization
* step fails. (Unlikely, but it could happen if you are out of memory.)
* This routine fills in the contents of struct jerr, and returns jerr's
* address which we place into the link field in cinfo.
*/
cinfo.err = jpeg_std_error(&jerr);
/* Now we can initialize the JPEG compression object. */
jpeg_create_compress(&cinfo);
/* Step 2: specify data destination (eg, a file) */
/* Note: steps 2 and 3 can be done in either order. */
/* Here we use the library-supplied code to send compressed data to a
* stdio stream. You can also write your own code to do something else.
* VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
* requires it in order to write binary files.
*/
if ((outfile = fopen(dst_filename, "wb")) == NULL) {
fprintf(stderr, "can't open %s\n", dst_filename);
exit(1);
}
jpeg_stdio_dest(&cinfo, outfile);
/* Step 3: set parameters for compression */
/* First we supply a description of the input image.
* Four fields of the cinfo struct must be filled in:
*/
cinfo.image_width = width; /* image width and height, in pixels */
cinfo.image_height = height;
cinfo.input_components = components; /* # of color components per pixel */
cinfo.in_color_space = (J_COLOR_SPACE)color_space; /* colorspace of input image */
/* Now use the library's routine to set default compression parameters.
* (You must set at least cinfo.in_color_space before calling this,
* since the defaults depend on the source color space.)
*/
jpeg_set_defaults(&cinfo);
/* Now you can set any non-default parameters you wish to.
* Here we just illustrate the use of quality (quantization table) scaling:
*/
jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
/* Step 4: Start compressor */
/* TRUE ensures that we will write a complete interchange-JPEG file.
* Pass TRUE unless you are very sure of what you're doing.
*/
jpeg_start_compress(&cinfo, TRUE);
/* Step 5: while (scan lines remain to be written) */
/* jpeg_write_scanlines(...); */
/* Here we use the library's state variable cinfo.next_scanline as the
* loop counter, so that we don't have to keep track ourselves.
* To keep things simple, we pass one scanline per call; you can pass
* more if you wish, though.
*/
row_stride = cinfo.image_width * cinfo.input_components; /* JSAMPLEs per row in image_buffer */
while (cinfo.next_scanline < cinfo.image_height) {
/* jpeg_write_scanlines expects an array of pointers to scanlines.
* Here the array is only one element long, but you could pass
* more than one scanline at a time if that's more convenient.
*/
row_pointer[0] = &src[cinfo.next_scanline * row_stride];
(void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
/* Step 6: Finish compression */
jpeg_finish_compress(&cinfo);
/* After finish_compress, we can close the output file. */
fclose(outfile);
/* Step 7: release JPEG compression object */
/* This is an important step since it will release a good deal of memory. */
jpeg_destroy_compress(&cinfo);
/* And we're done! */
}
void compress_jpeg_to_mem(
/*IN*/BYTE *src,int width, int height, int components, int color_space,int quality,
/*OUT*/BYTE **dst, unsigned long *dstLen
)
{
/* This struct contains the JPEG compression parameters and pointers to
* working space (which is allocated as needed by the JPEG library).
* It is possible to have several such structures, representing multiple
* compression/decompression processes, in existence at once. We refer
* to any one struct (and its associated working data) as a "JPEG object".
*/
struct jpeg_compress_struct cinfo;
/* This struct represents a JPEG error handler. It is declared separately
* because applications often want to supply a specialized error handler
* (see the second half of this file for an example). But here we just
* take the easy way out and use the standard error handler, which will
* print a message on stderr and call exit() if compression fails.
* Note that this struct must live as long as the main JPEG parameter
* struct, to avoid dangling-pointer problems.
*/
struct jpeg_error_mgr jerr;
/* More stuff */
//FILE *outfile; /* target file */
JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
int row_stride; /* physical row width in image buffer */
/* Step 1: allocate and initialize JPEG compression object */
/* We have to set up the error handler first, in case the initialization
* step fails. (Unlikely, but it could happen if you are out of memory.)
* This routine fills in the contents of struct jerr, and returns jerr's
* address which we place into the link field in cinfo.
*/
cinfo.err = jpeg_std_error(&jerr);
/* Now we can initialize the JPEG compression object. */
jpeg_create_compress(&cinfo);
/* Step 2: specify data destination (eg, a file) */
/* Note: steps 2 and 3 can be done in either order. */
//jpeg_stdio_dest(&cinfo, outfile);
jpeg_mem_dest(&cinfo, dst, dstLen);
/* Step 3: set parameters for compression */
/* First we supply a description of the input image.
* Four fields of the cinfo struct must be filled in:
*/
cinfo.image_width = width; /* image width and height, in pixels */
cinfo.image_height = height;
cinfo.input_components = components; /* # of color components per pixel */
cinfo.in_color_space = (J_COLOR_SPACE)color_space; /* colorspace of input image */
/* Now use the library's routine to set default compression parameters.
* (You must set at least cinfo.in_color_space before calling this,
* since the defaults depend on the source color space.)
*/
jpeg_set_defaults(&cinfo);
/* Now you can set any non-default parameters you wish to.
* Here we just illustrate the use of quality (quantization table) scaling:
*/
jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
/* Step 4: Start compressor */
/* TRUE ensures that we will write a complete interchange-JPEG file.
* Pass TRUE unless you are very sure of what you're doing.
*/
jpeg_start_compress(&cinfo, TRUE);
/* Step 5: while (scan lines remain to be written) */
/* jpeg_write_scanlines(...); */
/* Here we use the library's state variable cinfo.next_scanline as the
* loop counter, so that we don't have to keep track ourselves.
* To keep things simple, we pass one scanline per call; you can pass
* more if you wish, though.
*/
row_stride = cinfo.image_width * cinfo.input_components; /* JSAMPLEs per row in image_buffer */
while (cinfo.next_scanline < cinfo.image_height) {
/* jpeg_write_scanlines expects an array of pointers to scanlines.
* Here the array is only one element long, but you could pass
* more than one scanline at a time if that's more convenient.
*/
row_pointer[0] = &src[cinfo.next_scanline * row_stride];
(void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
/* Step 6: Finish compression */
jpeg_finish_compress(&cinfo);
/* After finish_compress, we can close the output file. */
//fclose(outfile);
/* Step 7: release JPEG compression object */
/* This is an important step since it will release a good deal of memory. */
jpeg_destroy_compress(&cinfo);
/* And we're done! */
}
int decompress_jpeg_from_file(
/*IN*/char *src_filename,
/*OUT*/BYTE **dst, unsigned long *dstLen, int *width, int *height, int *components,int *color_space)
{
/* This struct contains the JPEG decompression parameters and pointers to
* working space (which is allocated as needed by the JPEG library).
*/
struct jpeg_decompress_struct cinfo;
/* We use our private extension JPEG error handler.
* Note that this struct must live as long as the main JPEG parameter
* struct, to avoid dangling-pointer problems.
*/
struct jpeg_error_mgr jerr;
/* More stuff */
FILE *infile; /* source file */
int row_stride; /* physical row width in output buffer */
/* In this example we want to open the input file before doing anything else,
* so that the setjmp() error recovery below can assume the file is open.
* VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
* requires it in order to read binary files.
*/
if ((infile = fopen(src_filename, "rb")) == NULL) {
fprintf(stderr, "can't open %s\n", src_filename);
return 0;
}
/* Step 1: allocate and initialize JPEG decompression object */
/* We set up the normal JPEG error routines, then override error_exit. */
cinfo.err = jpeg_std_error(&jerr);
/* Now we can initialize the JPEG decompression object. */
jpeg_create_decompress(&cinfo);
/* Step 2: specify data source (eg, a file) */
jpeg_stdio_src(&cinfo, infile);
/* Step 3: read file parameters with jpeg_read_header() */
(void)jpeg_read_header(&cinfo, TRUE);
/* We can ignore the return value from jpeg_read_header since
* (a) suspension is not possible with the stdio data source, and
* (b) we passed TRUE to reject a tables-only JPEG file as an error.
* See libjpeg.txt for more info.
*/
/* Step 4: set parameters for decompression */
/* In this example, we don't need to change any of the defaults set by
* jpeg_read_header(), so we do nothing here.
*/
/* Step 5: Start decompressor */
(void)jpeg_start_decompress(&cinfo);
/* We can ignore the return value since suspension is not possible
* with the stdio data source.
*/
/* We may need to do some setup of our own at this point before reading
* the data. After jpeg_start_decompress() we have the correct scaled
* output image dimensions available, as well as the output colormap
* if we asked for color quantization.
* In this example, we need to make an output work buffer of the right size.
*/
/* JSAMPLEs per row in output buffer */
row_stride = cinfo.output_width * cinfo.output_components;
/* Make a one-row-high sample array that will go away when done with image */
/* Set output fields */
(*width) = cinfo.output_width;
(*height) = cinfo.output_height;
(*components) = cinfo.num_components;
(*color_space) = cinfo.jpeg_color_space;
(*dstLen) = (*width)*(*height)*(*components);
BYTE *tmp_dst = new BYTE[*dstLen]; /* Allocate out buffer */
JSAMPROW row_pointer[1];
row_stride = cinfo.output_width*cinfo.num_components;
/* Step 6: while (scan lines remain to be read) */
/* jpeg_read_scanlines(...); */
/* Here we use the library's state variable cinfo.output_scanline as the
* loop counter, so that we don't have to keep track ourselves.
*/
while (cinfo.output_scanline < cinfo.output_height) {
/* jpeg_read_scanlines expects an array of pointers to scanlines.
* Here the array is only one element long, but you could ask for
* more than one scanline at a time if that's more convenient.
*/
row_pointer[0] = &tmp_dst[cinfo.output_scanline*row_stride];
(void)jpeg_read_scanlines(&cinfo, row_pointer, 1);
}
(*dst) = tmp_dst; // assign to outside dst
/* Step 7: Finish decompression */
(void)jpeg_finish_decompress(&cinfo);
/* We can ignore the return value since suspension is not possible
* with the stdio data source.
*/
/* Step 8: Release JPEG decompression object */
/* This is an important step since it will release a good deal of memory. */
jpeg_destroy_decompress(&cinfo);
/* After finish_decompress, we can close the input file.
* Here we postpone it until after no more JPEG errors are possible,
* so as to simplify the setjmp error logic above. (Actually, I don't
* think that jpeg_destroy can do an error exit, but why assume anything...)
*/
fclose(infile);
/* At this point you may want to check to see whether any corrupt-data
* warnings occurred (test whether jerr.pub.num_warnings is nonzero).
*/
/* And we're done! */
return 1;
}
int decompress_jpeg_from_mem(
/*IN*/BYTE *src, unsigned long srcLen,
/*OUT*/BYTE **dst, unsigned long *dstLen, int *width, int *height, int *components, int *color_space)
{
/* This struct contains the JPEG decompression parameters and pointers to
* working space (which is allocated as needed by the JPEG library).
*/
struct jpeg_decompress_struct cinfo;
/* We use our private extension JPEG error handler.
* Note that this struct must live as long as the main JPEG parameter
* struct, to avoid dangling-pointer problems.
*/
struct jpeg_error_mgr jerr;
/* More stuff */
//FILE *infile; /* source file */
int row_stride; /* physical row width in output buffer */
/* In this example we want to open the input file before doing anything else,
* so that the setjmp() error recovery below can assume the file is open.
* VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
* requires it in order to read binary files.
*/
/*
if ((infile = fopen(src_filename, "rb")) == NULL) {
fprintf(stderr, "can't open %s\n", src_filename);
return 0;
}
*/
/* Step 1: allocate and initialize JPEG decompression object */
/* We set up the normal JPEG error routines, then override error_exit. */
cinfo.err = jpeg_std_error(&jerr);
/* Now we can initialize the JPEG decompression object. */
jpeg_create_decompress(&cinfo);
/* Step 2: specify data source (eg, a file) */
//jpeg_stdio_src(&cinfo, infile);
jpeg_mem_src(&cinfo, src, srcLen);
/* Step 3: read file parameters with jpeg_read_header() */
(void)jpeg_read_header(&cinfo, TRUE);
/* We can ignore the return value from jpeg_read_header since
* (a) suspension is not possible with the stdio data source, and
* (b) we passed TRUE to reject a tables-only JPEG file as an error.
* See libjpeg.txt for more info.
*/
/* Step 4: set parameters for decompression */
/* In this example, we don't need to change any of the defaults set by
* jpeg_read_header(), so we do nothing here.
*/
/* Step 5: Start decompressor */
(void)jpeg_start_decompress(&cinfo);
/* We can ignore the return value since suspension is not possible
* with the stdio data source.
*/
/* We may need to do some setup of our own at this point before reading
* the data. After jpeg_start_decompress() we have the correct scaled
* output image dimensions available, as well as the output colormap
* if we asked for color quantization.
* In this example, we need to make an output work buffer of the right size.
*/
/* JSAMPLEs per row in output buffer */
row_stride = cinfo.output_width * cinfo.output_components;
/* Make a one-row-high sample array that will go away when done with image */
/* Set output fields */
(*width) = cinfo.output_width;
(*height) = cinfo.output_height;
(*components) = cinfo.num_components;
(*color_space) = cinfo.jpeg_color_space;
(*dstLen) = (*width)*(*height)*(*components);
BYTE *tmp_dst = new BYTE[*dstLen]; /* Allocate out buffer */
JSAMPROW row_pointer[1];
row_stride = cinfo.output_width*cinfo.num_components;
/* Step 6: while (scan lines remain to be read) */
/* jpeg_read_scanlines(...); */
/* Here we use the library's state variable cinfo.output_scanline as the
* loop counter, so that we don't have to keep track ourselves.
*/
while (cinfo.output_scanline < cinfo.output_height) {
/* jpeg_read_scanlines expects an array of pointers to scanlines.
* Here the array is only one element long, but you could ask for
* more than one scanline at a time if that's more convenient.
*/
row_pointer[0] = &tmp_dst[cinfo.output_scanline*row_stride];
(void)jpeg_read_scanlines(&cinfo, row_pointer, 1);
}
(*dst) = tmp_dst; // assign to outside dst
/* Step 7: Finish decompression */
(void)jpeg_finish_decompress(&cinfo);
/* We can ignore the return value since suspension is not possible
* with the stdio data source.
*/
/* Step 8: Release JPEG decompression object */
/* This is an important step since it will release a good deal of memory. */
jpeg_destroy_decompress(&cinfo);
/* After finish_decompress, we can close the input file.
* Here we postpone it until after no more JPEG errors are possible,
* so as to simplify the setjmp error logic above. (Actually, I don't
* think that jpeg_destroy can do an error exit, but why assume anything...)
*/
//fclose(infile);
/* At this point you may want to check to see whether any corrupt-data
* warnings occurred (test whether jerr.pub.num_warnings is nonzero).
*/
/* And we're done! */
return 1;
}
void test_compress_to_file()
{
int width = 2000;
int height = 1000;
int channel = 1;
int nImgSize = width * height * channel;
unsigned char * pRawImage = new unsigned char[nImgSize]; // new buffer
memset(pRawImage, 0, nImgSize);
for (int i = 100; i < 300; i++) // row [height]
{
for (int j = 0; j < width; j++) // column [width]
{
*(pRawImage + width * i + j) = (char)255;
}
}
// do work.
compress_jpeg_to_file(
pRawImage,width,height,channel,J_COLOR_SPACE::JCS_GRAYSCALE,90,
"../image/compress/to_file.jpg"
);
delete[] pRawImage;
}
void test_compress_to_mem()
{
int width = 2000;
int height = 1000;
int channel = 1;
int nImgSize = width * height * channel;
unsigned char * pRawImage = new unsigned char[nImgSize]; // new buffer
memset(pRawImage, 0, nImgSize);
for (int i = 100; i < 300; i++) // row [height]
{
for (int j = 0; j < width; j++) // column [width]
{
*(pRawImage + width * i + j) = (char)255;
}
}
// (1) new dst space outside **compress** function
// pOutBuffer's nImgSize must > lOutSize to contain valid dst buffer.
unsigned char *pOutBuffer = new unsigned char[nImgSize]; // new dst buffer
unsigned long lOutSize = 0;
// (2) compress to mem
compress_jpeg_to_mem(
pRawImage, width, height, channel, J_COLOR_SPACE::JCS_GRAYSCALE, 90,
&pOutBuffer, &lOutSize
);
std::cout << "orginal size = " << nImgSize << std::endl;
std::cout << "compress size = "<<lOutSize << std::endl; // 30403
// (3) write mem buffer to file
const char* dst_filename = "../image/compress/mem_to_file.jpg";
FILE *outfile;
if ((outfile = fopen(dst_filename, "wb")) == NULL) {
fprintf(stderr, "can't open %s\n", dst_filename);
exit(1);
}
fwrite(pOutBuffer,lOutSize,1,outfile);
fclose(outfile);
delete[] pOutBuffer;
delete[] pRawImage;
}
void test_decompress_from_file()
{
char* src_filename = "../image/compress/to_file.jpg";
BYTE *dst = NULL; // raw image buffer allocated inside **decompress** function
unsigned long dstLen;
int width, height, channel,color_space;
// allocate dst inside function
decompress_jpeg_from_file(
src_filename,
&dst,&dstLen,&width,&height,&channel,&color_space
);
std::cout << dstLen << std::endl;
std::cout << width << std::endl;
std::cout << height << std::endl;
std::cout << channel << std::endl;
std::cout << color_space << std::endl;
// use raw image buffer
// do work.
compress_jpeg_to_file(
dst, width, height, channel, J_COLOR_SPACE::JCS_GRAYSCALE, 90,
"../image/compress/decompress_from_file_and_then_to_file.jpg"
);
// free allocated memory
if (dst != NULL)
{
delete[] dst;
}
}
void test_decompress_from_mem()
{
// (0) create memory src buffer
char* src_filename = "../image/compress/to_file.jpg";
std::ifstream ifs(src_filename, std::ios_base::binary | std::ios_base::in);
ifs.seekg(0, std::ios::end);
uint64_t size = ifs.tellg();
ifs.seekg(0, std::ios::beg);
//std::vector<char> buffer(size);
//ifs.read(&buffer.front(), size);
BYTE *src = new BYTE[size];
ifs.read((char*)src, size);
// (1) decompress from mem
BYTE *dst = NULL; // raw image buffer allocated inside **decompress** function
unsigned long dstLen;
int width, height, channel, color_space;
// allocate dst inside function
decompress_jpeg_from_mem(
src,size,
&dst, &dstLen, &width, &height, &channel, &color_space
);
std::cout << dstLen << std::endl;
std::cout << width << std::endl;
std::cout << height << std::endl;
std::cout << channel << std::endl;
std::cout << color_space << std::endl;
// (2) use raw image buffer
// do work.
compress_jpeg_to_file(
dst, width, height, channel, J_COLOR_SPACE::JCS_GRAYSCALE, 90,
"../image/compress/decompress_from_mem_and_then_to_file.jpg"
);
// free dst allocated memory
if (dst != NULL)
{
delete[] dst;
}
// free src memory buffer
delete[] src;
}
int IMAGE_COUNT = 10000;
void test_compress_time()
{
int width = 2000;
int height = 1000;
int channel = 1;
unsigned long srcLen = width * height * channel;
unsigned char * src = new unsigned char[srcLen]; // new buffer
memset(src, 0, srcLen);
for (int i = 100; i < 300; i++) // row [height]
{
for (int j = 0; j < width; j++) // column [width]
{
*(src + width * i + j) = (char)255;
}
}
int quality = 90;
time_t start = time(NULL);
for (int i = 0; i < IMAGE_COUNT; i++)
{
// (1) new dst space outside **compress** function
// pOutBuffer's nImgSize must > lOutSize to contain valid dst buffer.
unsigned char *pOutBuffer = new unsigned char[srcLen]; // new dst buffer
unsigned long lOutSize = 0;
// (2) compress to mem
compress_jpeg_to_mem(
src, width, height, channel, J_COLOR_SPACE::JCS_GRAYSCALE, 90,
&pOutBuffer, &lOutSize
);
// (3) free memory
delete[] pOutBuffer;
}
time_t end = time(NULL);
std::cout << "======================================" << std::endl;
double ms = (double)(end - start) * 1000;
std::cout << " use times = " << ms << "ms; avg = " << ms / IMAGE_COUNT << " ms; " << " #" << IMAGE_COUNT << std::endl;
// avg = 4.9 ms #10000 for jpeg
// avg = 4.5 ms #10000 for turbojpeg
std::cout << "======================================" << std::endl;
delete[] src;
}
void test_decompress_time()
{
}
int main(int argc, char* argv[])
{
// 30403, 30153
//test_compress_to_file();
//test_compress_to_mem();
//test_decompress_from_file();
//test_decompress_from_mem();
test_compress_time();
return 0;
}
turbojpeg
#include <iostream>
#include <fstream>
#include <vector>
#include <ctime>
#include "turbojpeg.h"
typedef unsigned char BYTE;
void save_buffer_to_file(const char *filename,BYTE* buffer,unsigned long size)
{
FILE *outfile;
if ((outfile = fopen(filename, "wb")) != NULL) {
fwrite(buffer, size, 1, outfile);
fclose(outfile);
}
else
{
fprintf(stderr, "can't open %s\n", filename);
exit(1);
}
}
/*
* Compress image buffer to a JPEG image in memory.
*
* @@input
*
* @param : [src] pointer to an image buffer that will be compressed.
* @param :
*
* @@output
* @param : [dst] pointer to an image buffer that will receive the compressed image.
This variable should be passed in with NULL, and will be allocated by
TurboJPEG(either by tjAlloc(),or by the Compress/Decompress) method
So we need to use tjFree() to free memory allocated after we are done
working on dst.
* @param : [dstLen] size of dst image buffer in bytes. This should be passed in with
value 0.
*
* @@return
* @param void
*
* @@demo
*
BYTE *dst = NULL;
unsigned long dstLen = 0;
tj_compress_jpeg_to_mem(
....,
&dst,&dstLen
)
*/
void tj_compress_jpeg_to_mem(
/*IN*/BYTE *src, int width, int height, int pixelFormat, int subsamp, int quality, int flags,
/*OUT*/BYTE **dst, unsigned long *dstLen
)
{
// NOTICE : we must use tjAlloc() and tjFree() to allocate dst buffer.
// for compress, we let **tjCompress2** allocate dst buffer.
// for decompress, we allocate dst buffer by ourself.
tjhandle handle = tjInitCompress();
//tjCompress2(handle, src, width, 0/*pitch*/, height, TJPF::TJPF_GRAY,
// &pOutBuffer, &lOutSize, TJSAMP::TJSAMP_GRAY, quality,
// TJFLAG_FASTDCT); //TJFLAG_FASTDCT
tjCompress2(
handle, src, width, 0/*pitch*/, height, pixelFormat,
dst, dstLen, subsamp, quality, flags
);
tjDestroy(handle);
}
void tj_compress_gray_jpeg_to_mem(
/*IN*/BYTE *src, int width, int height, int quality,
/*OUT*/BYTE **dst, unsigned long *dstLen
)
{
int pixelFormat = TJPF::TJPF_GRAY;
int subsamp = TJSAMP::TJSAMP_GRAY;
int flags = TJFLAG_FASTDCT;
tj_compress_jpeg_to_mem(
src, width, height, pixelFormat, subsamp, quality, flags,
dst, dstLen
);
}
void tj_compress_gray_jpeg_to_file(
/*IN*/BYTE *src, int width, int height, int quality,
/*OUT*/const char* dst_filename
)
{
int pixelFormat = TJPF::TJPF_GRAY;
int subsamp = TJSAMP::TJSAMP_GRAY;
int flags = TJFLAG_FASTDCT;
// (1) init dst memory buffer
BYTE *dst = NULL; // memory allocated by TurboJPEG tjAlloc()
unsigned long dstLen = 0;
// (2) compress
tj_compress_jpeg_to_mem(
src, width, height, pixelFormat, subsamp, quality, flags,
&dst, &dstLen
);
// (3) write buffer to file
save_buffer_to_file(dst_filename, dst, dstLen);
// (4) free memory allocated by TurboJPEG
tjFree(dst);
}
/*
* Compress image buffer to a JPEG image in memory.
*
* @@input
*
* @param : [src] pointer to an image buffer that will be compressed.
* @param :
*
* @@output
* @param : [dst] pointer to an image buffer that will receive the decompressed image.
This variable should be passed in with NULL, and will be allocated in
method by new[]. So we need to use delete[] to free memory allocated
after we are done working on dst.
* @param : [dstLen] size of dst image buffer in bytes. This should be passed in with
value 0.
*
* @@return
* @param void
*
* @@demo
*
BYTE *dst = NULL;
unsigned long dstLen = 0;
tj_decompress_jpeg_from_mem(
....,
&dst,&dstLen
)
*/
void tj_decompress_jpeg_from_mem(
/*IN*/BYTE *src, unsigned long srcLen,int tjPixelFormat,int flags,
/*OUT*/BYTE **dst, unsigned long *dstLen, int *width, int *height, int *components, int *jpegSubsamp, int *jpegColorspace)
{
tjhandle handle = tjInitDecompress();
tjDecompressHeader3(handle, src, srcLen, width, height, jpegSubsamp, jpegColorspace);
(*components) = tjPixelSize[(TJPF)tjPixelFormat]; // 1 for GRAY,3 for RGB
(*dstLen) = (*width) * (*height) * (*components);
BYTE *tmp_dst = new BYTE[*dstLen]; /* Allocate out buffer */
tjDecompress2(
handle, src, srcLen,
tmp_dst, *width, 0/*pitch*/, *height, tjPixelFormat, flags
);
tjDestroy(handle);
(*dst) = tmp_dst; // pass dst out
}
void tj_decompress_gray_jpeg_from_mem(
/*IN*/BYTE *src, unsigned long srcLen,
/*OUT*/BYTE **dst, unsigned long *dstLen, int *width, int *height, int *components
)
{
int pixelFormat = TJPF::TJPF_GRAY;
int flags = TJFLAG_ACCURATEDCT;
int subsamp,colorspace; // no use for now (3 TJSAMP::TJSAMP_GRAY, 2 TJCS::TJCS_GRAY)
tj_decompress_jpeg_from_mem(
src, srcLen, pixelFormat, flags,
dst, dstLen, width, height, components, &subsamp, &colorspace
);
}
void tj_decompress_gray_jpeg_from_file(
/*IN*/const char* src_filename,
/*OUT*/BYTE **dst, unsigned long *dstLen, int *width, int *height, int *components
)
{
// (0) read src memory buffer from file
std::ifstream ifs(src_filename, std::ios_base::binary | std::ios_base::in);
ifs.seekg(0, std::ios::end);
uint64_t srcLen = ifs.tellg();
ifs.seekg(0, std::ios::beg);
BYTE *src = new BYTE[srcLen];
ifs.read((char*)src, srcLen);
// (2) decompress
int pixelFormat = TJPF::TJPF_GRAY;
int flags = TJFLAG_ACCURATEDCT;
int subsamp, colorspace; // no use for now (3 TJSAMP::TJSAMP_GRAY, 2 TJCS::TJCS_GRAY)
tj_decompress_jpeg_from_mem(
src, srcLen, pixelFormat, flags,
dst, dstLen, width, height, components, &subsamp, &colorspace
);
// (3) free src memory buffer
delete[] src;
// (4) pass out dst buffer
}
void test_compress()
{
int width = 2000;
int height = 1000;
int channel = 1;
unsigned long srcLen = width * height * channel;
unsigned char * src = new unsigned char[srcLen]; // new buffer
memset(src, 0, srcLen);
for (int i = 100; i < 300; i++) // row [height]
{
for (int j = 0; j < width; j++) // column [width]
{
*(src + width * i + j) = (char)255;
}
}
//========================================================================
// compress to file
int quality = 90;
const char* filename = "../image/compress/tj_mem_to_file.jpg";
tj_compress_gray_jpeg_to_file(src, width, height, quality, filename);
//========================================================================
delete[] src;
}
void test_decompress()
{
// (0) create memory src buffer
char* src_filename = "../image/compress/to_file.jpg";
// (2) decompress
BYTE *dst = NULL; // allocated inside **decompress** function by new[].
unsigned long dstLen = 0;
int width, height, components;
tj_decompress_gray_jpeg_from_file(
src_filename,
&dst, &dstLen, &width, &height, &components
);
std::cout << dstLen << std::endl;
std::cout << width << std::endl;
std::cout << height << std::endl;
std::cout << components << std::endl;
// (3) use dst buffer
//========================================================================
// compress to file
int quality = 90;
const char* dst_filename = "../image/compress/tj_decompress_to_mem_to_file.jpg";
tj_compress_gray_jpeg_to_file(dst, width, height, quality, dst_filename);
//========================================================================
// (4) free dst buffer
delete[] dst;
}
int IMAGE_COUNT = 10000;
void test_compress_time()
{
int width = 2000;
int height = 1000;
int channel = 1;
unsigned long srcLen = width * height * channel;
unsigned char * src = new unsigned char[srcLen]; // new buffer
memset(src, 0, srcLen);
for (int i = 100; i < 300; i++) // row [height]
{
for (int j = 0; j < width; j++) // column [width]
{
*(src + width * i + j) = (char)255;
}
}
int quality = 90;
time_t start = time(NULL);
for (int i = 0; i < IMAGE_COUNT; i++)
{
//========================================================================
// (1) init dst memory buffer
BYTE *dst = NULL; // memory allocated by TurboJPEG tjAlloc()
unsigned long dstLen = 0;
// (2) compress
tj_compress_gray_jpeg_to_mem(
src, width, height, quality,
&dst, &dstLen
);
// (3) free memory allocated by TurboJPEG
tjFree(dst);
//========================================================================
}
time_t end = time(NULL);
std::cout << "======================================" << std::endl;
double ms = (double)(end - start) * 1000;
std::cout << " use times = " << ms << "ms; avg = " << ms / IMAGE_COUNT << " ms; " << " #" << IMAGE_COUNT << std::endl;
// avg = 4.9 ms #10000 for jpeg
// avg = 4.5 ms #10000 for turbojpeg
std::cout << "======================================" << std::endl;
delete[] src;
}
void test_decompress_time()
{
}
int main(int argc, char* argv[])
{
//test_compress();
//test_decompress();
test_compress_time();
return 0;
}
Reference
- example.c
- building
- turbo offical doc
- compress and decompress jpeg
- opencv imdecode to libjpeg-turbo (good)
- tjcompress and tjdecompress
History
- 20180201: created.
- 20180202: add example code.
Copyright
- Post author: kezunlin
- Post link: https://kezunlin.me/post/83828674/
- Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.
windows 10上源码编译libjpeg-turbo和使用教程 | compile and use libjpeg-turbo on windows 10的更多相关文章
- windows 10 上源码编译OpenCV并支持CUDA | compile opencv with CUDA support on windows 10
本文首发于个人博客https://kezunlin.me/post/6580691f/,欢迎阅读! compile opencv with CUDA support on windows 10 Ser ...
- windows 10上源码编译dlib教程 | compile dlib on windows 10
本文首发于个人博客https://kezunlin.me/post/654a6d04/,欢迎阅读! compile dlib on windows 10 Series Part 1: compile ...
- windows 10 上源码编译boost 1.66.0 | compile boost 1.66.0 from source on windows 10
本文首发于个人博客https://kezunlin.me/post/854071ac/,欢迎阅读! compile boost 1.66.0 from source on windows 10 Ser ...
- windows 10 上源码编译opengv | compile opengv on windows 10 from source
本文首发于个人博客https://kezunlin.me/post/51cd9fa0/,欢迎阅读! compile opengv on windows 10 from source Series co ...
- Windows 10上源码编译glog和gflags 编写glog-config.cmake和gflags-config.cmake | compile glog and glags on windows from source
本文首发于个人博客https://kezunlin.me/post/bb64e398/,欢迎阅读! compile glog v0.3.5 and glags on windows from sour ...
- Windows 10上源码编译Poco并编写httpserver和tcpserver | compile and install poco cpp library on windows
本文首发于个人博客https://kezunlin.me/post/9587bb47/,欢迎阅读! compile and install poco cpp library on windows Se ...
- [Part 4] 在Windows 10上源码编译PCL 1.8.1支持VTK和QT,可视化三维点云
本文首发于个人博客https://kezunlin.me/post/2d809f92/,欢迎阅读! Part-4: Compile pcl with vtk qt5 support from sour ...
- [Windows篇] 在windows 10上源码编译gtest 并编写CMakeLists.txt
本文首发于个人博客https://kezunlin.me/post/aca50ff8/,欢迎阅读! compile gtest on windows 10 Guide compile gtest on ...
- CentOS 7上源码编译安装和配置LNMP Web+phpMyAdmin服务器环境
CentOS 7上源码编译安装和配置LNMP Web+phpMyAdmin服务器环境 什么是LNMP? LNMP(别名LEMP)是指由Linux, Nginx, MySQL/MariaDB, PHP/ ...
随机推荐
- 二叉树的查找(前序、中序、后序、层序遍历)--biaobiao88
建立一棵含有n个结点的二叉树,采用二叉链表存储: 输出前序.中序.后序..层序遍历该二叉树的遍历结果. 定义二叉树的数据类型——二叉树结点结构体BiNode.建立二叉链表可以采用扩展二叉树的一个遍历序 ...
- 在.net core3.0中使用SignalR实现实时通信
最近用.net core3.0重构网站,老大想做个站内信功能,就是有些耗时的后台任务的结果需要推送给用户.一开始我想简单点,客户端每隔1分钟调用一下我的接口,看看是不是有新消息,有的话就告诉用户有新推 ...
- 【原】iOS开发进阶(唐巧)读书笔记(二)
第三部分:iOS开发底层原理 1.Objective-C对象模型 1.1 isa指针 NSObject.h部分代码: NS_ROOT_CLASS @interface NSObject <NSO ...
- 第九篇 Flask的before_request和after_request
Flask我们已经学习很多基础知识了,现在有一个问题 我们现在有一个 Flask 程序其中有3个路由和视图函数,如下: from flask import Flask app = Flask(__na ...
- 【java基础之异常】死了都要try,不淋漓尽致地catch我不痛快!
目录 1.异常 1.1 异常概念 1.2 异常体系 1.3 异常分类 1.4 异常的产生过程解析 2. 异常的处理 2.1 抛出异常throw 2.2 Objects非空判断 2.3 声明异常thro ...
- 九大Java性能调试工具,必备至少一款
九款Java性能调试工具,有什么更好.更多的工具,欢迎补充. NetBeans Profiler NetBeans中可以找到NetBeans Profiler. NetBeans分析器是NetBean ...
- Zabbix_agent 三 被动模式的配置
zabbix一共有三种监控模式分别默认是被动模式,由agent端收集数据,server去请求然后获取agent的数据. 还有就是主动模式,由agent收集数据并定时发送到server端,则就是被动模式 ...
- CSPS模拟 55
没睡醒就考试,蓝绶 考试前我在擦眼镜 好像总也擦不干净? 就像石乐志一样一直地在擦 cbx捅了我几下,好像想说什么? 没睡醒,不理 终于擦完了! 雾草要考试? T1 联 先离散化,再正面上线段树 em ...
- AHOI2018 排列
首先是那个非常吃shi的题意,想好久一会就能发现题里面的意思是: 如果某一个数的值为x,那么它必须排在第x个数后面. 然后我们就可以发现形成了一棵树,第i个数的父亲是i,如果出现了环就说明无解. 于是 ...
- NOIP模拟 30
补坑,很多都忘了. T1 树 像我这种人都能考场A掉当然是道水题辣 求出每条有向边的期望就好了 T2 回文串 当时毫无思路,暴力写挂. 首先把B转过来,那么都变成后缀的前缀拼起来 对于每一个LCP,他 ...