MCU平台libjpeg9移植使用说明

16 篇文章 0 订阅
8 篇文章 1 订阅

MCU平台libjpeg9移植使用说明

随着MCU平台的性能越来越强大,在MCU上使用jpeg软解码也成为可能,本文就将libjpeg移植做以说明。

libjpeg 是一个广泛使用的 JPEG 图像压缩/解压开源库,采用 C 语言开发。因此可以方便的移植到各种平台上。可以在这样下载源码 http://www.ijg.org/files/

这里我们使用最新的libjpeg9版本,早先的libjpeg6版本中仅提供的接口都是从文件读取源数据,而我们希望的是从内存中输入源数据,在libjpeg9版本中新增了jpeg_mem_src可以实现我们的需求。

在PC上编写测试代码验证

首先,第一步我们先不着急移植到开发板上,先在PC上编写代码测试下效果,这里我使用主机开发环境是ubuntu18.04。本着方便期间可以直接使用apt安装libjpeg9-dev这个包来使用。

sudo apt install libjpeg9-dev

当然,你可以自己编译源码

cd jpeg-9
./configure
make -j8

完成编译后,在.libs目录内可以找到libjpeg动态库和静态库,也可以使用make install 安装到本地目录,这样就和使用apt直接安装一样了。

接下来编写一个测试代码

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "jpeglib.h"

unsigned char jpeg_data[34518] = {
	0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 
	0x00, 0x01, 0x00, 0x00, 0xFF, 0xDB, 0x00, 0x43, 0x00, 0x06, 0x04, 0x05, 0x06, 0x05, 0x04, 0x06, 
	0x06, 0x05, 0x06, 0x07, 0x07, 0x06, 0x08, 0x0A, 0x10, 0x0A, 0x0A, 0x09, 0x09, 0x0A, 0x14, 0x0E, 
	这个数组内是一张jpeg的原始数据,这里省略不写...
};

#define PRINTF_JPEGDECODER_OUT_DATA          1   //开启后将解码数据打印在串口log内(YV12plan数据按16行分别打印YUV三个分量)
#define JPEGDECODER_OUT_DATA_TO_RAM        0   //开启后将解码数据输出到内存中固定地址0x70000000
#define JPEGDECODER_OUT_COLOR_SPACE_YV12     0   //YV12格式:这种是jpeg解码后的原始YV12plan数据,不进行任何色彩空间转换,不增加解码时间开销
#define JPEGDECODER_OUT_COLOR_SPACE_YUV444   0   //RGB格式:这种是进行色彩空间转换后的YUV444pack数据,增加解码时间开销
#define JPEGDECODER_OUT_COLOR_SPACE_RGB      1   //YVU444格式:这种是进行色彩空间转换后的RGB888数据,增加解码时间开销

struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;

