+#include <stdio.h>
+#include <stdlib.h>
+
+#include "bytesource.h"
+#include "choice.h"
+#include "dehuff.h"
+#include "input.h"
+
+struct jpeg_image {
+ unsigned precision;
+ unsigned width, height;
+ unsigned num_components;
+ unsigned hsample[256], vsample[256], qtable[256];
+};
+
+ssize_t stdio_read(void* userdata, uint8_t* buf, size_t count)
+{
+ return fread(buf, 1, count, (FILE*)userdata);
+}
+
+void read_sof(struct byte_source* source, struct jpeg_image* image)
+{
+ unsigned len = read_uint16(byte_source_input_func, source);
+ assert(len >= 8);
+ image->precision = read_uint8(byte_source_input_func, source);
+ assert(image->precision == 8);
+ image->width = read_uint16(byte_source_input_func, source);
+ image->height = read_uint16(byte_source_input_func, source);
+ image->num_components = read_uint8(byte_source_input_func, source);
+ len -= 8;
+
+ fprintf(stderr, "%u-bit %ux%u JPEG with %u components\n",
+ image->precision, image->width, image->height, image->num_components);
+
+ for (unsigned i = 0; i < image->num_components; ++i) {
+ assert(len >= 3);
+ unsigned c = read_uint8(byte_source_input_func, source);
+ unsigned sampling_factors = read_uint8(byte_source_input_func, source);
+ image->hsample[c] = sampling_factors >> 4;
+ image->vsample[c] = sampling_factors & 0x0f;
+ image->qtable[c] = read_uint8(byte_source_input_func, source);
+ len -= 3;
+
+ fprintf(stderr, "Component %u: sampling factors %u x %x, quantization table %u\n",
+ c, image->hsample[c], image->vsample[c], image->qtable[c]);
+ }
+}
+
+void read_scan(struct byte_source* source, struct jpeg_image* image, huffman_tables_t* tables)
+{
+ unsigned len = read_uint16(byte_source_input_func, source);
+ assert(len >= 2);
+ len -= 2;
+
+ assert(len >= 1);
+ unsigned num_components = read_uint8(byte_source_input_func, source);
+ --len;
+
+ unsigned component_num[256];
+ unsigned dc_huffman_table[256], ac_huffman_table[256];
+ unsigned ss, se, ah_al;
+ int last_dc[256];
+
+ for (unsigned i = 0; i < num_components; ++i) {
+ unsigned char td_ta;
+ assert(len >= 2);
+ component_num[i] = read_uint8(byte_source_input_func, source);
+ td_ta = read_uint8(byte_source_input_func, source);
+ len -= 2;
+ dc_huffman_table[i] = td_ta >> 4;
+ ac_huffman_table[i] = td_ta & 0x0f;
+ last_dc[i] = 0;
+ }
+
+ assert(len >= 3);
+ ss = read_uint8(byte_source_input_func, source);
+ se = read_uint8(byte_source_input_func, source);
+ ah_al = read_uint8(byte_source_input_func, source);
+ len -= 3;
+
+ if (len != 0) {
+ fprintf(stderr, "Error: %u unused bytes at end of SOS segment\n", len);
+ }
+
+ struct bit_source bits;
+ init_bit_source(&bits, byte_source_input_func, source);
+
+ for ( ;; ) {
+ for (unsigned c = 0; c < num_components; ++c) {
+ unsigned cn = component_num[c];
+ unsigned nc = image->vsample[cn] * image->hsample[cn];
+ for (unsigned n = 0; n < nc; ++n) {
+ const struct huffman_table* dc_table = &((*tables)[DC_CLASS][dc_huffman_table[c]]);
+ const struct huffman_table* ac_table = &((*tables)[AC_CLASS][ac_huffman_table[c]]);
+
+ // decode DC component
+ unsigned dc_category = read_huffman_symbol(dc_table, &bits);
+ possibly_refill(&bits, dc_category);
+ last_dc[c] += extend(read_bits(&bits, dc_category), dc_category);
+
+ // printf("dc=%d ac=", last_dc[c]);
+ putchar(last_dc[c]);
+
+ // decode AC components
+ int zz[63] = { 0 };
+ for (unsigned i = 0; i < 63; ++i) {
+ unsigned rs = read_huffman_symbol(ac_table, &bits);
+ unsigned r = rs >> 4;
+ unsigned s = rs & 0xf;
+
+ if (rs == 0x00) {
+ /* end of block */
+ break;
+ }
+ if (rs == 0xf0) {
+ /* 16 zero coefficients */
+ i += 15;
+ continue;
+ }
+
+ possibly_refill(&bits, s);
+
+ i += r;
+ zz[i] = extend(read_bits(&bits, s), s);
+ }
+
+ for (unsigned i = 0; i < 63; ++i) {
+ putchar(zz[i]);
+ //printf("%d ", zz[i]);
+ }
+ //printf("\n");
+ }
+ }
+ }
+ if (len != 0) {
+ fprintf(stderr, "Error: %u unused bytes at end of SOS segment\n", len);
+ }
+}
+
+void skip_segment(struct byte_source* source)
+{
+ uint8_t buf[4096];
+ for ( ;; ) {
+ ssize_t ret = byte_source_input_func(source, buf, 4096);
+ if (ret == -1) {
+ fprintf(stderr, "Input error!\n");
+ exit(1);
+ }
+ if (ret == 0) {
+ return;
+ }
+ }
+}
+
+int main(void)
+{
+ struct jpeg_image jpeg;
+ init_choices();
+
+ struct byte_source source;
+ init_byte_source(&source, stdio_read, stdin);
+
+ huffman_tables_t tables;
+
+ for ( ;; ) {
+ uint8_t m2 = byte_source_read_marker(&source);
+ assert(m2 != 0x00);
+
+ fprintf(stderr, "Marker 0x%02x, at position %ld\n", m2, ftell(stdin) - source.bytes_available);
+
+ switch (m2) {
+ case 0xe0:
+ case 0xe1:
+ case 0xe2:
+ case 0xe3:
+ case 0xe4:
+ case 0xe5:
+ case 0xe6:
+ case 0xe7:
+ case 0xe8:
+ case 0xe9:
+ case 0xea:
+ case 0xeb:
+ case 0xec:
+ case 0xed:
+ case 0xee:
+ case 0xef:
+ /* APP0 through APPF */
+ case 0xfc:
+ /* some EXIF stuff */
+ case 0xfe:
+ /* comment */
+ case 0xff:
+ /* ignore */
+ case 0xdb:
+ /* DQT */
+ skip_segment(&source);
+ break;
+ case 0xc0:
+ /* SOF0 (baseline DCT, Huffman encoded) */
+ read_sof(&source, &jpeg);
+ break;
+ case 0xd8:
+ /* SOI */
+ break;
+ case 0xc4:
+ /* DHT (define Huffman tables) */
+ read_huffman_tables(&tables, byte_source_input_func, &source);
+ break;
+ case 0xda:
+ /* SOS (start of scan) */
+ read_scan(&source, &jpeg, &tables);
+ break;
+ default:
+ fprintf(stderr, "Error: Unknown marker 0x%02x\n", m2);
+ exit(1);
+ }
+ }
+}