fix quantization table loading!
This commit is contained in:
parent
6032c98fae
commit
c27dd2f627
157
src/loader.c
157
src/loader.c
|
@ -11,6 +11,9 @@
|
||||||
static int load_segment(JPEG* jpeg, FILE* fp);
|
static int load_segment(JPEG* jpeg, FILE* fp);
|
||||||
|
|
||||||
static int load_quantization_table(JPEG* jpeg, FILE* fp);
|
static int load_quantization_table(JPEG* jpeg, FILE* fp);
|
||||||
|
static int load_huffman_table(JPEG* jpeg, FILE* fp);
|
||||||
|
static int load_start_of_frame(JPEG* jpeg, FILE* fp, uint8_t type);
|
||||||
|
|
||||||
static int load_rst_segment(JPEG* jpeg, FILE* fp, uint8_t n);
|
static int load_rst_segment(JPEG* jpeg, FILE* fp, uint8_t n);
|
||||||
static int load_app_segment(JPEG* jpeg, FILE* fp, uint8_t n);
|
static int load_app_segment(JPEG* jpeg, FILE* fp, uint8_t n);
|
||||||
|
|
||||||
|
@ -108,6 +111,15 @@ int load_segment(JPEG* jpeg, FILE* fp)
|
||||||
{
|
{
|
||||||
switch (segment_marker[1])
|
switch (segment_marker[1])
|
||||||
{
|
{
|
||||||
|
case 0xC0: case 0xC1: case 0xC2: case 0xC3:
|
||||||
|
case 0xC5: case 0xC6: case 0xC7:
|
||||||
|
case 0xC9: case 0xCA: case 0xCB:
|
||||||
|
case 0xCD: case 0xCE: case 0xCF:
|
||||||
|
return load_start_of_frame(jpeg, fp, segment_marker[1] & 0x0F);
|
||||||
|
|
||||||
|
case 0xC4:
|
||||||
|
return load_huffman_table(jpeg, fp);
|
||||||
|
|
||||||
case 0xD8: // Start of image
|
case 0xD8: // Start of image
|
||||||
DEBUG_LOG("SOI marker encountered");
|
DEBUG_LOG("SOI marker encountered");
|
||||||
break;
|
break;
|
||||||
|
@ -128,6 +140,9 @@ int load_quantization_table(JPEG* jpeg, FILE* fp)
|
||||||
{
|
{
|
||||||
DEBUG_LOG("DQT encountered");
|
DEBUG_LOG("DQT encountered");
|
||||||
|
|
||||||
|
assert(jpeg);
|
||||||
|
assert(fp);
|
||||||
|
|
||||||
if (jpeg->quantization_tables == NULL)
|
if (jpeg->quantization_tables == NULL)
|
||||||
{
|
{
|
||||||
jpeg->quantization_tables = (QuantizationTable*)malloc(sizeof(QuantizationTable) * MAX_QUANTIZATION_TABLES);
|
jpeg->quantization_tables = (QuantizationTable*)malloc(sizeof(QuantizationTable) * MAX_QUANTIZATION_TABLES);
|
||||||
|
@ -138,31 +153,143 @@ int load_quantization_table(JPEG* jpeg, FILE* fp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QuantizationTable* current_table = jpeg->quantization_tables + jpeg->num_quantization_tables;
|
uint16_t total_length;
|
||||||
if (fread(¤t_table->length, sizeof(uint8_t), sizeof(uint16_t), fp) != sizeof(uint16_t))
|
if (fread(&total_length, sizeof(uint8_t), sizeof(uint16_t), fp) != sizeof(uint16_t))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Failed to read quantization table length\n");
|
fprintf(stderr, "Failed to read length of quantization tables\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
jpeg->num_quantization_tables++;
|
total_length = bswap_16(total_length);
|
||||||
current_table->length = bswap_16(current_table->length) - 2;
|
size_t read_length = 2;
|
||||||
DEBUG_LOG("qt length = %u", current_table->length);
|
|
||||||
|
while (read_length < total_length)
|
||||||
current_table->data = (uint8_t*)malloc(sizeof(uint8_t) * current_table->length);
|
|
||||||
if (current_table->data == NULL)
|
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Failed to allocate memory for quantization table data\n");
|
QuantizationTable* current_table = jpeg->quantization_tables + jpeg->num_quantization_tables;
|
||||||
|
|
||||||
|
uint8_t meta_info;
|
||||||
|
if (fread(&meta_info, sizeof(uint8_t), sizeof(uint8_t), fp) != sizeof(uint8_t))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to read quantization table #%d meta info\n", jpeg->num_quantization_tables);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_table->precision = ((meta_info & 0xF) == 0) ? 8 : 16;
|
||||||
|
current_table->destination = (meta_info >> 4);
|
||||||
|
|
||||||
|
size_t table_length = current_table->precision * 64;
|
||||||
|
|
||||||
|
DEBUG_LOG(
|
||||||
|
"Quantization table #%d\n"
|
||||||
|
"\tprecision = %d bit\n"
|
||||||
|
"\tdestination = %d\n",
|
||||||
|
|
||||||
|
jpeg->num_quantization_tables,
|
||||||
|
current_table->precision,
|
||||||
|
current_table->destination
|
||||||
|
);
|
||||||
|
|
||||||
|
current_table->data = (uint8_t*)malloc(table_length);
|
||||||
|
if (current_table->data == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to allocate memory for quantization table #%d data\n", jpeg->num_quantization_tables);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fread(current_table->data, sizeof(uint8_t), table_length, fp) != table_length)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to read quantization table #%d data\n", jpeg->num_quantization_tables);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
jpeg->num_quantization_tables++;
|
||||||
|
read_length += table_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int load_huffman_table(JPEG* jpeg, FILE* fp)
|
||||||
|
{
|
||||||
|
DEBUG_LOG("DHT encountered");
|
||||||
|
|
||||||
|
assert(jpeg);
|
||||||
|
assert(fp);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int load_start_of_frame(JPEG* jpeg, FILE* fp, uint8_t type)
|
||||||
|
{
|
||||||
|
DEBUG_LOG("SOF%u encountered", type);
|
||||||
|
|
||||||
|
assert(jpeg);
|
||||||
|
assert(fp);
|
||||||
|
|
||||||
|
if (jpeg->frame_header != NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Found multiple frames\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t tmp = fread(current_table->data, sizeof(uint8_t), current_table->length, fp);
|
jpeg->frame_header = (FrameHeader*)malloc(sizeof(FrameHeader));
|
||||||
if (tmp != current_table->length)
|
if (jpeg->frame_header == NULL)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Failed to read quantization table data\n");
|
fprintf(stderr, "Failed to allocate memory for frame header\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fread(jpeg->frame_header, sizeof(uint8_t), FRAME_HEADER_SIZE, fp) != FRAME_HEADER_SIZE)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to read data from frame header\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
jpeg->frame_header->length = bswap_16(jpeg->frame_header->length);
|
||||||
|
jpeg->frame_header->num_lines = bswap_16(jpeg->frame_header->num_lines);
|
||||||
|
jpeg->frame_header->num_samples = bswap_16(jpeg->frame_header->num_samples);
|
||||||
|
|
||||||
|
jpeg->frame_header->encoding = type;
|
||||||
|
|
||||||
|
jpeg->frame_header->components = (FrameComponent*)malloc(sizeof(FrameComponent) * jpeg->frame_header->num_components);
|
||||||
|
if (jpeg->frame_header->components == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to allocate memory for frame components\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t c = 0; c < jpeg->frame_header->num_components; c++)
|
||||||
|
{
|
||||||
|
FrameComponent* current_component = jpeg->frame_header->components + c;
|
||||||
|
if (fread(current_component, sizeof(uint8_t), sizeof(FrameComponent), fp) != sizeof(FrameComponent))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Failed to read component #%u\n", c);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_LOG(
|
||||||
|
"Frame header\n"
|
||||||
|
"\tlength = %d\n"
|
||||||
|
"\tprecision = %d\n"
|
||||||
|
"\tlines, samples = %d, %d\n"
|
||||||
|
"\tcomponents = %d\n"
|
||||||
|
"\tencoding = %s %s, %s\n",
|
||||||
|
|
||||||
|
jpeg->frame_header->length,
|
||||||
|
jpeg->frame_header->precision,
|
||||||
|
jpeg->frame_header->num_lines, jpeg->frame_header->num_samples,
|
||||||
|
jpeg->frame_header->num_components,
|
||||||
|
(jpeg->frame_header->encoding & ENCODING_DCT_MASK) == NonDifferential ? "Non-differential" : "Differential",
|
||||||
|
|
||||||
|
(jpeg->frame_header->encoding & ENCODING_PROCESS_MASK) == Baseline ? "baseline DCT" :
|
||||||
|
(jpeg->frame_header->encoding & ENCODING_PROCESS_MASK) == Extended ? "extended sequential DCT" :
|
||||||
|
(jpeg->frame_header->encoding & ENCODING_PROCESS_MASK) == Progressive ? "progressive DCT" : "Lossless (sequential)",
|
||||||
|
|
||||||
|
(jpeg->frame_header->encoding & ENCODING_CODING_MASK) == Huffman ? "huffman coding" : "arithmetic coding"
|
||||||
|
);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -197,6 +324,7 @@ int load_app0_segment(JPEG* jpeg, FILE* fp)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(jpeg);
|
||||||
assert(fp);
|
assert(fp);
|
||||||
|
|
||||||
jpeg->app0 = (JFIFAPP0Segment*)malloc(sizeof(JFIFAPP0Segment));
|
jpeg->app0 = (JFIFAPP0Segment*)malloc(sizeof(JFIFAPP0Segment));
|
||||||
|
@ -209,8 +337,7 @@ int load_app0_segment(JPEG* jpeg, FILE* fp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract header without thumbnail data
|
// Extract header without thumbnail data
|
||||||
size_t jfif_header_size = sizeof(JFIFAPP0Segment) - sizeof(uint8_t*);
|
if (fread(jpeg->app0, sizeof(uint8_t), JFIF_APP0_SIZE, fp) != JFIF_APP0_SIZE)
|
||||||
if (fread(jpeg->app0, sizeof(uint8_t), jfif_header_size, fp) != jfif_header_size)
|
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Incomplete APP0 header\n");
|
fprintf(stderr, "Incomplete APP0 header\n");
|
||||||
return 1;
|
return 1;
|
||||||
|
|
62
src/loader.h
62
src/loader.h
|
@ -4,14 +4,70 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
#define ENCODING_PROCESS_MASK 3
|
||||||
|
#define ENCODING_DCT_MASK 4
|
||||||
|
#define ENCODING_CODING_MASK 8
|
||||||
|
|
||||||
|
typedef enum EncodingProcess
|
||||||
|
{
|
||||||
|
Baseline = 0,
|
||||||
|
Extended = 1,
|
||||||
|
Progressive = 2,
|
||||||
|
Lossless = 3,
|
||||||
|
} EncodingProcess;
|
||||||
|
|
||||||
|
typedef enum Coding
|
||||||
|
{
|
||||||
|
Huffman = 0,
|
||||||
|
Arithmetic = (1 << 3)
|
||||||
|
} Coding;
|
||||||
|
|
||||||
|
typedef enum DCTType
|
||||||
|
{
|
||||||
|
NonDifferential = 0,
|
||||||
|
Differential = (1 << 2)
|
||||||
|
} DCTType;
|
||||||
|
|
||||||
PACK(
|
PACK(
|
||||||
typedef struct QuantizationTable
|
typedef struct QuantizationTable
|
||||||
{
|
{
|
||||||
uint16_t length;
|
uint8_t precision;
|
||||||
|
uint8_t destination;
|
||||||
uint8_t* data;
|
uint8_t* data;
|
||||||
} QuantizationTable;
|
} QuantizationTable;
|
||||||
)
|
)
|
||||||
|
|
||||||
|
#define QUANTIZATION_TABLE_SIZE sizeof(QuantizationTable) - sizeof(uint8_t*)
|
||||||
|
|
||||||
|
PACK(
|
||||||
|
typedef struct FrameComponent
|
||||||
|
{
|
||||||
|
uint8_t identifier;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint8_t v : 4;
|
||||||
|
uint8_t h : 4;
|
||||||
|
} sampling_factor;
|
||||||
|
uint8_t quantization_table;
|
||||||
|
} FrameComponent;
|
||||||
|
)
|
||||||
|
|
||||||
|
PACK(
|
||||||
|
typedef struct FrameHeader
|
||||||
|
{
|
||||||
|
uint16_t length;
|
||||||
|
uint8_t precision;
|
||||||
|
uint16_t num_lines;
|
||||||
|
uint16_t num_samples;
|
||||||
|
uint8_t num_components;
|
||||||
|
|
||||||
|
uint8_t encoding;
|
||||||
|
FrameComponent* components;
|
||||||
|
} FrameHeader;
|
||||||
|
)
|
||||||
|
|
||||||
|
#define FRAME_HEADER_SIZE sizeof(FrameHeader) - (sizeof(FrameComponent*) + sizeof(uint8_t))
|
||||||
|
|
||||||
PACK (
|
PACK (
|
||||||
typedef struct JFIFAPP0Segment
|
typedef struct JFIFAPP0Segment
|
||||||
{
|
{
|
||||||
|
@ -34,12 +90,16 @@ typedef struct JFIFAPP0Segment
|
||||||
} JFIFAPP0Segment;
|
} JFIFAPP0Segment;
|
||||||
)
|
)
|
||||||
|
|
||||||
|
#define JFIF_APP0_SIZE sizeof(JFIFAPP0Segment) - sizeof(uint8_t*)
|
||||||
|
|
||||||
typedef struct JPEG
|
typedef struct JPEG
|
||||||
{
|
{
|
||||||
JFIFAPP0Segment* app0;
|
JFIFAPP0Segment* app0;
|
||||||
|
|
||||||
size_t num_quantization_tables;
|
size_t num_quantization_tables;
|
||||||
QuantizationTable* quantization_tables;
|
QuantizationTable* quantization_tables;
|
||||||
|
|
||||||
|
FrameHeader* frame_header;
|
||||||
} JPEG;
|
} JPEG;
|
||||||
|
|
||||||
JPEG* load_jpeg(const char* filename);
|
JPEG* load_jpeg(const char* filename);
|
||||||
|
|
Loading…
Reference in a new issue