int jpegDecode(void)
{
    cinfo.err = jpeg_std_error(&jerr); 

    jpeg_create_decompress(&cinfo);
    jpeg_mem_src(&cinfo, (void *)jpeg_data, sizeof(jpeg_data));
    jpeg_read_header(&cinfo, TRUE);
    

#if JPEGDECODER_OUT_COLOR_SPACE_RGB 
    cinfo.out_color_space = JCS_RGB;
#endif
#if JPEGDECODER_OUT_COLOR_SPACE_YUV444
    cinfo.out_color_space = JCS_YCbCr;
#endif
#if JPEGDECODER_OUT_COLOR_SPACE_YV12
    cinfo.out_color_space = JCS_YCbCr;
    cinfo.raw_data_out = TRUE;
    cinfo.do_fancy_upsampling = FALSE;
#endif 
    
  	jpeg_start_decompress(&cinfo);
    
	switch (cinfo.out_color_space)
    {
        case JCS_RGB:
        {            
            JSAMPARRAY out_buffer = (JSAMPARRAY)malloc(sizeof(JSAMPROW));
            out_buffer[0] = (JSAMPROW)malloc(sizeof(JSAMPLE) * cinfo.image_width * 3);
            
            #if JPEGDECODER_OUT_DATA_TO_RAM
            unsigned char *ram_out_buff = (unsigned char *)0x70000000;
            while (cinfo.output_scanline < cinfo.output_height) {
                jpeg_read_scanlines(&cinfo, out_buffer, 1);
                memcpy(ram_out_buff,out_buffer[0],cinfo.image_width * 3);
                ram_out_buff += cinfo.image_width * 3;
            }
            #else
            while (cinfo.output_scanline < cinfo.output_height) {
                jpeg_read_scanlines(&cinfo, out_buffer, 1);
                #if PRINTF_JPEGDECODER_OUT_DATA
                unsigned char *rgb_ptr = (unsigned char *)(out_buffer[0]);
                for (unsigned int i = 0; i < cinfo.output_width; i++) {       
                    printf("0x%02x ", *(rgb_ptr++));
                    printf("0x%02x ", *(rgb_ptr++));
                    printf("0x%02x ", *(rgb_ptr++));
                }
                #endif
            }
            #endif
            
            free(out_buffer[0]);
            free(out_buffer);
            break;
        }
        case JCS_YCbCr:
        {
            if(cinfo.raw_data_out == TRUE)
            {
                JSAMPIMAGE out_buffer = (JSAMPIMAGE)malloc(sizeof(JSAMPIMAGE) * 3);
                out_buffer[0] = (JSAMPARRAY  )malloc(sizeof(JSAMPARRAY ) * cinfo.output_height);
                out_buffer[1] = (JSAMPARRAY )malloc(sizeof(JSAMPARRAY ) * cinfo.output_height);
                out_buffer[2] = (JSAMPARRAY )malloc(sizeof(JSAMPARRAY ) * cinfo.output_height);
                JSAMPARRAY temp_out_buffer_0 = out_buffer[0];
                JSAMPARRAY temp_out_buffer_1 = out_buffer[1];
                JSAMPARRAY temp_out_buffer_2 = out_buffer[2];
                
                #if JPEGDECODER_OUT_DATA_TO_RAM
                //输出数据到ram,验证正确性
                unsigned char *ram_out_buff = (unsigned char *)0x70000000;
                int i;
                unsigned char *line;
                line = ram_out_buff;
                for (i = 0; i < cinfo.image_height; i ++, line += cinfo.output_width)
                    out_buffer[0][i] = line;
                if (2 == cinfo.comp_info[0].v_samp_factor)
                {
                    line = ram_out_buff + cinfo.output_width * cinfo.output_height;
                    for (i = 0; i < cinfo.image_height; i += 2, line += cinfo.output_width / 2)
                        out_buffer[1][i / 2] = line;

                    line = ram_out_buff + cinfo.output_width * cinfo.output_height * 5 / 4;
                    for (i = 0; i < cinfo.image_height; i += 2, line += cinfo.output_width / 2)
                        out_buffer[2][i / 2] =  line;

                    int y_read_line = 8;
                    for (int i = 0; cinfo.output_scanline < cinfo.output_height; i += 2 * y_read_line)
                    {
                        int j = jpeg_read_raw_data(&cinfo, out_buffer, 2 * y_read_line);
                        out_buffer[0] += 2 * y_read_line;
                        out_buffer[1] += y_read_line;
                        out_buffer[2] += y_read_line;
                    }
                }
                else
                {
                    printf("v_samp_factor is %d\n",cinfo.comp_info[0].v_samp_factor);
                    printf("is not YUV420 data\n");
					while(1);
                }
                #else
                // 不输出数据,用于测试时间
                unsigned char *sram_out_buff = (unsigned char * )malloc(16*cinfo.output_width*3/2);
                int i;
                unsigned char *line;
                line = sram_out_buff;
                for (i = 0; i < 16; i ++, line += cinfo.output_width)
                    out_buffer[0][i] = line;
                if (2 == cinfo.comp_info[0].v_samp_factor)
                {
                    line = sram_out_buff + cinfo.output_width * 16;
                    for (i = 0; i < 16; i += 2, line += cinfo.output_width / 2)
                        out_buffer[1][i / 2] = line;

                    line = sram_out_buff + cinfo.output_width * 16 * 5 / 4;
                    for (i = 0; i < 16; i += 2, line += cinfo.output_width / 2)
                        out_buffer[2][i / 2] =  line;

                    int y_read_line = 8;
                    for (int i = 0; cinfo.output_scanline < cinfo.output_height; i += 2 * y_read_line)
                    {
                        jpeg_read_raw_data(&cinfo, out_buffer, 2 * y_read_line);
                        #if PRINTF_JPEGDECODER_OUT_DATA
                        printf("Y: ");
                        for (size_t j = 0; j < 2*y_read_line*cinfo.output_width; j++)
                        {
                            printf("0x%02X ", sram_out_buff[j]);
                        }
                        printf("\n");
                        printf("U: ");
                        for (size_t j = 0; j < y_read_line*cinfo.output_width; j++)
                        {
                            printf("0x%02X ", sram_out_buff[j+2*y_read_line*cinfo.output_width]);
                        }
                        printf("\n");
                        printf("V: ");
                        for (size_t j = 0; j < y_read_line*cinfo.output_width; j++)
                        {
                            printf("0x%02X ", sram_out_buff[j+3*y_read_line*cinfo.output_width]);
                        }
                        printf("\n");
                        printf("\n");
                        #endif
                    }
                }
                else
                {
                    printf("v_samp_factor is %d\n",cinfo.comp_info[0].v_samp_factor);
                    printf("is not YUV420 data\n");
					while(1);
                }
                free(sram_out_buff);
                #endif
                free(temp_out_buffer_0);
                free(temp_out_buffer_1);
                free(temp_out_buffer_2);
                free(out_buffer);
            }
            else
            {
                // jpeg_read_scanlines这种方式输出的YUV444的pack数据,不是原始数据YUV420的plan数据
                JSAMPARRAY out_buffer = (JSAMPARRAY)malloc(sizeof(JSAMPROW));
                out_buffer[0] = (JSAMPROW)malloc(sizeof(JSAMPLE) * cinfo.image_width * 3 );

                #if JPEGDECODER_OUT_DATA_TO_RAM
                unsigned char *ram_out_buff = (unsigned char *)0x70000000;
                while (cinfo.output_scanline < cinfo.output_height) {
                    jpeg_read_scanlines(&cinfo, out_buffer, 1);
                    memcpy(ram_out_buff,out_buffer[0],cinfo.image_width * 3);
                    ram_out_buff += cinfo.image_width * 3;
                }
                #else
                while (cinfo.output_scanline < cinfo.output_height) {
                    jpeg_read_scanlines(&cinfo, out_buffer, 1);
                    #if PRINTF_JPEGDECODER_OUT_DATA
                    unsigned char *yuv_ptr = (unsigned char *)(out_buffer[0]);
                    for (unsigned int i = 0; i < cinfo.output_width; i++) {
                        printf("0x%02x ", *(yuv_ptr++));
                        printf("0x%02x ", *(yuv_ptr++));
                        printf("0x%02x ", *(yuv_ptr++));
                    }
                    #endif
                }
                #endif
                
                free(out_buffer[0]);
                free(out_buffer);
            }
            break;
        }
        default:
            break;
	}

	jpeg_finish_decompress(&cinfo);
    
    jpeg_destroy_decompress(&cinfo);
    
    printf("\nfinsh\n");
    
    return 0;
}

