• 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 FilesNASM 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
    ", 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
    ", 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
    ", 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
    ", 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
    ", 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

    History

    • 20180201: created.
    • 20180202: add example code.

    Copyright

  • 相关阅读:
    感谢一个名叫“祯玥”的姑娘
    下一代互联网
    伤心时要读的三十八句
    任何企业的竞争,归根结底都是智能的竞争
    互联网创业必须过的槛(转)
    钻到牛角尖里面去,想开公司必需知道的奥秘
    重游草堂
    牛根生:我们应该学会“三换思维”
    领导者的感染力和传染力
    幸福是一种心境(转)
  • 原文地址:https://www.cnblogs.com/kezunlin/p/11840754.html
Copyright © 2020-2023  润新知