Add support for single channel greyscale JPEGs

This commit is contained in:
Philip Heron 2018-06-13 16:01:43 +01:00
parent 6ff1a1073a
commit 82f383cd77
3 changed files with 36 additions and 14 deletions

3
README
View File

@ -25,7 +25,7 @@ LIMITATIONS
Only JPEG files are supported, with the following limitations: Only JPEG files are supported, with the following limitations:
- YUV/YCbCr colour format - Greyscale or YUV/YCbCr colour formats
- Width and height must be a multiple of 16 (up to a resolution of 4080 x 4080) - Width and height must be a multiple of 16 (up to a resolution of 4080 x 4080)
- Baseline DCT only - Baseline DCT only
- The total number of MCU blocks must not exceed 65535 - The total number of MCU blocks must not exceed 65535
@ -38,5 +38,4 @@ TODO
* Allow the decoder to handle multiple images in the input stream. * Allow the decoder to handle multiple images in the input stream.
* Experiment with adaptive or multiple huffman tables. * Experiment with adaptive or multiple huffman tables.
* Quality setting (4 bit / 16 quality levels).

46
ssdv.c
View File

@ -569,8 +569,22 @@ static char ssdv_process(ssdv_t *s)
if(s->acpart >= 64) if(s->acpart >= 64)
{ {
s->mcupart++;
if(s->greyscale && s->mcupart == s->ycparts)
{
/* For greyscale input images, pad the 2x1 MCUs with empty colour blocks */
for(; s->mcupart < s->ycparts + 2; s->mcupart++)
{
if(s->mcupart < s->ycparts) s->component = 0;
else s->component = s->mcupart - s->ycparts + 1;
s->acpart = 0; ssdv_out_jpeg_int(s, 0, 0); /* DC */
s->acpart = 1; ssdv_out_jpeg_int(s, 0, 0); /* AC */
}
}
/* Reached the end of this MCU part */ /* Reached the end of this MCU part */
if(++s->mcupart == s->ycparts + 2) if(s->mcupart == s->ycparts + 2)
{ {
s->mcupart = 0; s->mcupart = 0;
s->mcu_id++; s->mcu_id++;
@ -722,10 +736,10 @@ static char ssdv_have_marker_data(ssdv_t *s)
return(SSDV_ERROR); return(SSDV_ERROR);
} }
/* The image must have 3 components (Y'Cb'Cr) */ /* The image must have 1 or 3 components (Y'Cb'Cr) */
if(d[5] != 3) if(d[5] != 1 && d[5] != 3)
{ {
fprintf(stderr, "Error: The image must have 3 components\n"); fprintf(stderr, "Error: The image must have 1 or 3 components\n");
return(SSDV_ERROR); return(SSDV_ERROR);
} }
@ -745,7 +759,7 @@ static char ssdv_have_marker_data(ssdv_t *s)
/* TODO: Read in the quantisation table ID for each component */ /* TODO: Read in the quantisation table ID for each component */
// 01 22 00 02 11 01 03 11 01 // 01 22 00 02 11 01 03 11 01
for(i = 0; i < 3; i++) for(i = 0; i < d[5]; i++)
{ {
uint8_t *dq = &d[i * 3 + 6]; uint8_t *dq = &d[i * 3 + 6];
if(dq[0] != i + 1) if(dq[0] != i + 1)
@ -777,6 +791,14 @@ static char ssdv_have_marker_data(ssdv_t *s)
} }
} }
if(d[5] == 1)
{
/* Greyscale images are converted to 2x1 colour images */
s->greyscale = 1;
s->mcu_mode = 2;
s->ycparts = 2;
}
/* Calculate number of MCU blocks in this image */ /* Calculate number of MCU blocks in this image */
switch(s->mcu_mode) switch(s->mcu_mode)
{ {
@ -801,14 +823,14 @@ static char ssdv_have_marker_data(ssdv_t *s)
case J_SOS: case J_SOS:
fprintf(stderr, "Components: %i\n", d[0]); fprintf(stderr, "Components: %i\n", d[0]);
/* The image must have 3 components (Y'Cb'Cr) */ /* The image must have 1 or 3 components (Y'Cb'Cr) */
if(d[0] != 3) if(d[0] != 1 && d[0] != 3)
{ {
fprintf(stderr, "Error: The image must have 3 components\n"); fprintf(stderr, "Error: The image must have 1 or 3 components\n");
return(SSDV_ERROR); return(SSDV_ERROR);
} }
for(i = 0; i < 3; i++) for(i = 0; i < d[0]; i++)
{ {
uint8_t *dh = &d[i * 2 + 1]; uint8_t *dh = &d[i * 2 + 1];
if(dh[0] != i + 1) if(dh[0] != i + 1)
@ -824,14 +846,14 @@ static char ssdv_have_marker_data(ssdv_t *s)
/* 00 3F 00 */ /* 00 3F 00 */
/* Verify all of the DQT and DHT tables where loaded */ /* Verify all of the DQT and DHT tables where loaded */
if(!s->sdqt[0] || !s->sdqt[1]) if(!s->sdqt[0] || (d[0] > 1 && !s->sdqt[1]))
{ {
fprintf(stderr, "Error: The image is missing one or more DQT tables\n"); fprintf(stderr, "Error: The image is missing one or more DQT tables\n");
return(SSDV_ERROR); return(SSDV_ERROR);
} }
if(!s->sdht[0][0] || !s->sdht[0][1] || if(!s->sdht[0][0] || (d[0] > 1 && !s->sdht[0][1]) ||
!s->sdht[1][0] || !s->sdht[1][1]) !s->sdht[1][0] || (d[0] > 1 && !s->sdht[1][1]))
{ {
fprintf(stderr, "Error: The image is missing one or more DHT tables\n"); fprintf(stderr, "Error: The image is missing one or more DHT tables\n");
return(SSDV_ERROR); return(SSDV_ERROR);

1
ssdv.h
View File

@ -99,6 +99,7 @@ typedef struct
uint16_t marker_len; /* Length of data following marker */ uint16_t marker_len; /* Length of data following marker */
uint8_t *marker_data; /* Where to copy marker data too */ uint8_t *marker_data; /* Where to copy marker data too */
uint16_t marker_data_len; /* How much is there */ uint16_t marker_data_len; /* How much is there */
uint8_t greyscale; /* 0 = Normal (3 channels), 1 = Greyscale */
uint8_t component; /* 0 = Y, 1 = Cb, 2 = Cr */ uint8_t component; /* 0 = Y, 1 = Cb, 2 = Cr */
uint8_t ycparts; /* Number of Y component parts per MCU */ uint8_t ycparts; /* Number of Y component parts per MCU */
uint8_t mcupart; /* 0-3 = Y, 4 = Cb, 5 = Cr */ uint8_t mcupart; /* 0-3 = Y, 4 = Cb, 5 = Cr */