int main()
{
	jpegDecode();
	return 0;
}

编译上述代码运行,可以确认解码正常

gcc decode_jpeg.c -ljpeg -o decode_jpeg

这里多说两句,上述测试代码中有以下三个测试宏,可以将jpeg的解码结果输出成不同格式的,实际验证解码成不同格式的数据,时间开销也不同,后续我们移植到自己平台上使用什么样的最终数据格式能节约MCU的带宽是一个重要的考虑因素,因为jpeg编码是通过将rgb数据转换问YUV的色彩空间进行压缩的,而部分MCU平台硬件提供了YUV转换RGB的硬件加速单元,因此软件解码jpeg可以仅仅转换到YV12格式,大大节约CPU带宽资源。

另外代码中的YV12格式的数据组织仅作为示例,你可以根据自己需求的数据格式组织数据输出,我之前在网上搜索了很多博客都没找到这个库解码成YUV420格式的示例代码,或者是有些代码不能用,有些代码过于老旧不适合新版本的libjpeg9。这份代码可以给大家一个参考。

#define JPEGDECODER_OUT_COLOR_SPACE_YV12     0   //YV12格式:这种是jpeg解码后的原始YV12plan数据,不进行任何色彩空间转换,不增加解码时间开销
#define JPEGDECODER_OUT_COLOR_SPACE_YUV444   0   //RGB格式:这种是进行色彩空间转换后的YUV444pack数据,增加解码时间开销
#define JPEGDECODER_OUT_COLOR_SPACE_RGB      1   //YVU444格式:这种是进行色彩空间转换后的RGB888数据,增加解码时间开销
移植

