improve logic of __mg_check_jpg for performance .

loop for reading JPEG marker from MG_RWops object,if meet other JPEG marker(eg. SOI,APPn,DQT) skip the payload bytes for next marker,until reach SOF0 or SOF2.
about JPEG marker, see also https://en.wikipedia.org/wiki/JPEG
This commit is contained in:
10km
2018-08-31 15:00:50 +08:00
parent 09e83b6a8b
commit 1297ba836d
+69 -65
View File
@@ -254,10 +254,37 @@ static void my_error_exit (j_common_ptr cinfo)
longjmp (myerr->setjmp_buffer, 1);
}
/*
* Common JPEG markers
* see also https://en.wikipedia.org/wiki/JPEG
* */
#define JMK_SOI 0xFFD8 /* Start Of Image */
#define JMK_SOF0 0xFFC0 /* Start Of Frame (baseline DCT) */
#define JMK_SOF2 0xFFC2 /* Start Of Frame (progressive DCT) */
#define JMK_DHT 0xFFC4 /* Define Huffman Table(s) */
#define JMK_DQT 0xFFDB /* Define Quantization Table(s) */
#define JMK_DRI 0xFFDD /* Define Restart Interval */
#define JMK_SOS 0xFFDA /* Start Of Scan */
#define JMK_RST_mask 0xFFD0 /* mask of Restart */
#define JMK_APP_mask 0xFFE0 /* mask of Application-specific */
#define JMK_COM 0xFFFE /* Comment */
#define JMK_EOI 0xFFD9 /* End Of Image */
/**
* Reads a 16-bit big endian integer from a MG_RWops object.
* return TRUE if sucess,or FALSE if the read failed.
*/
static BOOL read_be16 (MG_RWops *fp,Uint16 *value)
{
if(-1 == MGUI_RWread(fp, value, (sizeof *value), 1))
return FALSE;
*value = (ArchSwapBE16(*value));
return TRUE;
}
void* __mg_init_jpg (MG_RWops *fp, MYBITMAP* mybmp, RGB* pal)
{
int i;
unsigned char magic[5];
Uint16 soi_marker;
/* This struct contains the JPEG decompression parameters
* and pointers to working space
@@ -267,11 +294,8 @@ void* __mg_init_jpg (MG_RWops *fp, MYBITMAP* mybmp, RGB* pal)
struct my_error_mgr *jerr;
jpeg_init_info_t* init_info;
if (!MGUI_RWread (fp, magic, 2, 1))
goto err; /* not JPEG image*/
if (magic[0] != 0xFF || magic[1] != 0xD8)
goto err; /* not JPEG image*/
if(!read_be16(fp,&soi_marker) || JMK_SOI != soi_marker )
goto err; /* not JPEG image*/
MGUI_RWseek (fp, 0, SEEK_SET);
@@ -446,68 +470,48 @@ int __mg_load_jpg (MG_RWops* fp, void* init_info, MYBITMAP *my_bmp,
return ERR_BMP_OK;
}
/**
* loop read JPEG marker from MG_RWops object,until reach SOF0 or SOF2.
* return TRUE if match JPEG image format,or FALSE if the read failed or not JPEG image
*/
BOOL __mg_check_jpg (MG_RWops* fp)
{
unsigned char magic [5];
if (!MGUI_RWread (fp, magic, 2, 1))
return FALSE; /* not JPEG image*/
if (magic[0] != 0xFF || magic[1] != 0xD8)
return FALSE; /* not JPEG image*/
MGUI_RWseek (fp, 0, SEEK_SET);
/* 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;
struct my_error_mgr *jerr;
jpeg_init_info_t* init_info;
/* Step 1: allocate and initialize JPEG decompression object */
cinfo = calloc (1, sizeof(struct jpeg_decompress_struct));
jerr = calloc (1, sizeof(struct my_error_mgr));
init_info = calloc (1, sizeof(jpeg_init_info_t));
if (cinfo == NULL || jerr == NULL || init_info == NULL)
return FALSE;
/* We set up the normal JPEG error routines first. */
cinfo->err = jpeg_std_error (&jerr->pub);
jerr->pub.error_exit = my_error_exit;
/* return value*/
BOOL ret = TRUE;
/* Establish the setjmp return context for my_error_exit to use. */
if (setjmp (jerr->setjmp_buffer))
{
/* If we get here, the JPEG code has signaled an error */
ret = FALSE;
goto end;
for(Uint16 jpeg_marker;read_be16(fp,&jpeg_marker) /* read JPEG marker */;){
/* payload length of current marker */
Uint16 payload = 1; /* set 1 for default, mean that current marker followed by payload bytes*/
switch(jpeg_marker)
{
case JMK_SOI:
payload = 0; /* no payload */
break;
case JMK_SOF0:
case JMK_SOF2:
return TRUE; /* JPEG image*/
case JMK_DHT:
case JMK_DQT:
case JMK_DRI:
case JMK_SOS:
case JMK_COM:
break;
case JMK_EOI:
return FALSE; /* not JPEG image*/
default:
if((0XFFF8 & jpeg_marker) == JMK_RST_mask){
payload = 0; /* RST0~7(FFD0~FFD7),no payload */
}else if((0XFFF0 & jpeg_marker) == JMK_APP_mask){
/* APP0~APP15,do nothing */
}else
return FALSE; /* not JPEG image*/
}
if(payload){
/*read payload length and skip next marker */
if(!read_be16(fp,&payload))
return FALSE; /* not JPEG image*/
MGUI_RWseek (fp, payload- sizeof(payload), SEEK_CUR);
}
}
/* Now we can initialize the JPEG decompression object. */
jpeg_create_decompress (cinfo);
init_info->dec_started = 0;
/* Step 2: specify data source */
my_jpeg_data_src (cinfo, fp);
/* Step 3: read file parameters with jpeg_read_header() */
if(JPEG_HEADER_OK != jpeg_read_header (cinfo, TRUE))
{
longjmp (jerr->setjmp_buffer, 1);
}
end:
jpeg_destroy_decompress (cinfo);
free (init_info);
free (jerr);
free (cinfo);
return ret;
return FALSE; /* not JPEG image*/
}
#endif /* _MGIMAGE_JPG */