接下来我们就可以将这个测试代码已经libjpeg统统移植到mcu平台上了。

添加以下文件到你MCU平台工程内,注意libjpeg源码内的其他文件不必添加你工程内,因为有大量平台相关的测试代码,而你的平台未必能支持到,以下源文件才是该编解码库的核心功能。

jaricom.c、jcapimin.c、jcapistd.c、jccoefct.c、
jccolor.c、jcdctmgr.c、jchuff.c、jcinit.c、
jcmainct.c、jcmarker.c、jcmaster.c、jcomapi.c、
jcparam.c、jcprepct.c、jcsample.c、jctrans.c、
jdapimin.c、jdapistd.c、jdarith.c、jdatadst.c、
jdatasrc.c、jdcoefct.c、jdcolor.c、jddctmgr.c、
jdhuff.c、jdinput.c、jdmainct.c、jdmarker.c、
jdmaster.c、jdmerge.c、jdpostct.c、jdsample.c、
jdtrans.c、jerror.c、jfdctflt.c、jfdctfst.c、
jfdctint.c、jidctflt.c、jidctfst.c、jidctint.c、
jmemmgr.c、jmemnobs.c、jquant1.c、jquant2.c、 jutils.c

新建文件jconfig.h(PC上该文件有自动构建工具自动生成的,这里我们要自己编写适合自己平台的,以下内容供参考),内容如下:

/*
 * jconfig.h
 *
 * Copyright (C) 1991-1994, Thomas G. Lane.
 * This file is part of the Independent JPEG Group's software.
 * For conditions of distribution and use, see the accompanying README file.
 *
 * This file documents the configuration options that are required to
 * customize the JPEG software for a particular system.
 *
 * The actual configuration options for a particular installation are stored
 * in jconfig.h.  On many machines, jconfig.h can be generated automatically
 * or copied from one of the "canned" jconfig files that we supply.  But if
 * you need to generate a jconfig.h file by hand, this file tells you how.
 *
 * DO NOT EDIT THIS FILE --- IT WON'T ACCOMPLISH ANYTHING.
 * EDIT A COPY NAMED JCONFIG.H.
 */


/*
 * These symbols indicate the properties of your machine or compiler.
 * #define the symbol if yes, #undef it if no.
 */

/* Does your compiler support function prototypes?
 * (If not, you also need to use ansi2knr, see install.txt)
 */
#define HAVE_PROTOTYPES

/* Does your compiler support the declaration "unsigned char" ?
 * How about "unsigned short" ?
 */
#define HAVE_UNSIGNED_CHAR
#define HAVE_UNSIGNED_SHORT

/* Define "void" as "char" if your compiler doesn't know about type void.
 * NOTE: be sure to define void such that "void *" represents the most general
 * pointer type, e.g., that returned by malloc().
 */
#undef void

/* Define "const" as empty if your compiler doesn't know the "const" keyword.
 */
#undef const

/* Define this if an ordinary "char" type is unsigned.
 * If you're not sure, leaving it undefined will work at some cost in speed.
 * If you defined HAVE_UNSIGNED_CHAR then the speed difference is minimal.
 */
#define CHAR_IS_UNSIGNED

/* Define this if your system has an ANSI-conforming <stddef.h> file.
 */
#define HAVE_STDDEF_H

/* Define this if your system has an ANSI-conforming <stdlib.h> file.
 */
#define HAVE_STDLIB_H 
#define FILE void  
#define USE_LIBJPEG_MY_LOG 
#define USE_LIBJPEG_MY_MALLOC    

/* Define this if your system does not have an ANSI/SysV <string.h>,
 * but does have a BSD-style <strings.h>.
 */
#undef NEED_BSD_STRINGS

/* Define this if your system does not provide typedef size_t in any of the
 * ANSI-standard places (stddef.h, stdlib.h, or stdio.h), but places it in
 * <sys/types.h> instead.
 */
#undef NEED_SYS_TYPES_H

/* For 80x86 machines, you need to define NEED_FAR_POINTERS,
 * unless you are using a large-data memory model or 80386 flat-memory mode.
 * On less brain-damaged CPUs this symbol must not be defined.
 * (Defining this symbol causes large data structures to be referenced through
 * "far" pointers and to be allocated with a special version of malloc.)
 */
#undef NEED_FAR_POINTERS

/* Define this if your linker needs global names to be unique in less
 * than the first 15 characters.
 */
#undef NEED_SHORT_EXTERNAL_NAMES

/* Although a real ANSI C compiler can deal perfectly well with pointers to
 * unspecified structures (see "incomplete types" in the spec), a few pre-ANSI
 * and pseudo-ANSI compilers get confused.  To keep one of these bozos happy,
 * define INCOMPLETE_TYPES_BROKEN.  This is not recommended unless you
 * actually get "missing structure definition" warnings or errors while
 * compiling the JPEG code.
 */
#undef INCOMPLETE_TYPES_BROKEN

/* Define "boolean" as unsigned char, not int, on Windows systems.
 */
#ifdef _WIN32
#ifndef __RPCNDR_H__		/* don't conflict if rpcndr.h already read */
typedef unsigned char boolean;
#endif
#define HAVE_BOOLEAN		/* prevent jmorecfg.h from redefining it */
#endif

/*
 * The following options affect code selection within the JPEG library,
 * but they don't need to be visible to applications using the library.
 * To minimize application namespace pollution, the symbols won't be
 * defined unless JPEG_INTERNALS has been defined.
 */

#ifdef JPEG_INTERNALS

/* Define this if your compiler implements ">>" on signed values as a logical
 * (unsigned) shift; leave it undefined if ">>" is a signed (arithmetic) shift,
 * which is the normal and rational definition.
 */
#undef RIGHT_SHIFT_IS_UNSIGNED
#define INLINE inline
/* These are for configuring the JPEG memory manager. */
#undef DEFAULT_MAX_MEM
#undef NO_MKTEMP

#endif /* JPEG_INTERNALS */


/*
 * The remaining options do not affect the JPEG library proper,
 * but only the sample applications cjpeg/djpeg (see cjpeg.c, djpeg.c).
 * Other applications can ignore these.
 */

#ifdef JPEG_CJPEG_DJPEG

/* These defines indicate which image (non-JPEG) file formats are allowed. */

#define BMP_SUPPORTED		/* BMP image file format */
#define GIF_SUPPORTED		/* GIF image file format */
#define PPM_SUPPORTED		/* PBMPLUS PPM/PGM image file format */
#undef RLE_SUPPORTED		/* Utah RLE image file format */
#define TARGA_SUPPORTED		/* Targa image file format */

/* Define this if you want to name both input and output files on the command
 * line, rather than using stdout and optionally stdin.  You MUST do this if
 * your system can't cope with binary I/O to stdin/stdout.  See comments at
 * head of cjpeg.c or djpeg.c.
 */
#undef TWO_FILE_COMMANDLINE

/* Define this if your system needs explicit cleanup of temporary files.
 * This is crucial under MS-DOS, where the temporary "files" may be areas
 * of extended memory; on most other systems it's not as important.
 */
#undef NEED_SIGNAL_CATCHER

/* By default, we open image files with fopen(...,"rb") or fopen(...,"wb").
 * This is necessary on systems that distinguish text files from binary files,
 * and is harmless on most systems that don't.  If you have one of the rare
 * systems that complains about the "b" spec, define this symbol.
 */
#undef DONT_USE_B_MODE

/* Define this if you want percent-done progress reports from cjpeg/djpeg.
 */
#undef PROGRESS_REPORT


#endif /* JPEG_CJPEG_DJPEG */

修改以下两个源文件,注意对比以下相比原本改动的内容是输出printf打印和malloc内存分配相关的内容,你可以根据我的修改成适合你平台的接口

jmemnobs.c


/*
 * jmemnobs.c
 *
 * Copyright (C) 1992-1996, Thomas G. Lane.
 * This file is part of the Independent JPEG Group's software.
 * For conditions of distribution and use, see the accompanying README file.
 *
 * This file provides a really simple implementation of the system-
 * dependent portion of the JPEG memory manager.  This implementation
 * assumes that no backing-store files are needed: all required space
 * can be obtained from malloc().
 * This is very portable in the sense that it'll compile on almost anything,
 * but you'd better have lots of main memory (or virtual memory) if you want
 * to process big images.
 * Note that the max_memory_to_use option is ignored by this implementation.
 */

#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"
#include "jmemsys.h"		/* import the system-dependent declarations */

#ifndef HAVE_STDLIB_H		/* <stdlib.h> should declare malloc(),free() */
extern void * malloc JPP((size_t size));
extern void free JPP((void *ptr));
#endif

#ifdef USE_LIBJPEG_MY_MALLOC
#include "my_log.h"
extern void *pvPortCalloc( size_t nmemb, size_t size );
extern void *pvPortMalloc( size_t xWantedSize );
extern void *pvPortRealloc( void *pv, size_t size );
extern void vPortFree( void *pv );

#define malloc  pvPortMalloc 
#define calloc  pvPortCalloc 
#define realloc pvPortRealloc 
#define free    vPortFree
#endif

/*
 * Memory allocation and freeing are controlled by the regular library
 * routines malloc() and free().
 */

GLOBAL(void *)
jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject)
{
  void *p = (void *) malloc(sizeofobject);
  if(p == NULL) {
        get_fmem_status();
        mprintf("sizeofobject %d\n",sizeofobject);
  }
  return p;
}

GLOBAL(void)
jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject)
{
  free(object);
}


/*
 * "Large" objects are treated the same as "small" ones.
 * NB: although we include FAR keywords in the routine declarations,
 * this file won't actually work in 80x86 small/medium model; at least,
 * you probably won't be able to process useful-size images in only 64KB.
 */

GLOBAL(void FAR *)
jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject)
{
  void *p = (void *) malloc(sizeofobject);
  if(p == NULL) {
        get_fmem_status();
        mprintf("sizeofobject %d\n",sizeofobject);
  }
  return (void FAR *)p;
}

GLOBAL(void)
jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject)
{
  free(object);
}


/*
 * This routine computes the total memory space available for allocation.
 * Here we always say, "we got all you want bud!"
 */

GLOBAL(long)
jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed,
		    long max_bytes_needed, long already_allocated)
{
  return max_bytes_needed;
}


/*
 * Backing store (temporary file) management.
 * Since jpeg_mem_available always promised the moon,
 * this should never be called and we can just error out.
 */

GLOBAL(void)
jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info,
			 long total_bytes_needed)
{
  ERREXIT(cinfo, JERR_NO_BACKING_STORE);
}


/*
 * These routines take care of any system-dependent initialization and
 * cleanup required.  Here, there isn't any.
 */

GLOBAL(long)
jpeg_mem_init (j_common_ptr cinfo)
{
  return 0;			/* just set max_memory_to_use to 0 */
}

GLOBAL(void)
jpeg_mem_term (j_common_ptr cinfo)
{
  /* no work */
}

jerror.c

/*
 * jerror.c
 *
 * Copyright (C) 1991-1998, Thomas G. Lane.
 * Modified 2012 by Guido Vollbeding.
 * This file is part of the Independent JPEG Group's software.
 * For conditions of distribution and use, see the accompanying README file.
 *
 * This file contains simple error-reporting and trace-message routines.
 * These are suitable for Unix-like systems and others where writing to
 * stderr is the right thing to do.  Many applications will want to replace
 * some or all of these routines.
 *
 * If you define USE_WINDOWS_MESSAGEBOX in jconfig.h or in the makefile,
 * you get a Windows-specific hack to display error messages in a dialog box.
 * It ain't much, but it beats dropping error messages into the bit bucket,
 * which is what happens to output to stderr under most Windows C compilers.
 *
 * These routines are used by both the compression and decompression code.
 */

/* this is not a core library module, so it doesn't define JPEG_INTERNALS */
#include "jinclude.h"
#include "jpeglib.h"
#include "jversion.h"
#include "jerror.h"

#ifdef USE_WINDOWS_MESSAGEBOX
#include <windows.h>
#endif

#ifdef USE_LIBJPEG_MY_LOG
#include "my_log.h"
#endif

#ifndef EXIT_FAILURE		/* define exit() codes if not provided */
#define EXIT_FAILURE  1
#endif


/*
 * Create the message string table.
 * We do this from the master message list in jerror.h by re-reading
 * jerror.h with a suitable definition for macro JMESSAGE.
 * The message table is made an external symbol just in case any applications
 * want to refer to it directly.
 */

#ifdef NEED_SHORT_EXTERNAL_NAMES
#define jpeg_std_message_table	jMsgTable
#endif

#define JMESSAGE(code,string)	string ,

const char * const jpeg_std_message_table[] = {
#include "jerror.h"
  NULL
};


/*
 * Error exit handler: must not return to caller.
 *
 * Applications may override this if they want to get control back after
 * an error.  Typically one would longjmp somewhere instead of exiting.
 * The setjmp buffer can be made a private field within an expanded error
 * handler object.  Note that the info needed to generate an error message
 * is stored in the error object, so you can generate the message now or
 * later, at your convenience.
 * You should make sure that the JPEG object is cleaned up (with jpeg_abort
 * or jpeg_destroy) at some point.
 */

METHODDEF(noreturn_t)
error_exit (j_common_ptr cinfo)
{
  /* Always display the message */
  (*cinfo->err->output_message) (cinfo);

  /* Let the memory manager delete any temp files before we die */
  jpeg_destroy(cinfo);

  exit(EXIT_FAILURE);
}


/*
 * Actual output of an error or trace message.
 * Applications may override this method to send JPEG messages somewhere
 * other than stderr.
 *
 * On Windows, printing to stderr is generally completely useless,
 * so we provide optional code to produce an error-dialog popup.
 * Most Windows applications will still prefer to override this routine,
 * but if they don't, it'll do something at least marginally useful.
 *
 * NOTE: to use the library in an environment that doesn't support the
 * C stdio library, you may have to delete the call to fprintf() entirely,
 * not just not use this routine.
 */

METHODDEF(void)
output_message (j_common_ptr cinfo)
{
  char buffer[JMSG_LENGTH_MAX];

  /* Create the message */
  (*cinfo->err->format_message) (cinfo, buffer);

#ifdef USE_WINDOWS_MESSAGEBOX
  /* Display it in a message dialog box */
  MessageBox(GetActiveWindow(), buffer, "JPEG Library Error",
	     MB_OK | MB_ICONERROR);
#else
  /* Send it to stderr, adding a newline */
  #ifdef USE_LIBJPEG_MY_LOG
  mprintf("%s\n", buffer);
  #else
  fprintf(stderr, "%s\n", buffer);
  #endif
#endif
}


/*
 * Decide whether to emit a trace or warning message.
 * msg_level is one of:
 *   -1: recoverable corrupt-data warning, may want to abort.
 *    0: important advisory messages (always display to user).
 *    1: first level of tracing detail.
 *    2,3,...: successively more detailed tracing messages.
 * An application might override this method if it wanted to abort on warnings
 * or change the policy about which messages to display.
 */

METHODDEF(void)
emit_message (j_common_ptr cinfo, int msg_level)
{
  struct jpeg_error_mgr * err = cinfo->err;

  if (msg_level < 0) {
    /* It's a warning message.  Since corrupt files may generate many warnings,
     * the policy implemented here is to show only the first warning,
     * unless trace_level >= 3.
     */
    if (err->num_warnings == 0 || err->trace_level >= 3)
      (*err->output_message) (cinfo);
    /* Always count warnings in num_warnings. */
    err->num_warnings++;
  } else {
    /* It's a trace message.  Show it if trace_level >= msg_level. */
    if (err->trace_level >= msg_level)
      (*err->output_message) (cinfo);
  }
}


/*
 * Format a message string for the most recent JPEG error or message.
 * The message is stored into buffer, which should be at least JMSG_LENGTH_MAX
 * characters.  Note that no '\n' character is added to the string.
 * Few applications should need to override this method.
 */

METHODDEF(void)
format_message (j_common_ptr cinfo, char * buffer)
{
  struct jpeg_error_mgr * err = cinfo->err;
  int msg_code = err->msg_code;
  const char * msgtext = NULL;
  const char * msgptr;
  char ch;
  boolean isstring;

  /* Look up message string in proper table */
  if (msg_code > 0 && msg_code <= err->last_jpeg_message) {
    msgtext = err->jpeg_message_table[msg_code];
  } else if (err->addon_message_table != NULL &&
	     msg_code >= err->first_addon_message &&
	     msg_code <= err->last_addon_message) {
    msgtext = err->addon_message_table[msg_code - err->first_addon_message];
  }

  /* Defend against bogus message number */
  if (msgtext == NULL) {
    err->msg_parm.i[0] = msg_code;
    msgtext = err->jpeg_message_table[0];
  }

  /* Check for string parameter, as indicated by %s in the message text */
  isstring = FALSE;
  msgptr = msgtext;
  while ((ch = *msgptr++) != '\0') {
    if (ch == '%') {
      if (*msgptr == 's') isstring = TRUE;
      break;
    }
  }

  /* Format the message into the passed buffer */
  if (isstring)
    sprintf(buffer, msgtext, err->msg_parm.s);
  else
    sprintf(buffer, msgtext,
	    err->msg_parm.i[0], err->msg_parm.i[1],
	    err->msg_parm.i[2], err->msg_parm.i[3],
	    err->msg_parm.i[4], err->msg_parm.i[5],
	    err->msg_parm.i[6], err->msg_parm.i[7]);
}


/*
 * Reset error state variables at start of a new image.
 * This is called during compression startup to reset trace/error
 * processing to default state, without losing any application-specific
 * method pointers.  An application might possibly want to override
 * this method if it has additional error processing state.
 */

METHODDEF(void)
reset_error_mgr (j_common_ptr cinfo)
{
  cinfo->err->num_warnings = 0;
  /* trace_level is not reset since it is an application-supplied parameter */
  cinfo->err->msg_code = 0;	/* may be useful as a flag for "no error" */
}


/*
 * Fill in the standard error-handling methods in a jpeg_error_mgr object.
 * Typical call is:
 *	struct jpeg_compress_struct cinfo;
 *	struct jpeg_error_mgr err;
 *
 *	cinfo.err = jpeg_std_error(&err);
 * after which the application may override some of the methods.
 */

GLOBAL(struct jpeg_error_mgr *)
jpeg_std_error (struct jpeg_error_mgr * err)
{
  err->error_exit = error_exit;
  err->emit_message = emit_message;
  err->output_message = output_message;
  err->format_message = format_message;
  err->reset_error_mgr = reset_error_mgr;

  err->trace_level = 0;		/* default = no tracing */
  err->num_warnings = 0;	/* no warnings emitted yet */
  err->msg_code = 0;		/* may be useful as a flag for "no error" */

  /* Initialize message table pointers */
  err->jpeg_message_table = jpeg_std_message_table;
  err->last_jpeg_message = (int) JMSG_LASTMSGCODE - 1;

  err->addon_message_table = NULL;
  err->first_addon_message = 0;	/* for safety */
  err->last_addon_message = 0;

  return err;
}

最后,添加我们之前的测试源码就可以对比PC输出结果,验证移植的正确性了。

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Quard_D

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值