* [PATCH] jpeg image reader @ 2008-01-09 17:21 Bean 2008-01-09 17:56 ` Bean 0 siblings, 1 reply; 23+ messages in thread From: Bean @ 2008-01-09 17:21 UTC (permalink / raw) To: The development of GRUB 2 Hi, this patch handle jpeg image files. diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index a46bc74..4beeeff 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -136,7 +136,7 @@ pkglib_MODULES = biosdisk.mod _chain.mod _linux.mod linux.mod normal.mod \ _multiboot.mod chain.mod multiboot.mod reboot.mod halt.mod \ vbe.mod vbetest.mod vbeinfo.mod video.mod gfxterm.mod \ videotest.mod play.mod bitmap.mod tga.mod cpuid.mod serial.mod \ - ata.mod vga.mod + ata.mod vga.mod jpeg.mod # For biosdisk.mod. biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c @@ -249,6 +249,11 @@ tga_mod_SOURCES = video/readers/tga.c tga_mod_CFLAGS = $(COMMON_CFLAGS) tga_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For jpeg.mod +jpeg_mod_SOURCES = video/readers/jpeg.c +jpeg_mod_CFLAGS = $(COMMON_CFLAGS) +jpeg_mod_LDFLAGS = $(COMMON_LDFLAGS) + # For cpuid.mod. cpuid_mod_SOURCES = commands/i386/cpuid.c cpuid_mod_CFLAGS = $(COMMON_CFLAGS) diff --git a/video/readers/jpeg.c b/video/readers/jpeg.c new file mode 100755 index 0000000..bcbf820 --- /dev/null +++ b/video/readers/jpeg.c @@ -0,0 +1,734 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <grub/bitmap.h> +#include <grub/types.h> +#include <grub/normal.h> +#include <grub/dl.h> +#include <grub/mm.h> +#include <grub/misc.h> +#include <grub/arg.h> +#include <grub/file.h> +#include <grub/setjmp.h> + +/* Uncomment following define to enable JPEG debug. */ +//#define JPEG_DEBUG + +struct grub_jpeg_data +{ + grub_file_t file; + grub_jmp_buf jumper; + + int image_width; + int image_height; + + grub_uint8_t *huff_value[4]; + int huff_offset[4][16]; + int huff_maxval[4][16]; + + grub_uint8_t quan_table[2][64]; + int comp_index[3][3]; + + int ydu[4][64], cbdu[64], crdu[64]; + + int Cr_r_tab[256], Cb_b_tab[256], Cr_g_tab[256], Cb_g_tab[256]; + + int dc_value[3]; + + int bit_mask, bit_save; + + struct grub_video_bitmap **bitmap; +}; + +static grub_uint8_t +get_byte (struct grub_jpeg_data *data) +{ + grub_uint8_t r; + + if (grub_file_read (data->file, (char *) &r, 1) != 1) + grub_longjmp (data->jumper, 1); + + return r; +} + +static unsigned +get_word (struct grub_jpeg_data *data) +{ + unsigned aa, bb; + + aa = get_byte (data); + bb = get_byte (data); + return (aa << 8) + bb; +} + +static int +get_bit (struct grub_jpeg_data *data) +{ + int ret; + + if (data->bit_mask == 0) + { + data->bit_save = get_byte (data); + if (data->bit_save == 0xFF) + { + if (get_byte (data) != 0) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, + "invalid 0xFF in data stream"); + grub_longjmp (data->jumper, 1); + } + } + data->bit_mask = 0x80; + } + + ret = (data->bit_save & data->bit_mask); + data->bit_mask >>= 1; + return ret; +} + +static int +get_huff_leng (struct grub_jpeg_data *data, int num) +{ + int value, i, bit; + + if (num == 0) + return 0; + + bit = get_bit (data); + value = (bit != 0); + for (i = 1; i < num; i++) + value = value * 2 + (get_bit (data) != 0); + if (!bit) + value += 1 - (1 << num); + + return value; +} + +static int +get_huff_base (struct grub_jpeg_data *data, int id) +{ + int code, i; + + code = 0; + for (i = 0; i < 16; i++) + { + code <<= 1; + if (get_bit (data)) + code++; + if (code < data->huff_maxval[id][i]) + return data->huff_value[id][code + data->huff_offset[id][i]]; + } + grub_error (GRUB_ERR_BAD_FILE_TYPE, "huffman decode fails"); + grub_longjmp (data->jumper, 1); + return 0; +} + +static void +decode_huff_table (struct grub_jpeg_data *data) +{ + unsigned id; + int ac, i, n, base, ofs; + grub_uint8_t count[16]; + + get_word (data); + id = get_byte (data); + ac = (id >> 4); + id &= 0xF; + if (id > 1) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, "too many huff table"); + grub_longjmp (data->jumper, 1); + } + + if (grub_file_read (data->file, (char *) &count, sizeof (count)) != + sizeof (count)) + grub_longjmp (data->jumper, 1); + + n = 0; + for (i = 0; i < 16; i++) + n += count[i]; + + id += ac * 2; + if ((data->huff_value[id] = grub_malloc (n)) == NULL) + grub_longjmp (data->jumper, 1); + + if (grub_file_read (data->file, (char *) data->huff_value[id], n) != n) + grub_longjmp (data->jumper, 1); + + base = 0; + ofs = 0; + for (i = 0; i < 16; i++) + { + base += count[i]; + ofs += count[i]; + + data->huff_maxval[id][i] = base; + data->huff_offset[id][i] = ofs - base; + + base <<= 1; + } +} + +static void +decode_quan_table (struct grub_jpeg_data *data) +{ + unsigned id; + + get_word (data); + id = get_byte (data); + if (id >= 0x10) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, + "only 8-bit precision is supported"); + grub_longjmp (data->jumper, 1); + } + + if (id > 1) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, "too many quantization table"); + grub_longjmp (data->jumper, 1); + } + + if (grub_file_read (data->file, (char *) &data->quan_table[id], 64) != 64) + grub_longjmp (data->jumper, 1); +} + +static void +decode_sof (struct grub_jpeg_data *data) +{ + int nc, i; + + get_word (data); + if (get_byte (data) != 8) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, + "only 8-bit precision is supported"); + grub_longjmp (data->jumper, 1); + } + + data->image_height = get_word (data); + data->image_width = get_word (data); + + if ((!data->image_height) || (!data->image_width)) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid image size"); + grub_longjmp (data->jumper, 1); + } + + nc = get_byte (data); + if (nc != 3) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, "component count must be 3"); + grub_longjmp (data->jumper, 1); + } + + for (i = 0; i < nc; i++) + { + int id, ss; + + id = get_byte (data) - 1; + ss = get_byte (data); + if (((!id) && (ss != 0x22)) || ((id) && (ss != 0x11))) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, "only support 2:1:1 sampling"); + grub_longjmp (data->jumper, 1); + } + data->comp_index[id][0] = get_byte (data); + } +} + +#define DCTSIZE 8 + +#define CONST_BITS 8 +#define PASS1_BITS 2 + +#define FIX_1_082392200 ((int) 277) /* FIX(1.082392200) */ +#define FIX_1_414213562 ((int) 362) /* FIX(1.414213562) */ +#define FIX_1_847759065 ((int) 473) /* FIX(1.847759065) */ +#define FIX_2_613125930 ((int) 669) /* FIX(2.613125930) */ + +#define ONE ((long) 1) +#define DESCALE(x,n) (((x) + (ONE << ((n)-1))) >> (n)) + +#define MULTIPLY(var,const) DESCALE((var) * (const), CONST_BITS) + +static const unsigned char natural_order[64] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 +}; + +static const short aanscales[64] = { + /* precomputed values scaled up by 14 bits */ + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, + 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, + 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, + 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, + 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 +}; + +static void +idct_transform (int *du) +{ + int *pd; + int ctr; + int tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + int tmp10, tmp11, tmp12, tmp13; + int z5, z10, z11, z12, z13; + + /* Pass 1: process columns from input, store into work array. */ + + pd = du; + for (ctr = DCTSIZE; ctr > 0; ctr--) + { + if ((pd[DCTSIZE * 1] | pd[DCTSIZE * 2] | pd[DCTSIZE * 3] | + pd[DCTSIZE * 4] | pd[DCTSIZE * 5] | pd[DCTSIZE * 6] | + pd[DCTSIZE * 7]) == 0) + { + pd[DCTSIZE * 1] = pd[DCTSIZE * 2] + = pd[DCTSIZE * 3] = pd[DCTSIZE * 4] + = pd[DCTSIZE * 5] = pd[DCTSIZE * 6] + = pd[DCTSIZE * 7] = pd[DCTSIZE * 0]; + + pd++; /* advance pointers to next column */ + continue; + } + + /* Even part */ + + tmp0 = pd[DCTSIZE * 0]; + tmp1 = pd[DCTSIZE * 2]; + tmp2 = pd[DCTSIZE * 4]; + tmp3 = pd[DCTSIZE * 6]; + + tmp10 = tmp0 + tmp2; /* phase 3 */ + tmp11 = tmp0 - tmp2; + + tmp13 = tmp1 + tmp3; /* phases 5-3 */ + tmp12 = MULTIPLY (tmp1 - tmp3, FIX_1_414213562) - tmp13; /* 2*c4 */ + + tmp0 = tmp10 + tmp13; /* phase 2 */ + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + tmp4 = pd[DCTSIZE * 1]; + tmp5 = pd[DCTSIZE * 3]; + tmp6 = pd[DCTSIZE * 5]; + tmp7 = pd[DCTSIZE * 7]; + + z13 = tmp6 + tmp5; /* phase 6 */ + z10 = tmp6 - tmp5; + z11 = tmp4 + tmp7; + z12 = tmp4 - tmp7; + + tmp7 = z11 + z13; /* phase 5 */ + tmp11 = MULTIPLY (z11 - z13, FIX_1_414213562); /* 2*c4 */ + + z5 = MULTIPLY (z10 + z12, FIX_1_847759065); /* 2*c2 */ + tmp10 = MULTIPLY (z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */ + tmp12 = MULTIPLY (z10, -FIX_2_613125930) + z5; /* -2*(c2+c6) */ + + + tmp6 = tmp12 - tmp7; /* phase 2 */ + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + + pd[DCTSIZE * 0] = (int) (tmp0 + tmp7); + pd[DCTSIZE * 7] = (int) (tmp0 - tmp7); + pd[DCTSIZE * 1] = (int) (tmp1 + tmp6); + pd[DCTSIZE * 6] = (int) (tmp1 - tmp6); + pd[DCTSIZE * 2] = (int) (tmp2 + tmp5); + pd[DCTSIZE * 5] = (int) (tmp2 - tmp5); + pd[DCTSIZE * 4] = (int) (tmp3 + tmp4); + pd[DCTSIZE * 3] = (int) (tmp3 - tmp4); + + pd++; /* advance pointers to next column */ + } + + /* Pass 2: process rows from work array, store into output array. */ + /* Note that we must descale the results by a factor of 8 == 2**3, */ + /* and also undo the PASS1_BITS scaling. */ + + pd = du; + for (ctr = 0; ctr < DCTSIZE; ctr++) + { + /* Even part */ + + tmp10 = pd[0] + pd[4]; + tmp11 = pd[0] - pd[4]; + + tmp13 = pd[2] + pd[6]; + tmp12 = MULTIPLY (pd[2] - pd[6], FIX_1_414213562) - tmp13; + + tmp0 = tmp10 + tmp13; + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + z13 = pd[5] + pd[3]; + z10 = pd[5] - pd[3]; + z11 = pd[1] + pd[7]; + z12 = pd[1] - pd[7]; + + tmp7 = z11 + z13; /* phase 5 */ + tmp11 = MULTIPLY (z11 - z13, FIX_1_414213562); /* 2*c4 */ + + z5 = MULTIPLY (z10 + z12, FIX_1_847759065); /* 2*c2 */ + tmp10 = MULTIPLY (z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */ + tmp12 = MULTIPLY (z10, -FIX_2_613125930) + z5; /* -2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; /* phase 2 */ + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + + /* Final output stage: scale down by a factor of 8 and range-limit */ + + pd[0] = DESCALE (tmp0 + tmp7, PASS1_BITS + 3) + 128; + pd[7] = DESCALE (tmp0 - tmp7, PASS1_BITS + 3) + 128; + pd[1] = DESCALE (tmp1 + tmp6, PASS1_BITS + 3) + 128; + pd[6] = DESCALE (tmp1 - tmp6, PASS1_BITS + 3) + 128; + pd[2] = DESCALE (tmp2 + tmp5, PASS1_BITS + 3) + 128; + pd[5] = DESCALE (tmp2 - tmp5, PASS1_BITS + 3) + 128; + pd[4] = DESCALE (tmp3 + tmp4, PASS1_BITS + 3) + 128; + pd[3] = DESCALE (tmp3 - tmp4, PASS1_BITS + 3) + 128; + + pd += DCTSIZE; /* advance pointer to next row */ + } + + for (ctr = 0; ctr < 64; ctr++) + { + if (du[ctr] < 0) + du[ctr] = 0; + if (du[ctr] > 255) + du[ctr] = 255; + } +} + +static void +decode_du (struct grub_jpeg_data *data, int id, int *du) +{ + int pos, h1, h2, qt; + + grub_memset (du, 0, sizeof (int) * 64); + + qt = data->comp_index[id][0]; + h1 = data->comp_index[id][1]; + h2 = data->comp_index[id][2]; + + data->dc_value[id] += get_huff_leng (data, get_huff_base (data, h1)); + + du[0] = + data->dc_value[id] * DESCALE ((int) data->quan_table[qt][0] * + (int) aanscales[0], 14 - 2); + pos = 1; + while (pos < 64) + { + int num, val; + + num = get_huff_base (data, h2); + if (!num) + break; + val = get_huff_leng (data, num & 0xF); + num >>= 4; + pos += num; + du[natural_order[pos]] = + val * DESCALE ((int) data->quan_table[qt][pos] * + (int) aanscales[natural_order[pos]], 14 - 2); + pos++; + } + + idct_transform (du); +} + +#define SCALEBITS 16 /* speediest right-shift on some machines */ +#define ONE_HALF ((int) 1 << (SCALEBITS-1)) +#define FIX(x) ((int) ((x) * (1L<<SCALEBITS) + 0.5)) + +static void +build_color_table (struct grub_jpeg_data *data) +{ + int i, x; + + for (i = 0, x = -128; i <= 255; i++, x++) + { + data->Cr_r_tab[i] = (int) (FIX (1.40200) * x + ONE_HALF) >> SCALEBITS; + data->Cb_b_tab[i] = (int) (FIX (1.77200) * x + ONE_HALF) >> SCALEBITS; + data->Cr_g_tab[i] = (-FIX (0.71414)) * x; + data->Cb_g_tab[i] = (-FIX (0.34414)) * x + ONE_HALF; + } +} + +static void +decode_sos (struct grub_jpeg_data *data) +{ + int nc, i, r1, c1; + grub_uint8_t *ptr; + + get_word (data); + nc = get_byte (data); + + if (nc != 3) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, "component count must be 3"); + grub_longjmp (data->jumper, 1); + } + + for (i = 0; i < nc; i++) + { + int id, ht; + + id = get_byte (data) - 1; + ht = get_byte (data); + data->comp_index[id][1] = (ht >> 4); + data->comp_index[id][2] = (ht & 0xF) + 2; + } + + get_byte (data); + get_word (data); + + if (grub_video_bitmap_create (data->bitmap, data->image_width, + data->image_height, + GRUB_VIDEO_BLIT_FORMAT_R8G8B8)) + grub_longjmp (data->jumper, 1); + + ptr = (*data->bitmap)->data; + data->bit_mask = 0x0; + + for (r1 = 0; r1 < (data->image_height >> 4); r1++) + for (c1 = 0; c1 < (data->image_width >> 4); c1++) + { + int r2, c2, r3, c3; + + decode_du (data, 0, &data->ydu[0][0]); + decode_du (data, 0, &data->ydu[1][0]); + + decode_du (data, 0, &data->ydu[2][0]); + decode_du (data, 0, &data->ydu[3][0]); + + decode_du (data, 1, &data->cbdu[0]); + decode_du (data, 2, &data->crdu[0]); + + for (r2 = 0; r2 < 2; r2++) + for (c2 = 0; c2 < 2; c2++) + for (r3 = 0; r3 < 8; r3++) + for (c3 = 0; c3 < 8; c3++) + { + int i0, i1, i2, cr, cb, dd; + + i0 = + ((r1 * 16 + r2 * 8 + r3) * (data->image_width) + c1 * 16 + + c2 * 8 + c3) * 3; + i1 = r3 * 8 + c3; + i2 = (r2 * 32 + c2 * 4) + (r3 >> 1) * 8 + (c3 >> 1); + + cr = data->crdu[i2]; + cb = data->cbdu[i2]; + + // Red + dd = data->ydu[r2 * 2 + c2][i1] + data->Cr_r_tab[cr]; + if (dd < 0) + dd = 0; + ptr[i0] = dd; + + // Green + dd = + data->ydu[r2 * 2 + c2][i1] + + ((data->Cb_g_tab[cb] + data->Cr_g_tab[cr]) >> SCALEBITS); + if (dd < 0) + dd = 0; + ptr[i0 + 1] = dd; + + // Blue + dd = data->ydu[r2 * 2 + c2][i1] + data->Cb_b_tab[cb]; + if (dd < 0) + dd = 0; + ptr[i0 + 2] = dd; + } + } +} + + +static grub_uint8_t +get_marker (struct grub_jpeg_data *data) +{ + grub_uint8_t r; + + r = get_byte (data); + + if (r != 0xFF) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid maker"); + grub_longjmp (data->jumper, 1); + } + + return get_byte (data); +} + +static void +decode_jpeg (struct grub_jpeg_data *data) +{ + build_color_table (data); + + if (get_marker (data) != 0xD8) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid jpeg file"); + grub_longjmp (data->jumper, 1); + } + + while (1) + { + grub_uint8_t marker; + + marker = get_marker (data); +#ifdef JPEG_DEBUG + grub_printf ("marker: %x\n", marker); +#endif + switch (marker) + { + case 0xc4: + decode_huff_table (data); + break; + case 0xdb: + decode_quan_table (data); + break; + case 0xc0: + decode_sof (data); + break; + case 0xda: + decode_sos (data); + break; + case 0xd9: + return; + case 0xe0: + case 0xfe: + { + unsigned sz; + + sz = get_word (data); + grub_file_seek (data->file, data->file->offset + sz - 2); + break; + } + default: + grub_error (GRUB_ERR_BAD_FILE_TYPE, "unrecognized marker %x", + marker); + grub_longjmp (data->jumper, 1); + } + } +} + +static grub_err_t +grub_video_reader_jpeg (struct grub_video_bitmap **bitmap, + const char *filename) +{ + grub_file_t file; + struct grub_jpeg_data *data; + + file = grub_file_open (filename); + if (!file) + return grub_errno; + + if ((data = grub_malloc (sizeof (*data))) != NULL) + { + int i; + + grub_memset (data, 0, sizeof (*data)); + data->file = file; + data->bitmap = bitmap; + if (!grub_setjmp (data->jumper)) + decode_jpeg (data); + + for (i = 0; i < 4; i++) + if (data->huff_value[i]) + grub_free (data->huff_value[i]); + grub_free (data); + } + + if ((grub_errno != GRUB_ERR_NONE) && (*bitmap)) + { + grub_video_bitmap_destroy (*bitmap); + *bitmap = 0; + } + + grub_file_close (file); + return grub_errno; +} + +#if defined(JPEG_DEBUG) +static grub_err_t +grub_cmd_jpegtest (struct grub_arg_list *state __attribute__ ((unused)), + int argc, char **args) +{ + struct grub_video_bitmap *bitmap = 0; + + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); + + grub_video_reader_jpeg (&bitmap, args[0]); + if (grub_errno != GRUB_ERR_NONE) + return grub_errno; + + grub_video_bitmap_destroy (bitmap); + + return GRUB_ERR_NONE; +} +#endif + +static struct grub_video_bitmap_reader jpg_reader = { + .extension = ".jpg", + .reader = grub_video_reader_jpeg, + .next = 0 +}; + +static struct grub_video_bitmap_reader jpeg_reader = { + .extension = ".jpeg", + .reader = grub_video_reader_jpeg, + .next = 0 +}; + +GRUB_MOD_INIT (video_reader_jpeg) +{ + grub_video_bitmap_reader_register (&jpg_reader); + grub_video_bitmap_reader_register (&jpeg_reader); +#if defined(JPEG_DEBUG) + grub_register_command ("jpegtest", grub_cmd_jpegtest, + GRUB_COMMAND_FLAG_BOTH, "jpegtest FILE", + "Tests loading of JPEG bitmap.", 0); +#endif +} + +GRUB_MOD_FINI (video_reader_jpeg) +{ +#if defined(JPEG_DEBUG) + grub_unregister_command ("jpegtest"); +#endif + grub_video_bitmap_reader_unregister (&jpeg_reader); + grub_video_bitmap_reader_unregister (&jpg_reader); +} -- Bean ^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [PATCH] jpeg image reader 2008-01-09 17:21 [PATCH] jpeg image reader Bean @ 2008-01-09 17:56 ` Bean 2008-01-09 20:33 ` Vesa Jääskeläinen 0 siblings, 1 reply; 23+ messages in thread From: Bean @ 2008-01-09 17:56 UTC (permalink / raw) To: The development of GRUB 2 Hi, I just fix a small bug that can cause color distortion, here is the new patch. diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index a46bc74..4beeeff 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -136,7 +136,7 @@ pkglib_MODULES = biosdisk.mod _chain.mod _linux.mod linux.mod normal.mod \ _multiboot.mod chain.mod multiboot.mod reboot.mod halt.mod \ vbe.mod vbetest.mod vbeinfo.mod video.mod gfxterm.mod \ videotest.mod play.mod bitmap.mod tga.mod cpuid.mod serial.mod \ - ata.mod vga.mod + ata.mod vga.mod jpeg.mod # For biosdisk.mod. biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c @@ -249,6 +249,11 @@ tga_mod_SOURCES = video/readers/tga.c tga_mod_CFLAGS = $(COMMON_CFLAGS) tga_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For jpeg.mod +jpeg_mod_SOURCES = video/readers/jpeg.c +jpeg_mod_CFLAGS = $(COMMON_CFLAGS) +jpeg_mod_LDFLAGS = $(COMMON_LDFLAGS) + # For cpuid.mod. cpuid_mod_SOURCES = commands/i386/cpuid.c cpuid_mod_CFLAGS = $(COMMON_CFLAGS) diff --git a/video/readers/jpeg.c b/video/readers/jpeg.c new file mode 100755 index 0000000..bcbf820 --- /dev/null +++ b/video/readers/jpeg.c @@ -0,0 +1,734 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <grub/bitmap.h> +#include <grub/types.h> +#include <grub/normal.h> +#include <grub/dl.h> +#include <grub/mm.h> +#include <grub/misc.h> +#include <grub/arg.h> +#include <grub/file.h> +#include <grub/setjmp.h> + +/* Uncomment following define to enable JPEG debug. */ +//#define JPEG_DEBUG + +struct grub_jpeg_data +{ + grub_file_t file; + grub_jmp_buf jumper; + + int image_width; + int image_height; + + grub_uint8_t *huff_value[4]; + int huff_offset[4][16]; + int huff_maxval[4][16]; + + grub_uint8_t quan_table[2][64]; + int comp_index[3][3]; + + int ydu[4][64], cbdu[64], crdu[64]; + + int Cr_r_tab[256], Cb_b_tab[256], Cr_g_tab[256], Cb_g_tab[256]; + + int dc_value[3]; + + int bit_mask, bit_save; + + struct grub_video_bitmap **bitmap; +}; + +static grub_uint8_t +get_byte (struct grub_jpeg_data *data) +{ + grub_uint8_t r; + + if (grub_file_read (data->file, (char *) &r, 1) != 1) + grub_longjmp (data->jumper, 1); + + return r; +} + +static unsigned +get_word (struct grub_jpeg_data *data) +{ + unsigned aa, bb; + + aa = get_byte (data); + bb = get_byte (data); + return (aa << 8) + bb; +} + +static int +get_bit (struct grub_jpeg_data *data) +{ + int ret; + + if (data->bit_mask == 0) + { + data->bit_save = get_byte (data); + if (data->bit_save == 0xFF) + { + if (get_byte (data) != 0) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, + "invalid 0xFF in data stream"); + grub_longjmp (data->jumper, 1); + } + } + data->bit_mask = 0x80; + } + + ret = (data->bit_save & data->bit_mask); + data->bit_mask >>= 1; + return ret; +} + +static int +get_huff_leng (struct grub_jpeg_data *data, int num) +{ + int value, i, bit; + + if (num == 0) + return 0; + + bit = get_bit (data); + value = (bit != 0); + for (i = 1; i < num; i++) + value = value * 2 + (get_bit (data) != 0); + if (!bit) + value += 1 - (1 << num); + + return value; +} + +static int +get_huff_base (struct grub_jpeg_data *data, int id) +{ + int code, i; + + code = 0; + for (i = 0; i < 16; i++) + { + code <<= 1; + if (get_bit (data)) + code++; + if (code < data->huff_maxval[id][i]) + return data->huff_value[id][code + data->huff_offset[id][i]]; + } + grub_error (GRUB_ERR_BAD_FILE_TYPE, "huffman decode fails"); + grub_longjmp (data->jumper, 1); + return 0; +} + +static void +decode_huff_table (struct grub_jpeg_data *data) +{ + unsigned id; + int ac, i, n, base, ofs; + grub_uint8_t count[16]; + + get_word (data); + id = get_byte (data); + ac = (id >> 4); + id &= 0xF; + if (id > 1) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, "too many huff table"); + grub_longjmp (data->jumper, 1); + } + + if (grub_file_read (data->file, (char *) &count, sizeof (count)) != + sizeof (count)) + grub_longjmp (data->jumper, 1); + + n = 0; + for (i = 0; i < 16; i++) + n += count[i]; + + id += ac * 2; + if ((data->huff_value[id] = grub_malloc (n)) == NULL) + grub_longjmp (data->jumper, 1); + + if (grub_file_read (data->file, (char *) data->huff_value[id], n) != n) + grub_longjmp (data->jumper, 1); + + base = 0; + ofs = 0; + for (i = 0; i < 16; i++) + { + base += count[i]; + ofs += count[i]; + + data->huff_maxval[id][i] = base; + data->huff_offset[id][i] = ofs - base; + + base <<= 1; + } +} + +static void +decode_quan_table (struct grub_jpeg_data *data) +{ + unsigned id; + + get_word (data); + id = get_byte (data); + if (id >= 0x10) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, + "only 8-bit precision is supported"); + grub_longjmp (data->jumper, 1); + } + + if (id > 1) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, "too many quantization table"); + grub_longjmp (data->jumper, 1); + } + + if (grub_file_read (data->file, (char *) &data->quan_table[id], 64) != 64) + grub_longjmp (data->jumper, 1); +} + +static void +decode_sof (struct grub_jpeg_data *data) +{ + int nc, i; + + get_word (data); + if (get_byte (data) != 8) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, + "only 8-bit precision is supported"); + grub_longjmp (data->jumper, 1); + } + + data->image_height = get_word (data); + data->image_width = get_word (data); + + if ((!data->image_height) || (!data->image_width)) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid image size"); + grub_longjmp (data->jumper, 1); + } + + nc = get_byte (data); + if (nc != 3) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, "component count must be 3"); + grub_longjmp (data->jumper, 1); + } + + for (i = 0; i < nc; i++) + { + int id, ss; + + id = get_byte (data) - 1; + ss = get_byte (data); + if (((!id) && (ss != 0x22)) || ((id) && (ss != 0x11))) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, "only support 2:1:1 sampling"); + grub_longjmp (data->jumper, 1); + } + data->comp_index[id][0] = get_byte (data); + } +} + +#define DCTSIZE 8 + +#define CONST_BITS 8 +#define PASS1_BITS 2 + +#define FIX_1_082392200 ((int) 277) /* FIX(1.082392200) */ +#define FIX_1_414213562 ((int) 362) /* FIX(1.414213562) */ +#define FIX_1_847759065 ((int) 473) /* FIX(1.847759065) */ +#define FIX_2_613125930 ((int) 669) /* FIX(2.613125930) */ + +#define ONE ((long) 1) +#define DESCALE(x,n) (((x) + (ONE << ((n)-1))) >> (n)) + +#define MULTIPLY(var,const) DESCALE((var) * (const), CONST_BITS) + +static const unsigned char natural_order[64] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 +}; + +static const short aanscales[64] = { + /* precomputed values scaled up by 14 bits */ + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, + 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, + 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, + 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, + 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 +}; + +static void +idct_transform (int *du) +{ + int *pd; + int ctr; + int tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + int tmp10, tmp11, tmp12, tmp13; + int z5, z10, z11, z12, z13; + + /* Pass 1: process columns from input, store into work array. */ + + pd = du; + for (ctr = DCTSIZE; ctr > 0; ctr--) + { + if ((pd[DCTSIZE * 1] | pd[DCTSIZE * 2] | pd[DCTSIZE * 3] | + pd[DCTSIZE * 4] | pd[DCTSIZE * 5] | pd[DCTSIZE * 6] | + pd[DCTSIZE * 7]) == 0) + { + pd[DCTSIZE * 1] = pd[DCTSIZE * 2] + = pd[DCTSIZE * 3] = pd[DCTSIZE * 4] + = pd[DCTSIZE * 5] = pd[DCTSIZE * 6] + = pd[DCTSIZE * 7] = pd[DCTSIZE * 0]; + + pd++; /* advance pointers to next column */ + continue; + } + + /* Even part */ + + tmp0 = pd[DCTSIZE * 0]; + tmp1 = pd[DCTSIZE * 2]; + tmp2 = pd[DCTSIZE * 4]; + tmp3 = pd[DCTSIZE * 6]; + + tmp10 = tmp0 + tmp2; /* phase 3 */ + tmp11 = tmp0 - tmp2; + + tmp13 = tmp1 + tmp3; /* phases 5-3 */ + tmp12 = MULTIPLY (tmp1 - tmp3, FIX_1_414213562) - tmp13; /* 2*c4 */ + + tmp0 = tmp10 + tmp13; /* phase 2 */ + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + tmp4 = pd[DCTSIZE * 1]; + tmp5 = pd[DCTSIZE * 3]; + tmp6 = pd[DCTSIZE * 5]; + tmp7 = pd[DCTSIZE * 7]; + + z13 = tmp6 + tmp5; /* phase 6 */ + z10 = tmp6 - tmp5; + z11 = tmp4 + tmp7; + z12 = tmp4 - tmp7; + + tmp7 = z11 + z13; /* phase 5 */ + tmp11 = MULTIPLY (z11 - z13, FIX_1_414213562); /* 2*c4 */ + + z5 = MULTIPLY (z10 + z12, FIX_1_847759065); /* 2*c2 */ + tmp10 = MULTIPLY (z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */ + tmp12 = MULTIPLY (z10, -FIX_2_613125930) + z5; /* -2*(c2+c6) */ + + + tmp6 = tmp12 - tmp7; /* phase 2 */ + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + + pd[DCTSIZE * 0] = (int) (tmp0 + tmp7); + pd[DCTSIZE * 7] = (int) (tmp0 - tmp7); + pd[DCTSIZE * 1] = (int) (tmp1 + tmp6); + pd[DCTSIZE * 6] = (int) (tmp1 - tmp6); + pd[DCTSIZE * 2] = (int) (tmp2 + tmp5); + pd[DCTSIZE * 5] = (int) (tmp2 - tmp5); + pd[DCTSIZE * 4] = (int) (tmp3 + tmp4); + pd[DCTSIZE * 3] = (int) (tmp3 - tmp4); + + pd++; /* advance pointers to next column */ + } + + /* Pass 2: process rows from work array, store into output array. */ + /* Note that we must descale the results by a factor of 8 == 2**3, */ + /* and also undo the PASS1_BITS scaling. */ + + pd = du; + for (ctr = 0; ctr < DCTSIZE; ctr++) + { + /* Even part */ + + tmp10 = pd[0] + pd[4]; + tmp11 = pd[0] - pd[4]; + + tmp13 = pd[2] + pd[6]; + tmp12 = MULTIPLY (pd[2] - pd[6], FIX_1_414213562) - tmp13; + + tmp0 = tmp10 + tmp13; + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + z13 = pd[5] + pd[3]; + z10 = pd[5] - pd[3]; + z11 = pd[1] + pd[7]; + z12 = pd[1] - pd[7]; + + tmp7 = z11 + z13; /* phase 5 */ + tmp11 = MULTIPLY (z11 - z13, FIX_1_414213562); /* 2*c4 */ + + z5 = MULTIPLY (z10 + z12, FIX_1_847759065); /* 2*c2 */ + tmp10 = MULTIPLY (z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */ + tmp12 = MULTIPLY (z10, -FIX_2_613125930) + z5; /* -2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; /* phase 2 */ + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + + /* Final output stage: scale down by a factor of 8 and range-limit */ + + pd[0] = DESCALE (tmp0 + tmp7, PASS1_BITS + 3) + 128; + pd[7] = DESCALE (tmp0 - tmp7, PASS1_BITS + 3) + 128; + pd[1] = DESCALE (tmp1 + tmp6, PASS1_BITS + 3) + 128; + pd[6] = DESCALE (tmp1 - tmp6, PASS1_BITS + 3) + 128; + pd[2] = DESCALE (tmp2 + tmp5, PASS1_BITS + 3) + 128; + pd[5] = DESCALE (tmp2 - tmp5, PASS1_BITS + 3) + 128; + pd[4] = DESCALE (tmp3 + tmp4, PASS1_BITS + 3) + 128; + pd[3] = DESCALE (tmp3 - tmp4, PASS1_BITS + 3) + 128; + + pd += DCTSIZE; /* advance pointer to next row */ + } + + for (ctr = 0; ctr < 64; ctr++) + { + if (du[ctr] < 0) + du[ctr] = 0; + if (du[ctr] > 255) + du[ctr] = 255; + } +} + +static void +decode_du (struct grub_jpeg_data *data, int id, int *du) +{ + int pos, h1, h2, qt; + + grub_memset (du, 0, sizeof (int) * 64); + + qt = data->comp_index[id][0]; + h1 = data->comp_index[id][1]; + h2 = data->comp_index[id][2]; + + data->dc_value[id] += get_huff_leng (data, get_huff_base (data, h1)); + + du[0] = + data->dc_value[id] * DESCALE ((int) data->quan_table[qt][0] * + (int) aanscales[0], 14 - 2); + pos = 1; + while (pos < 64) + { + int num, val; + + num = get_huff_base (data, h2); + if (!num) + break; + val = get_huff_leng (data, num & 0xF); + num >>= 4; + pos += num; + du[natural_order[pos]] = + val * DESCALE ((int) data->quan_table[qt][pos] * + (int) aanscales[natural_order[pos]], 14 - 2); + pos++; + } + + idct_transform (du); +} + +#define SCALEBITS 16 /* speediest right-shift on some machines */ +#define ONE_HALF ((int) 1 << (SCALEBITS-1)) +#define FIX(x) ((int) ((x) * (1L<<SCALEBITS) + 0.5)) + +static void +build_color_table (struct grub_jpeg_data *data) +{ + int i, x; + + for (i = 0, x = -128; i <= 255; i++, x++) + { + data->Cr_r_tab[i] = (int) (FIX (1.40200) * x + ONE_HALF) >> SCALEBITS; + data->Cb_b_tab[i] = (int) (FIX (1.77200) * x + ONE_HALF) >> SCALEBITS; + data->Cr_g_tab[i] = (-FIX (0.71414)) * x; + data->Cb_g_tab[i] = (-FIX (0.34414)) * x + ONE_HALF; + } +} + +static void +decode_sos (struct grub_jpeg_data *data) +{ + int nc, i, r1, c1; + grub_uint8_t *ptr; + + get_word (data); + nc = get_byte (data); + + if (nc != 3) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, "component count must be 3"); + grub_longjmp (data->jumper, 1); + } + + for (i = 0; i < nc; i++) + { + int id, ht; + + id = get_byte (data) - 1; + ht = get_byte (data); + data->comp_index[id][1] = (ht >> 4); + data->comp_index[id][2] = (ht & 0xF) + 2; + } + + get_byte (data); + get_word (data); + + if (grub_video_bitmap_create (data->bitmap, data->image_width, + data->image_height, + GRUB_VIDEO_BLIT_FORMAT_R8G8B8)) + grub_longjmp (data->jumper, 1); + + ptr = (*data->bitmap)->data; + data->bit_mask = 0x0; + + for (r1 = 0; r1 < (data->image_height >> 4); r1++) + for (c1 = 0; c1 < (data->image_width >> 4); c1++) + { + int r2, c2, r3, c3; + + decode_du (data, 0, &data->ydu[0][0]); + decode_du (data, 0, &data->ydu[1][0]); + + decode_du (data, 0, &data->ydu[2][0]); + decode_du (data, 0, &data->ydu[3][0]); + + decode_du (data, 1, &data->cbdu[0]); + decode_du (data, 2, &data->crdu[0]); + + for (r2 = 0; r2 < 2; r2++) + for (c2 = 0; c2 < 2; c2++) + for (r3 = 0; r3 < 8; r3++) + for (c3 = 0; c3 < 8; c3++) + { + int i0, i1, i2, cr, cb, dd; + + i0 = + ((r1 * 16 + r2 * 8 + r3) * (data->image_width) + c1 * 16 + + c2 * 8 + c3) * 3; + i1 = r3 * 8 + c3; + i2 = (r2 * 32 + c2 * 4) + (r3 >> 1) * 8 + (c3 >> 1); + + cr = data->crdu[i2]; + cb = data->cbdu[i2]; + + // Red + dd = data->ydu[r2 * 2 + c2][i1] + data->Cr_r_tab[cr]; + if (dd < 0) + dd = 0; + ptr[i0] = dd; + + // Green + dd = + data->ydu[r2 * 2 + c2][i1] + + ((data->Cb_g_tab[cb] + data->Cr_g_tab[cr]) >> SCALEBITS); + if (dd < 0) + dd = 0; + ptr[i0 + 1] = dd; + + // Blue + dd = data->ydu[r2 * 2 + c2][i1] + data->Cb_b_tab[cb]; + if (dd < 0) + dd = 0; + ptr[i0 + 2] = dd; + } + } +} + + +static grub_uint8_t +get_marker (struct grub_jpeg_data *data) +{ + grub_uint8_t r; + + r = get_byte (data); + + if (r != 0xFF) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid maker"); + grub_longjmp (data->jumper, 1); + } + + return get_byte (data); +} + +static void +decode_jpeg (struct grub_jpeg_data *data) +{ + build_color_table (data); + + if (get_marker (data) != 0xD8) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid jpeg file"); + grub_longjmp (data->jumper, 1); + } + + while (1) + { + grub_uint8_t marker; + + marker = get_marker (data); +#ifdef JPEG_DEBUG + grub_printf ("marker: %x\n", marker); +#endif + switch (marker) + { + case 0xc4: + decode_huff_table (data); + break; + case 0xdb: + decode_quan_table (data); + break; + case 0xc0: + decode_sof (data); + break; + case 0xda: + decode_sos (data); + break; + case 0xd9: + return; + case 0xe0: + case 0xfe: + { + unsigned sz; + + sz = get_word (data); + grub_file_seek (data->file, data->file->offset + sz - 2); + break; + } + default: + grub_error (GRUB_ERR_BAD_FILE_TYPE, "unrecognized marker %x", + marker); + grub_longjmp (data->jumper, 1); + } + } +} + +static grub_err_t +grub_video_reader_jpeg (struct grub_video_bitmap **bitmap, + const char *filename) +{ + grub_file_t file; + struct grub_jpeg_data *data; + + file = grub_file_open (filename); + if (!file) + return grub_errno; + + if ((data = grub_malloc (sizeof (*data))) != NULL) + { + int i; + + grub_memset (data, 0, sizeof (*data)); + data->file = file; + data->bitmap = bitmap; + if (!grub_setjmp (data->jumper)) + decode_jpeg (data); + + for (i = 0; i < 4; i++) + if (data->huff_value[i]) + grub_free (data->huff_value[i]); + grub_free (data); + } + + if ((grub_errno != GRUB_ERR_NONE) && (*bitmap)) + { + grub_video_bitmap_destroy (*bitmap); + *bitmap = 0; + } + + grub_file_close (file); + return grub_errno; +} + +#if defined(JPEG_DEBUG) +static grub_err_t +grub_cmd_jpegtest (struct grub_arg_list *state __attribute__ ((unused)), + int argc, char **args) +{ + struct grub_video_bitmap *bitmap = 0; + + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); + + grub_video_reader_jpeg (&bitmap, args[0]); + if (grub_errno != GRUB_ERR_NONE) + return grub_errno; + + grub_video_bitmap_destroy (bitmap); + + return GRUB_ERR_NONE; +} +#endif + +static struct grub_video_bitmap_reader jpg_reader = { + .extension = ".jpg", + .reader = grub_video_reader_jpeg, + .next = 0 +}; + +static struct grub_video_bitmap_reader jpeg_reader = { + .extension = ".jpeg", + .reader = grub_video_reader_jpeg, + .next = 0 +}; + +GRUB_MOD_INIT (video_reader_jpeg) +{ + grub_video_bitmap_reader_register (&jpg_reader); + grub_video_bitmap_reader_register (&jpeg_reader); +#if defined(JPEG_DEBUG) + grub_register_command ("jpegtest", grub_cmd_jpegtest, + GRUB_COMMAND_FLAG_BOTH, "jpegtest FILE", + "Tests loading of JPEG bitmap.", 0); +#endif +} + +GRUB_MOD_FINI (video_reader_jpeg) +{ +#if defined(JPEG_DEBUG) + grub_unregister_command ("jpegtest"); +#endif + grub_video_bitmap_reader_unregister (&jpeg_reader); + grub_video_bitmap_reader_unregister (&jpg_reader); +} -- Bean ^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [PATCH] jpeg image reader 2008-01-09 17:56 ` Bean @ 2008-01-09 20:33 ` Vesa Jääskeläinen 2008-01-10 10:12 ` Bean 0 siblings, 1 reply; 23+ messages in thread From: Vesa Jääskeläinen @ 2008-01-09 20:33 UTC (permalink / raw) To: The development of GRUB 2 Bean wrote: > Hi, > > I just fix a small bug that can cause color distortion, here is the new patch. Nice job for implementing JPEG. This is the major reason I made the bitmap loader interface, to allow other people to write loaders... now if we would just have PNG support ;) I will not comment on the JPEG format or any possible IPR issues as I am not too clear on that myself, just the patch itself. I would have hoped a bit more comments. Check your tabs and spaces. Re-check array handling. I know lots of JPEG loaders seems to use longjmp for error handling, personally I don't like it, but I suppose it is ok. In grub2 you could just check if grub_errno != GRUB_ERR_NONE and then just return and at that level do the same check. This mechanism works a bit like c++'s exceptions. Another thing is that if there is a problem loading JPEG, user gets a message like "invalid marker: 1234", this doesn't really tell user a thing. So I would propose to use jpeg prefix like "jpeg: invalid marker...", or more descriptive from user's perspective. > diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk > index a46bc74..4beeeff 100644 > --- a/conf/i386-pc.rmk > +++ b/conf/i386-pc.rmk > @@ -136,7 +136,7 @@ pkglib_MODULES = biosdisk.mod _chain.mod > _linux.mod linux.mod normal.mod \ > _multiboot.mod chain.mod multiboot.mod reboot.mod halt.mod \ > vbe.mod vbetest.mod vbeinfo.mod video.mod gfxterm.mod \ > videotest.mod play.mod bitmap.mod tga.mod cpuid.mod serial.mod \ > - ata.mod vga.mod > + ata.mod vga.mod jpeg.mod > > # For biosdisk.mod. > biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c > @@ -249,6 +249,11 @@ tga_mod_SOURCES = video/readers/tga.c > tga_mod_CFLAGS = $(COMMON_CFLAGS) > tga_mod_LDFLAGS = $(COMMON_LDFLAGS) > > +# For jpeg.mod > +jpeg_mod_SOURCES = video/readers/jpeg.c > +jpeg_mod_CFLAGS = $(COMMON_CFLAGS) > +jpeg_mod_LDFLAGS = $(COMMON_LDFLAGS) > + > # For cpuid.mod. > cpuid_mod_SOURCES = commands/i386/cpuid.c > cpuid_mod_CFLAGS = $(COMMON_CFLAGS) > diff --git a/video/readers/jpeg.c b/video/readers/jpeg.c > new file mode 100755 > index 0000000..bcbf820 > --- /dev/null > +++ b/video/readers/jpeg.c > @@ -0,0 +1,734 @@ > +/* > + * GRUB -- GRand Unified Bootloader > + * Copyright (C) 2008 Free Software Foundation, Inc. > + * > + * GRUB is free software: you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation, either version 3 of the License, or > + * (at your option) any later version. > + * > + * GRUB is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. > + */ > + > +#include <grub/bitmap.h> > +#include <grub/types.h> > +#include <grub/normal.h> > +#include <grub/dl.h> > +#include <grub/mm.h> > +#include <grub/misc.h> > +#include <grub/arg.h> > +#include <grub/file.h> > +#include <grub/setjmp.h> > + > +/* Uncomment following define to enable JPEG debug. */ > +//#define JPEG_DEBUG > + > +struct grub_jpeg_data > +{ > + grub_file_t file; > + grub_jmp_buf jumper; > + > + int image_width; > + int image_height; > + > + grub_uint8_t *huff_value[4]; > + int huff_offset[4][16]; > + int huff_maxval[4][16]; > + > + grub_uint8_t quan_table[2][64]; > + int comp_index[3][3]; > + > + int ydu[4][64], cbdu[64], crdu[64]; > + > + int Cr_r_tab[256], Cb_b_tab[256], Cr_g_tab[256], Cb_g_tab[256]; > + > + int dc_value[3]; > + > + int bit_mask, bit_save; > + > + struct grub_video_bitmap **bitmap; > +}; > + > +static grub_uint8_t > +get_byte (struct grub_jpeg_data *data) > +{ > + grub_uint8_t r; > + > + if (grub_file_read (data->file, (char *) &r, 1) != 1) > + grub_longjmp (data->jumper, 1); > + > + return r; > +} > + > +static unsigned unsigned -> grub_uint16_t > +get_word (struct grub_jpeg_data *data) > +{ > + unsigned aa, bb; > + > + aa = get_byte (data); > + bb = get_byte (data); > + return (aa << 8) + bb; > +} > + > +static int > +get_bit (struct grub_jpeg_data *data) > +{ > + int ret; > + > + if (data->bit_mask == 0) > + { > + data->bit_save = get_byte (data); > + if (data->bit_save == 0xFF) > + { > + if (get_byte (data) != 0) > + { > + grub_error (GRUB_ERR_BAD_FILE_TYPE, > + "invalid 0xFF in data stream"); > + grub_longjmp (data->jumper, 1); > + } > + } > + data->bit_mask = 0x80; > + } > + > + ret = (data->bit_save & data->bit_mask); > + data->bit_mask >>= 1; > + return ret; > +} > + > +static int > +get_huff_leng (struct grub_jpeg_data *data, int num) _length? > +{ > + int value, i, bit; > + > + if (num == 0) > + return 0; > + > + bit = get_bit (data); > + value = (bit != 0); > + for (i = 1; i < num; i++) > + value = value * 2 + (get_bit (data) != 0); > + if (!bit) > + value += 1 - (1 << num); > + > + return value; > +} > + > +static int > +get_huff_base (struct grub_jpeg_data *data, int id) > +{ > + int code, i; > + > + code = 0; > + for (i = 0; i < 16; i++) > + { > + code <<= 1; > + if (get_bit (data)) > + code++; > + if (code < data->huff_maxval[id][i]) > + return data->huff_value[id][code + data->huff_offset[id][i]]; > + } > + grub_error (GRUB_ERR_BAD_FILE_TYPE, "huffman decode fails"); > + grub_longjmp (data->jumper, 1); > + return 0; > +} > + > +static void > +decode_huff_table (struct grub_jpeg_data *data) > +{ > + unsigned id; unsigned -> grub_uint8_t > + int ac, i, n, base, ofs; > + grub_uint8_t count[16]; > + > + get_word (data); not important word? > + id = get_byte (data); > + ac = (id >> 4); > + id &= 0xF; > + if (id > 1) > + { > + grub_error (GRUB_ERR_BAD_FILE_TYPE, "too many huff table"); > + grub_longjmp (data->jumper, 1); > + } > + > + if (grub_file_read (data->file, (char *) &count, sizeof (count)) != > + sizeof (count)) > + grub_longjmp (data->jumper, 1); > + > + n = 0; > + for (i = 0; i < 16; i++) > + n += count[i]; > + > + id += ac * 2; > + if ((data->huff_value[id] = grub_malloc (n)) == NULL) try to keep malloc on own line and then check for pointer or for grub_errno (or both). > + grub_longjmp (data->jumper, 1); > + > + if (grub_file_read (data->file, (char *) data->huff_value[id], n) != n) > + grub_longjmp (data->jumper, 1); > + > + base = 0; > + ofs = 0; > + for (i = 0; i < 16; i++) > + { > + base += count[i]; > + ofs += count[i]; > + > + data->huff_maxval[id][i] = base; > + data->huff_offset[id][i] = ofs - base; > + > + base <<= 1; > + } > +} > + > +static void > +decode_quan_table (struct grub_jpeg_data *data) > +{ > + unsigned id; > + > + get_word (data); > + id = get_byte (data); > + if (id >= 0x10) 0x10? > + { > + grub_error (GRUB_ERR_BAD_FILE_TYPE, > + "only 8-bit precision is supported"); > + grub_longjmp (data->jumper, 1); > + } > + > + if (id > 1) > + { > + grub_error (GRUB_ERR_BAD_FILE_TYPE, "too many quantization table"); > + grub_longjmp (data->jumper, 1); > + } > + > + if (grub_file_read (data->file, (char *) &data->quan_table[id], 64) != 64) > + grub_longjmp (data->jumper, 1); > +} > + > +static void > +decode_sof (struct grub_jpeg_data *data) > +{ > + int nc, i; > + > + get_word (data); > + if (get_byte (data) != 8) > + { > + grub_error (GRUB_ERR_BAD_FILE_TYPE, > + "only 8-bit precision is supported"); > + grub_longjmp (data->jumper, 1); > + } > + > + data->image_height = get_word (data); > + data->image_width = get_word (data); > + > + if ((!data->image_height) || (!data->image_width)) > + { > + grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid image size"); > + grub_longjmp (data->jumper, 1); > + } > + > + nc = get_byte (data); > + if (nc != 3) > + { > + grub_error (GRUB_ERR_BAD_FILE_TYPE, "component count must be 3"); > + grub_longjmp (data->jumper, 1); > + } > + > + for (i = 0; i < nc; i++) > + { > + int id, ss; > + > + id = get_byte (data) - 1; > + ss = get_byte (data); > + if (((!id) && (ss != 0x22)) || ((id) && (ss != 0x11))) > + { > + grub_error (GRUB_ERR_BAD_FILE_TYPE, "only support 2:1:1 sampling"); > + grub_longjmp (data->jumper, 1); > + } > + data->comp_index[id][0] = get_byte (data); Buffer overflow possibility. > + } > +} > + > +#define DCTSIZE 8 > + > +#define CONST_BITS 8 > +#define PASS1_BITS 2 > + > +#define FIX_1_082392200 ((int) 277) /* FIX(1.082392200) */ > +#define FIX_1_414213562 ((int) 362) /* FIX(1.414213562) */ > +#define FIX_1_847759065 ((int) 473) /* FIX(1.847759065) */ > +#define FIX_2_613125930 ((int) 669) /* FIX(2.613125930) */ > + > +#define ONE ((long) 1) > +#define DESCALE(x,n) (((x) + (ONE << ((n)-1))) >> (n)) > + > +#define MULTIPLY(var,const) DESCALE((var) * (const), CONST_BITS) > + > +static const unsigned char natural_order[64] = { grub_uint8_t, or just (unsigned) int > + 0, 1, 8, 16, 9, 2, 3, 10, > + 17, 24, 32, 25, 18, 11, 4, 5, > + 12, 19, 26, 33, 40, 48, 41, 34, > + 27, 20, 13, 6, 7, 14, 21, 28, > + 35, 42, 49, 56, 57, 50, 43, 36, > + 29, 22, 15, 23, 30, 37, 44, 51, > + 58, 59, 52, 45, 38, 31, 39, 46, > + 53, 60, 61, 54, 47, 55, 62, 63 > +}; > + > +static const short aanscales[64] = { use just int (as it is anyway casted to int, and I don't think it is necessary to save some bytes on here from module. > + /* precomputed values scaled up by 14 bits */ > + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, > + 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, > + 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, > + 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, > + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, > + 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, > + 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, > + 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 > +}; > + > +static void > +idct_transform (int *du) > +{ > + int *pd; > + int ctr; > + int tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; > + int tmp10, tmp11, tmp12, tmp13; > + int z5, z10, z11, z12, z13; > + > + /* Pass 1: process columns from input, store into work array. */ Extra space after last dot. > + > + pd = du; > + for (ctr = DCTSIZE; ctr > 0; ctr--) > + { > + if ((pd[DCTSIZE * 1] | pd[DCTSIZE * 2] | pd[DCTSIZE * 3] | > + pd[DCTSIZE * 4] | pd[DCTSIZE * 5] | pd[DCTSIZE * 6] | > + pd[DCTSIZE * 7]) == 0) > + { > + pd[DCTSIZE * 1] = pd[DCTSIZE * 2] > + = pd[DCTSIZE * 3] = pd[DCTSIZE * 4] > + = pd[DCTSIZE * 5] = pd[DCTSIZE * 6] > + = pd[DCTSIZE * 7] = pd[DCTSIZE * 0]; > + > + pd++; /* advance pointers to next column */ > + continue; > + } > + > + /* Even part */ > + > + tmp0 = pd[DCTSIZE * 0]; > + tmp1 = pd[DCTSIZE * 2]; > + tmp2 = pd[DCTSIZE * 4]; > + tmp3 = pd[DCTSIZE * 6]; > + > + tmp10 = tmp0 + tmp2; /* phase 3 */ > + tmp11 = tmp0 - tmp2; > + > + tmp13 = tmp1 + tmp3; /* phases 5-3 */ > + tmp12 = MULTIPLY (tmp1 - tmp3, FIX_1_414213562) - tmp13; /* 2*c4 */ > + > + tmp0 = tmp10 + tmp13; /* phase 2 */ > + tmp3 = tmp10 - tmp13; > + tmp1 = tmp11 + tmp12; > + tmp2 = tmp11 - tmp12; > + > + /* Odd part */ > + > + tmp4 = pd[DCTSIZE * 1]; > + tmp5 = pd[DCTSIZE * 3]; > + tmp6 = pd[DCTSIZE * 5]; > + tmp7 = pd[DCTSIZE * 7]; > + > + z13 = tmp6 + tmp5; /* phase 6 */ > + z10 = tmp6 - tmp5; > + z11 = tmp4 + tmp7; > + z12 = tmp4 - tmp7; > + > + tmp7 = z11 + z13; /* phase 5 */ > + tmp11 = MULTIPLY (z11 - z13, FIX_1_414213562); /* 2*c4 */ > + > + z5 = MULTIPLY (z10 + z12, FIX_1_847759065); /* 2*c2 */ > + tmp10 = MULTIPLY (z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */ > + tmp12 = MULTIPLY (z10, -FIX_2_613125930) + z5; /* -2*(c2+c6) */ > + > + > + tmp6 = tmp12 - tmp7; /* phase 2 */ > + tmp5 = tmp11 - tmp6; > + tmp4 = tmp10 + tmp5; > + > + pd[DCTSIZE * 0] = (int) (tmp0 + tmp7); > + pd[DCTSIZE * 7] = (int) (tmp0 - tmp7); > + pd[DCTSIZE * 1] = (int) (tmp1 + tmp6); > + pd[DCTSIZE * 6] = (int) (tmp1 - tmp6); > + pd[DCTSIZE * 2] = (int) (tmp2 + tmp5); > + pd[DCTSIZE * 5] = (int) (tmp2 - tmp5); > + pd[DCTSIZE * 4] = (int) (tmp3 + tmp4); > + pd[DCTSIZE * 3] = (int) (tmp3 - tmp4); > + > + pd++; /* advance pointers to next column */ > + } > + > + /* Pass 2: process rows from work array, store into output array. */ > + /* Note that we must descale the results by a factor of 8 == 2**3, */ > + /* and also undo the PASS1_BITS scaling. */ > + > + pd = du; > + for (ctr = 0; ctr < DCTSIZE; ctr++) > + { > + /* Even part */ > + > + tmp10 = pd[0] + pd[4]; > + tmp11 = pd[0] - pd[4]; > + > + tmp13 = pd[2] + pd[6]; > + tmp12 = MULTIPLY (pd[2] - pd[6], FIX_1_414213562) - tmp13; > + > + tmp0 = tmp10 + tmp13; > + tmp3 = tmp10 - tmp13; > + tmp1 = tmp11 + tmp12; > + tmp2 = tmp11 - tmp12; > + > + /* Odd part */ > + > + z13 = pd[5] + pd[3]; > + z10 = pd[5] - pd[3]; > + z11 = pd[1] + pd[7]; > + z12 = pd[1] - pd[7]; > + > + tmp7 = z11 + z13; /* phase 5 */ > + tmp11 = MULTIPLY (z11 - z13, FIX_1_414213562); /* 2*c4 */ > + > + z5 = MULTIPLY (z10 + z12, FIX_1_847759065); /* 2*c2 */ > + tmp10 = MULTIPLY (z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */ > + tmp12 = MULTIPLY (z10, -FIX_2_613125930) + z5; /* -2*(c2+c6) */ > + > + tmp6 = tmp12 - tmp7; /* phase 2 */ > + tmp5 = tmp11 - tmp6; > + tmp4 = tmp10 + tmp5; > + > + /* Final output stage: scale down by a factor of 8 and range-limit */ > + > + pd[0] = DESCALE (tmp0 + tmp7, PASS1_BITS + 3) + 128; > + pd[7] = DESCALE (tmp0 - tmp7, PASS1_BITS + 3) + 128; > + pd[1] = DESCALE (tmp1 + tmp6, PASS1_BITS + 3) + 128; > + pd[6] = DESCALE (tmp1 - tmp6, PASS1_BITS + 3) + 128; > + pd[2] = DESCALE (tmp2 + tmp5, PASS1_BITS + 3) + 128; > + pd[5] = DESCALE (tmp2 - tmp5, PASS1_BITS + 3) + 128; > + pd[4] = DESCALE (tmp3 + tmp4, PASS1_BITS + 3) + 128; > + pd[3] = DESCALE (tmp3 - tmp4, PASS1_BITS + 3) + 128; > + > + pd += DCTSIZE; /* advance pointer to next row */ > + } > + > + for (ctr = 0; ctr < 64; ctr++) > + { > + if (du[ctr] < 0) > + du[ctr] = 0; > + if (du[ctr] > 255) > + du[ctr] = 255; > + } > +} > + > +static void > +decode_du (struct grub_jpeg_data *data, int id, int *du) > +{ > + int pos, h1, h2, qt; > + > + grub_memset (du, 0, sizeof (int) * 64); du is always that size ? perhaps add warning about it to prototype, or provide length? I didn't check for indexes below, verify them. > + > + qt = data->comp_index[id][0]; > + h1 = data->comp_index[id][1]; > + h2 = data->comp_index[id][2]; > + > + data->dc_value[id] += get_huff_leng (data, get_huff_base (data, h1)); > + > + du[0] = > + data->dc_value[id] * DESCALE ((int) data->quan_table[qt][0] * > + (int) aanscales[0], 14 - 2); > + pos = 1; > + while (pos < 64) > + { > + int num, val; > + > + num = get_huff_base (data, h2); > + if (!num) > + break; > + val = get_huff_leng (data, num & 0xF); > + num >>= 4; > + pos += num; > + du[natural_order[pos]] = > + val * DESCALE ((int) data->quan_table[qt][pos] * > + (int) aanscales[natural_order[pos]], 14 - 2); > + pos++; > + } > + > + idct_transform (du); > +} > + > +#define SCALEBITS 16 /* speediest right-shift on some machines */ > +#define ONE_HALF ((int) 1 << (SCALEBITS-1)) > +#define FIX(x) ((int) ((x) * (1L<<SCALEBITS) + 0.5)) > + > +static void > +build_color_table (struct grub_jpeg_data *data) > +{ > + int i, x; > + > + for (i = 0, x = -128; i <= 255; i++, x++) > + { > + data->Cr_r_tab[i] = (int) (FIX (1.40200) * x + ONE_HALF) >> SCALEBITS; > + data->Cb_b_tab[i] = (int) (FIX (1.77200) * x + ONE_HALF) >> SCALEBITS; > + data->Cr_g_tab[i] = (-FIX (0.71414)) * x; > + data->Cb_g_tab[i] = (-FIX (0.34414)) * x + ONE_HALF; > + } > +} > + > +static void > +decode_sos (struct grub_jpeg_data *data) > +{ > + int nc, i, r1, c1; > + grub_uint8_t *ptr; > + > + get_word (data); No use for first word? > + nc = get_byte (data); > + > + if (nc != 3) > + { > + grub_error (GRUB_ERR_BAD_FILE_TYPE, "component count must be 3"); > + grub_longjmp (data->jumper, 1); > + } > + > + for (i = 0; i < nc; i++) > + { > + int id, ht; > + > + id = get_byte (data) - 1; > + ht = get_byte (data); > + data->comp_index[id][1] = (ht >> 4); > + data->comp_index[id][2] = (ht & 0xF) + 2; Buffer overflows. > + } > + > + get_byte (data); > + get_word (data); > + > + if (grub_video_bitmap_create (data->bitmap, data->image_width, > + data->image_height, > + GRUB_VIDEO_BLIT_FORMAT_R8G8B8)) > + grub_longjmp (data->jumper, 1); > + > + ptr = (*data->bitmap)->data; > + data->bit_mask = 0x0; > + > + for (r1 = 0; r1 < (data->image_height >> 4); r1++) > + for (c1 = 0; c1 < (data->image_width >> 4); c1++) > + { > + int r2, c2, r3, c3; > + > + decode_du (data, 0, &data->ydu[0][0]); > + decode_du (data, 0, &data->ydu[1][0]); > + > + decode_du (data, 0, &data->ydu[2][0]); > + decode_du (data, 0, &data->ydu[3][0]); > + > + decode_du (data, 1, &data->cbdu[0]); > + decode_du (data, 2, &data->crdu[0]); > + > + for (r2 = 0; r2 < 2; r2++) > + for (c2 = 0; c2 < 2; c2++) > + for (r3 = 0; r3 < 8; r3++) > + for (c3 = 0; c3 < 8; c3++) > + { > + int i0, i1, i2, cr, cb, dd; > + > + i0 = > + ((r1 * 16 + r2 * 8 + r3) * (data->image_width) + c1 * 16 + > + c2 * 8 + c3) * 3; > + i1 = r3 * 8 + c3; > + i2 = (r2 * 32 + c2 * 4) + (r3 >> 1) * 8 + (c3 >> 1); I have following indexes are correct.... (didn't check them) > + > + cr = data->crdu[i2]; > + cb = data->cbdu[i2]; > + > + // Red Try to use C comments. /* ... > + dd = data->ydu[r2 * 2 + c2][i1] + data->Cr_r_tab[cr]; > + if (dd < 0) > + dd = 0; > + ptr[i0] = dd; > + > + // Green > + dd = > + data->ydu[r2 * 2 + c2][i1] + > + ((data->Cb_g_tab[cb] + data->Cr_g_tab[cr]) >> SCALEBITS); > + if (dd < 0) > + dd = 0; > + ptr[i0 + 1] = dd; > + > + // Blue > + dd = data->ydu[r2 * 2 + c2][i1] + data->Cb_b_tab[cb]; > + if (dd < 0) > + dd = 0; > + ptr[i0 + 2] = dd; > + } > + } > +} > + > + > +static grub_uint8_t > +get_marker (struct grub_jpeg_data *data) > +{ > + grub_uint8_t r; > + > + r = get_byte (data); > + > + if (r != 0xFF) 0xFF? > + { > + grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid maker"); > + grub_longjmp (data->jumper, 1); > + } > + > + return get_byte (data); > +} > + > +static void > +decode_jpeg (struct grub_jpeg_data *data) > +{ > + build_color_table (data); > + > + if (get_marker (data) != 0xD8) 0xD8? > + { > + grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid jpeg file"); > + grub_longjmp (data->jumper, 1); > + } > + > + while (1) > + { > + grub_uint8_t marker; > + > + marker = get_marker (data); > +#ifdef JPEG_DEBUG > + grub_printf ("marker: %x\n", marker); > +#endif > + switch (marker) > + { > + case 0xc4: 0xC4 ? > + decode_huff_table (data); > + break; > + case 0xdb: Same... > + decode_quan_table (data); > + break; > + case 0xc0: > + decode_sof (data); > + break; > + case 0xda: > + decode_sos (data); > + break; > + case 0xd9: > + return; > + case 0xe0: > + case 0xfe: > + { > + unsigned sz; unsigned -> grub_uint16_t > + > + sz = get_word (data); > + grub_file_seek (data->file, data->file->offset + sz - 2); > + break; > + } > + default: > + grub_error (GRUB_ERR_BAD_FILE_TYPE, "unrecognized marker %x", > + marker); > + grub_longjmp (data->jumper, 1); > + } > + } > +} > + > +static grub_err_t > +grub_video_reader_jpeg (struct grub_video_bitmap **bitmap, > + const char *filename) > +{ > + grub_file_t file; > + struct grub_jpeg_data *data; > + > + file = grub_file_open (filename); > + if (!file) > + return grub_errno; > + > + if ((data = grub_malloc (sizeof (*data))) != NULL) Separate as two lines. > + { > + int i; > + > + grub_memset (data, 0, sizeof (*data)); > + data->file = file; > + data->bitmap = bitmap; > + if (!grub_setjmp (data->jumper)) > + decode_jpeg (data); > + > + for (i = 0; i < 4; i++) > + if (data->huff_value[i]) > + grub_free (data->huff_value[i]); > + grub_free (data); > + } > + > + if ((grub_errno != GRUB_ERR_NONE) && (*bitmap)) No need to check for *bitmap > + { > + grub_video_bitmap_destroy (*bitmap); > + *bitmap = 0; > + } > + > + grub_file_close (file); > + return grub_errno; > +} > + > +#if defined(JPEG_DEBUG) > +static grub_err_t > +grub_cmd_jpegtest (struct grub_arg_list *state __attribute__ ((unused)), > + int argc, char **args) > +{ > + struct grub_video_bitmap *bitmap = 0; > + > + if (argc != 1) > + return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); > + > + grub_video_reader_jpeg (&bitmap, args[0]); > + if (grub_errno != GRUB_ERR_NONE) > + return grub_errno; > + > + grub_video_bitmap_destroy (bitmap); > + > + return GRUB_ERR_NONE; > +} > +#endif > + > +static struct grub_video_bitmap_reader jpg_reader = { > + .extension = ".jpg", > + .reader = grub_video_reader_jpeg, > + .next = 0 > +}; > + > +static struct grub_video_bitmap_reader jpeg_reader = { > + .extension = ".jpeg", > + .reader = grub_video_reader_jpeg, > + .next = 0 > +}; > + > +GRUB_MOD_INIT (video_reader_jpeg) > +{ > + grub_video_bitmap_reader_register (&jpg_reader); > + grub_video_bitmap_reader_register (&jpeg_reader); > +#if defined(JPEG_DEBUG) > + grub_register_command ("jpegtest", grub_cmd_jpegtest, > + GRUB_COMMAND_FLAG_BOTH, "jpegtest FILE", > + "Tests loading of JPEG bitmap.", 0); > +#endif > +} > + > +GRUB_MOD_FINI (video_reader_jpeg) > +{ > +#if defined(JPEG_DEBUG) > + grub_unregister_command ("jpegtest"); > +#endif > + grub_video_bitmap_reader_unregister (&jpeg_reader); > + grub_video_bitmap_reader_unregister (&jpg_reader); > +} > > ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] jpeg image reader 2008-01-09 20:33 ` Vesa Jääskeläinen @ 2008-01-10 10:12 ` Bean 2008-01-12 8:51 ` Bean 0 siblings, 1 reply; 23+ messages in thread From: Bean @ 2008-01-10 10:12 UTC (permalink / raw) To: The development of GRUB 2 On Jan 10, 2008 4:33 AM, Vesa Jääskeläinen <chaac@nic.fi> wrote: > Nice job for implementing JPEG. This is the major reason I made the > bitmap loader interface, to allow other people to write loaders... now > if we would just have PNG support ;) This is my next project. > I know lots of JPEG loaders seems to use longjmp for error handling, > personally I don't like it, but I suppose it is ok. In grub2 you could > just check if grub_errno != GRUB_ERR_NONE and then just return and at > that level do the same check. This mechanism works a bit like c++'s > exceptions. error can occur deep within function call. i can check for return value, but longjmp seems easier. > > + get_word (data); > > not important word? The first word of a segment is the length, but we don't need it. > try to keep malloc on own line and then check for pointer or for > grub_errno (or both). ok. > +static int > +get_huff_leng (struct grub_jpeg_data *data, int num) _length? change to get_huff_code. > > + get_word (data); > > + id = get_byte (data); > > + if (id >= 0x10) > > 0x10? the upper 4-bit is precision, 0 is 8-bit, 1 is 16-bit, etc. > > +static void > > +decode_du (struct grub_jpeg_data *data, int id, int *du) > > +{ > > + int pos, h1, h2, qt; > > + > > + grub_memset (du, 0, sizeof (int) * 64); > > du is always that size ? perhaps add warning about it to prototype, or > provide length? now i use type jpeg_data_unit. > > + if (get_marker (data) != 0xD8) > > 0xD8? use symbols now. diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index a46bc74..4beeeff 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -136,7 +136,7 @@ pkglib_MODULES = biosdisk.mod _chain.mod _linux.mod linux.mod normal.mod \ _multiboot.mod chain.mod multiboot.mod reboot.mod halt.mod \ vbe.mod vbetest.mod vbeinfo.mod video.mod gfxterm.mod \ videotest.mod play.mod bitmap.mod tga.mod cpuid.mod serial.mod \ - ata.mod vga.mod + ata.mod vga.mod jpeg.mod # For biosdisk.mod. biosdisk_mod_SOURCES = disk/i386/pc/biosdisk.c @@ -249,6 +249,11 @@ tga_mod_SOURCES = video/readers/tga.c tga_mod_CFLAGS = $(COMMON_CFLAGS) tga_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For jpeg.mod +jpeg_mod_SOURCES = video/readers/jpeg.c +jpeg_mod_CFLAGS = $(COMMON_CFLAGS) +jpeg_mod_LDFLAGS = $(COMMON_LDFLAGS) + # For cpuid.mod. cpuid_mod_SOURCES = commands/i386/cpuid.c cpuid_mod_CFLAGS = $(COMMON_CFLAGS) diff --git a/video/readers/jpeg.c b/video/readers/jpeg.c new file mode 100755 index 0000000..bb1eda5 --- /dev/null +++ b/video/readers/jpeg.c @@ -0,0 +1,839 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <grub/bitmap.h> +#include <grub/types.h> +#include <grub/normal.h> +#include <grub/dl.h> +#include <grub/mm.h> +#include <grub/misc.h> +#include <grub/arg.h> +#include <grub/file.h> +#include <grub/setjmp.h> + +/* Uncomment following define to enable JPEG debug. */ +//#define JPEG_DEBUG + +typedef enum +{ /* JPEG marker codes */ + M_SOF0 = 0xc0, + M_SOF1 = 0xc1, + M_SOF2 = 0xc2, + M_SOF3 = 0xc3, + + M_SOF5 = 0xc5, + M_SOF6 = 0xc6, + M_SOF7 = 0xc7, + + M_JPG = 0xc8, + M_SOF9 = 0xc9, + M_SOF10 = 0xca, + M_SOF11 = 0xcb, + + M_SOF13 = 0xcd, + M_SOF14 = 0xce, + M_SOF15 = 0xcf, + + M_DHT = 0xc4, + + M_DAC = 0xcc, + + M_RST0 = 0xd0, + M_RST1 = 0xd1, + M_RST2 = 0xd2, + M_RST3 = 0xd3, + M_RST4 = 0xd4, + M_RST5 = 0xd5, + M_RST6 = 0xd6, + M_RST7 = 0xd7, + + M_SOI = 0xd8, + M_EOI = 0xd9, + M_SOS = 0xda, + M_DQT = 0xdb, + M_DNL = 0xdc, + M_DRI = 0xdd, + M_DHP = 0xde, + M_EXP = 0xdf, + + M_APP0 = 0xe0, + M_APP1 = 0xe1, + M_APP2 = 0xe2, + M_APP3 = 0xe3, + M_APP4 = 0xe4, + M_APP5 = 0xe5, + M_APP6 = 0xe6, + M_APP7 = 0xe7, + M_APP8 = 0xe8, + M_APP9 = 0xe9, + M_APP10 = 0xea, + M_APP11 = 0xeb, + M_APP12 = 0xec, + M_APP13 = 0xed, + M_APP14 = 0xee, + M_APP15 = 0xef, + + M_JPG0 = 0xf0, + M_JPG13 = 0xfd, + M_COM = 0xfe, + + M_TEM = 0x01, + + M_ERROR = 0x100 +} JPEG_MARKER; + +typedef int jpeg_data_unit[64]; + +struct grub_jpeg_data +{ + grub_file_t file; + grub_jmp_buf jumper; + + int image_width; + int image_height; + + grub_uint8_t *huff_value[4]; + int huff_offset[4][16]; + int huff_maxval[4][16]; + + grub_uint8_t quan_table[2][64]; + int comp_index[3][3]; + + jpeg_data_unit ydu[4]; + jpeg_data_unit crdu; + jpeg_data_unit cbdu; + + int Cr_r_tab[256], Cb_b_tab[256], Cr_g_tab[256], Cb_g_tab[256]; + + int dc_value[3]; + + int bit_mask, bit_save; + + struct grub_video_bitmap **bitmap; +}; + + +static grub_uint8_t +get_byte (struct grub_jpeg_data *data) +{ + grub_uint8_t r; + + if (grub_file_read (data->file, (char *) &r, 1) != 1) + grub_longjmp (data->jumper, 1); + + return r; +} + +static grub_uint16_t +get_word (struct grub_jpeg_data *data) +{ + grub_uint16_t aa, bb; + + aa = get_byte (data); + bb = get_byte (data); + return (aa << 8) + bb; +} + +static int +get_bit (struct grub_jpeg_data *data) +{ + int ret; + + if (data->bit_mask == 0) + { + data->bit_save = get_byte (data); + if (data->bit_save == 0xFF) + { + if (get_byte (data) != 0) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: invalid 0xFF in data stream"); + grub_longjmp (data->jumper, 1); + } + } + data->bit_mask = 0x80; + } + + ret = (data->bit_save & data->bit_mask); + data->bit_mask >>= 1; + return ret; +} + +static int +get_huff_code (struct grub_jpeg_data *data, int num) +{ + int value, i, bit; + + if (num == 0) + return 0; + + bit = get_bit (data); + value = (bit != 0); + for (i = 1; i < num; i++) + value = value * 2 + (get_bit (data) != 0); + if (!bit) + value += 1 - (1 << num); + + return value; +} + +static int +get_huff_base (struct grub_jpeg_data *data, int id) +{ + int code, i; + + code = 0; + for (i = 0; i < 16; i++) + { + code <<= 1; + if (get_bit (data)) + code++; + if (code < data->huff_maxval[id][i]) + return data->huff_value[id][code + data->huff_offset[id][i]]; + } + grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: huffman decode fails"); + grub_longjmp (data->jumper, 1); + return 0; +} + +static void +decode_huff_table (struct grub_jpeg_data *data) +{ + int id, ac, i, n, base, ofs; + grub_uint8_t count[16]; + + get_word (data); + id = get_byte (data); + ac = (id >> 4); + id &= 0xF; + if (id > 1) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: too many huffman table"); + grub_longjmp (data->jumper, 1); + } + + if (grub_file_read (data->file, (char *) &count, sizeof (count)) != + sizeof (count)) + grub_longjmp (data->jumper, 1); + + n = 0; + for (i = 0; i < 16; i++) + n += count[i]; + + id += ac * 2; + data->huff_value[id] = grub_malloc (n); + if (data->huff_value[id] == NULL) + grub_longjmp (data->jumper, 1); + + if (grub_file_read (data->file, (char *) data->huff_value[id], n) != n) + grub_longjmp (data->jumper, 1); + + base = 0; + ofs = 0; + for (i = 0; i < 16; i++) + { + base += count[i]; + ofs += count[i]; + + data->huff_maxval[id][i] = base; + data->huff_offset[id][i] = ofs - base; + + base <<= 1; + } +} + +static void +decode_quan_table (struct grub_jpeg_data *data) +{ + int id; + + get_word (data); + id = get_byte (data); + if (id >= 0x10) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: only 8-bit precision is supported"); + grub_longjmp (data->jumper, 1); + } + + if (id > 1) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: too many quantization table"); + grub_longjmp (data->jumper, 1); + } + + if (grub_file_read (data->file, (char *) &data->quan_table[id], 64) != 64) + grub_longjmp (data->jumper, 1); +} + +static void +decode_sof (struct grub_jpeg_data *data) +{ + int nc, i; + + get_word (data); + if (get_byte (data) != 8) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: only 8-bit precision is supported"); + grub_longjmp (data->jumper, 1); + } + + data->image_height = get_word (data); + data->image_width = get_word (data); + + if ((!data->image_height) || (!data->image_width)) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid image size"); + grub_longjmp (data->jumper, 1); + } + + nc = get_byte (data); + if (nc != 3) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: component count must be 3"); + grub_longjmp (data->jumper, 1); + } + + for (i = 0; i < nc; i++) + { + int id, ss; + + id = get_byte (data) - 1; + if ((id < 0) || (id >= 3)) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index"); + grub_longjmp (data->jumper, 1); + } + ss = get_byte (data); + if (((!id) && (ss != 0x22)) || ((id) && (ss != 0x11))) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: only support 2:1:1 sampling"); + grub_longjmp (data->jumper, 1); + } + data->comp_index[id][0] = get_byte (data); + } +} + +#define DCTSIZE 8 + +#define CONST_BITS 8 +#define PASS1_BITS 2 + +#define FIX_1_082392200 ((int) 277) /* FIX(1.082392200) */ +#define FIX_1_414213562 ((int) 362) /* FIX(1.414213562) */ +#define FIX_1_847759065 ((int) 473) /* FIX(1.847759065) */ +#define FIX_2_613125930 ((int) 669) /* FIX(2.613125930) */ + +#define ONE ((long) 1) +#define DESCALE(x,n) (((x) + (ONE << ((n)-1))) >> (n)) + +#define MULTIPLY(var,const) DESCALE((var) * (const), CONST_BITS) + +static const grub_uint8_t natural_order[64] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 +}; + +static const int aanscales[64] = { + /* precomputed values scaled up by 14 bits */ + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, + 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, + 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, + 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, + 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 +}; + +static void +idct_transform (jpeg_data_unit du) +{ + int *pd; + int ctr; + int tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + int tmp10, tmp11, tmp12, tmp13; + int z5, z10, z11, z12, z13; + + /* Pass 1: process columns from input, store into work array. */ + + pd = du; + for (ctr = DCTSIZE; ctr > 0; ctr--) + { + if ((pd[DCTSIZE * 1] | pd[DCTSIZE * 2] | pd[DCTSIZE * 3] | + pd[DCTSIZE * 4] | pd[DCTSIZE * 5] | pd[DCTSIZE * 6] | + pd[DCTSIZE * 7]) == 0) + { + pd[DCTSIZE * 1] = pd[DCTSIZE * 2] + = pd[DCTSIZE * 3] = pd[DCTSIZE * 4] + = pd[DCTSIZE * 5] = pd[DCTSIZE * 6] + = pd[DCTSIZE * 7] = pd[DCTSIZE * 0]; + + pd++; /* advance pointers to next column */ + continue; + } + + /* Even part */ + + tmp0 = pd[DCTSIZE * 0]; + tmp1 = pd[DCTSIZE * 2]; + tmp2 = pd[DCTSIZE * 4]; + tmp3 = pd[DCTSIZE * 6]; + + tmp10 = tmp0 + tmp2; /* phase 3 */ + tmp11 = tmp0 - tmp2; + + tmp13 = tmp1 + tmp3; /* phases 5-3 */ + tmp12 = MULTIPLY (tmp1 - tmp3, FIX_1_414213562) - tmp13; /* 2*c4 */ + + tmp0 = tmp10 + tmp13; /* phase 2 */ + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + tmp4 = pd[DCTSIZE * 1]; + tmp5 = pd[DCTSIZE * 3]; + tmp6 = pd[DCTSIZE * 5]; + tmp7 = pd[DCTSIZE * 7]; + + z13 = tmp6 + tmp5; /* phase 6 */ + z10 = tmp6 - tmp5; + z11 = tmp4 + tmp7; + z12 = tmp4 - tmp7; + + tmp7 = z11 + z13; /* phase 5 */ + tmp11 = MULTIPLY (z11 - z13, FIX_1_414213562); /* 2*c4 */ + + z5 = MULTIPLY (z10 + z12, FIX_1_847759065); /* 2*c2 */ + tmp10 = MULTIPLY (z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */ + tmp12 = MULTIPLY (z10, -FIX_2_613125930) + z5; /* -2*(c2+c6) */ + + + tmp6 = tmp12 - tmp7; /* phase 2 */ + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + + pd[DCTSIZE * 0] = (int) (tmp0 + tmp7); + pd[DCTSIZE * 7] = (int) (tmp0 - tmp7); + pd[DCTSIZE * 1] = (int) (tmp1 + tmp6); + pd[DCTSIZE * 6] = (int) (tmp1 - tmp6); + pd[DCTSIZE * 2] = (int) (tmp2 + tmp5); + pd[DCTSIZE * 5] = (int) (tmp2 - tmp5); + pd[DCTSIZE * 4] = (int) (tmp3 + tmp4); + pd[DCTSIZE * 3] = (int) (tmp3 - tmp4); + + pd++; /* advance pointers to next column */ + } + + /* Pass 2: process rows from work array, store into output array. */ + /* Note that we must descale the results by a factor of 8 == 2**3, */ + /* and also undo the PASS1_BITS scaling. */ + + pd = du; + for (ctr = 0; ctr < DCTSIZE; ctr++) + { + /* Even part */ + + tmp10 = pd[0] + pd[4]; + tmp11 = pd[0] - pd[4]; + + tmp13 = pd[2] + pd[6]; + tmp12 = MULTIPLY (pd[2] - pd[6], FIX_1_414213562) - tmp13; + + tmp0 = tmp10 + tmp13; + tmp3 = tmp10 - tmp13; + tmp1 = tmp11 + tmp12; + tmp2 = tmp11 - tmp12; + + /* Odd part */ + + z13 = pd[5] + pd[3]; + z10 = pd[5] - pd[3]; + z11 = pd[1] + pd[7]; + z12 = pd[1] - pd[7]; + + tmp7 = z11 + z13; /* phase 5 */ + tmp11 = MULTIPLY (z11 - z13, FIX_1_414213562); /* 2*c4 */ + + z5 = MULTIPLY (z10 + z12, FIX_1_847759065); /* 2*c2 */ + tmp10 = MULTIPLY (z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */ + tmp12 = MULTIPLY (z10, -FIX_2_613125930) + z5; /* -2*(c2+c6) */ + + tmp6 = tmp12 - tmp7; /* phase 2 */ + tmp5 = tmp11 - tmp6; + tmp4 = tmp10 + tmp5; + + /* Final output stage: scale down by a factor of 8 and range-limit */ + + pd[0] = DESCALE (tmp0 + tmp7, PASS1_BITS + 3) + 128; + pd[7] = DESCALE (tmp0 - tmp7, PASS1_BITS + 3) + 128; + pd[1] = DESCALE (tmp1 + tmp6, PASS1_BITS + 3) + 128; + pd[6] = DESCALE (tmp1 - tmp6, PASS1_BITS + 3) + 128; + pd[2] = DESCALE (tmp2 + tmp5, PASS1_BITS + 3) + 128; + pd[5] = DESCALE (tmp2 - tmp5, PASS1_BITS + 3) + 128; + pd[4] = DESCALE (tmp3 + tmp4, PASS1_BITS + 3) + 128; + pd[3] = DESCALE (tmp3 - tmp4, PASS1_BITS + 3) + 128; + + pd += DCTSIZE; /* advance pointer to next row */ + } + + for (ctr = 0; ctr < 64; ctr++) + { + if (du[ctr] < 0) + du[ctr] = 0; + if (du[ctr] > 255) + du[ctr] = 255; + } +} + +static void +decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit du) +{ + int pos, h1, h2, qt; + + grub_memset (du, 0, sizeof (jpeg_data_unit)); + + qt = data->comp_index[id][0]; + h1 = data->comp_index[id][1]; + h2 = data->comp_index[id][2]; + + data->dc_value[id] += get_huff_code (data, get_huff_base (data, h1)); + + du[0] = + data->dc_value[id] * DESCALE ((int) data->quan_table[qt][0] * + (int) aanscales[0], 14 - 2); + pos = 1; + while (pos < 64) + { + int num, val; + + num = get_huff_base (data, h2); + if (!num) + break; + val = get_huff_code (data, num & 0xF); + num >>= 4; + pos += num; + du[natural_order[pos]] = + val * DESCALE ((int) data->quan_table[qt][pos] * + (int) aanscales[natural_order[pos]], 14 - 2); + pos++; + } + + idct_transform (du); +} + +#define SCALEBITS 16 /* speediest right-shift on some machines */ +#define ONE_HALF ((int) 1 << (SCALEBITS-1)) +#define FIX(x) ((int) ((x) * (1L<<SCALEBITS) + 0.5)) + +static void +build_color_table (struct grub_jpeg_data *data) +{ + int i, x; + + for (i = 0, x = -128; i <= 255; i++, x++) + { + data->Cr_r_tab[i] = (int) (FIX (1.40200) * x + ONE_HALF) >> SCALEBITS; + data->Cb_b_tab[i] = (int) (FIX (1.77200) * x + ONE_HALF) >> SCALEBITS; + data->Cr_g_tab[i] = (-FIX (0.71414)) * x; + data->Cb_g_tab[i] = (-FIX (0.34414)) * x + ONE_HALF; + } +} + +static void +decode_sos (struct grub_jpeg_data *data) +{ + int nc, i, r1, c1; + grub_uint8_t *ptr; + + get_word (data); + nc = get_byte (data); + + if (nc != 3) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: component count must be 3"); + grub_longjmp (data->jumper, 1); + } + + for (i = 0; i < nc; i++) + { + int id, ht; + + id = get_byte (data) - 1; + if ((id < 0) || (id >= 3)) + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index"); + grub_longjmp (data->jumper, 1); + } + + ht = get_byte (data); + data->comp_index[id][1] = (ht >> 4); + data->comp_index[id][2] = (ht & 0xF) + 2; + } + + get_byte (data); + get_word (data); + + if (grub_video_bitmap_create (data->bitmap, data->image_width, + data->image_height, + GRUB_VIDEO_BLIT_FORMAT_R8G8B8)) + grub_longjmp (data->jumper, 1); + + ptr = (*data->bitmap)->data; + data->bit_mask = 0x0; + + for (r1 = 0; r1 < (data->image_height >> 4); r1++) + for (c1 = 0; c1 < (data->image_width >> 4); c1++) + { + int r2, c2, r3, c3; + + decode_du (data, 0, data->ydu[0]); + decode_du (data, 0, data->ydu[1]); + + decode_du (data, 0, data->ydu[2]); + decode_du (data, 0, data->ydu[3]); + + decode_du (data, 1, data->cbdu); + decode_du (data, 2, data->crdu); + + for (r2 = 0; r2 < 2; r2++) + for (c2 = 0; c2 < 2; c2++) + for (r3 = 0; r3 < 8; r3++) + for (c3 = 0; c3 < 8; c3++) + { + int i0, i1, i2, cr, cb, dd; + + i0 = + ((r1 * 16 + r2 * 8 + r3) * (data->image_width) + c1 * 16 + + c2 * 8 + c3) * 3; + i1 = r3 * 8 + c3; + i2 = (r2 * 32 + c2 * 4) + (r3 >> 1) * 8 + (c3 >> 1); + + cr = data->crdu[i2]; + cb = data->cbdu[i2]; + + if (((c3 & 1) != 0) && ((i2 & 7) != 7)) + { + cr = (cr + data->crdu[i2 + 1]) >> 1; + cb = (cb + data->cbdu[i2 + 1]) >> 1; + } + + if (((r3 & 1) != 0) && (i2 < 64 - 8)) + { + cr = (cr + data->crdu[i2 + 8]) >> 1; + cb = (cb + data->cbdu[i2 + 8]) >> 1; + } + + /* Red */ + dd = data->ydu[r2 * 2 + c2][i1] + data->Cr_r_tab[cr]; + if (dd < 0) + dd = 0; + if (dd > 255) + dd = 255; + ptr[i0] = dd; + + /* Green */ + dd = + data->ydu[r2 * 2 + c2][i1] + + ((data->Cb_g_tab[cb] + data->Cr_g_tab[cr]) >> SCALEBITS); + if (dd < 0) + dd = 0; + if (dd > 255) + dd = 255; + ptr[i0 + 1] = dd; + + /* Blue */ + dd = data->ydu[r2 * 2 + c2][i1] + data->Cb_b_tab[cb]; + if (dd < 0) + dd = 0; + if (dd > 255) + dd = 255; + ptr[i0 + 2] = dd; + } + } +} + + +static grub_uint8_t +get_marker (struct grub_jpeg_data *data) +{ + grub_uint8_t r; + + r = get_byte (data); + + if (r != 0xFF) /* escape character */ + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid maker"); + grub_longjmp (data->jumper, 1); + } + + return get_byte (data); +} + +static void +decode_jpeg (struct grub_jpeg_data *data) +{ + build_color_table (data); + + if (get_marker (data) != M_SOI) /* Start Of Image */ + { + grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid jpeg file"); + grub_longjmp (data->jumper, 1); + } + + while (1) + { + grub_uint8_t marker; + + marker = get_marker (data); +#ifdef JPEG_DEBUG + grub_printf ("jpeg marker: %x\n", marker); +#endif + switch (marker) + { + case M_DHT: /* Define Huffman Table */ + decode_huff_table (data); + break; + case M_DQT: /* Define Quantization Table */ + decode_quan_table (data); + break; + case M_SOF0: /* Start Of Frame 0 */ + decode_sof (data); + break; + case M_SOS: /* Start Of Scan */ + decode_sos (data); + break; + case M_EOI: /* End Of Image */ + return; + case M_APP0: /* JFIF APP0 segment */ + case M_COM: /* Comment */ + { + grub_uint16_t sz; + + sz = get_word (data); + grub_file_seek (data->file, data->file->offset + sz - 2); + break; + } + default: + grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: unrecognized marker %x", + marker); + grub_longjmp (data->jumper, 1); + } + } +} + +static grub_err_t +grub_video_reader_jpeg (struct grub_video_bitmap **bitmap, + const char *filename) +{ + grub_file_t file; + struct grub_jpeg_data *data; + + file = grub_file_open (filename); + if (!file) + return grub_errno; + + data = grub_malloc (sizeof (*data)); + if (data != NULL) + { + int i; + + grub_memset (data, 0, sizeof (*data)); + data->file = file; + data->bitmap = bitmap; + if (!grub_setjmp (data->jumper)) + decode_jpeg (data); + + for (i = 0; i < 4; i++) + if (data->huff_value[i]) + grub_free (data->huff_value[i]); + grub_free (data); + } + + if (grub_errno != GRUB_ERR_NONE) + { + grub_video_bitmap_destroy (*bitmap); + *bitmap = 0; + } + + grub_file_close (file); + return grub_errno; +} + +#if defined(JPEG_DEBUG) +static grub_err_t +grub_cmd_jpegtest (struct grub_arg_list *state __attribute__ ((unused)), + int argc, char **args) +{ + struct grub_video_bitmap *bitmap = 0; + + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); + + grub_video_reader_jpeg (&bitmap, args[0]); + if (grub_errno != GRUB_ERR_NONE) + return grub_errno; + + grub_video_bitmap_destroy (bitmap); + + return GRUB_ERR_NONE; +} +#endif + +static struct grub_video_bitmap_reader jpg_reader = { + .extension = ".jpg", + .reader = grub_video_reader_jpeg, + .next = 0 +}; + +static struct grub_video_bitmap_reader jpeg_reader = { + .extension = ".jpeg", + .reader = grub_video_reader_jpeg, + .next = 0 +}; + +GRUB_MOD_INIT (video_reader_jpeg) +{ + grub_video_bitmap_reader_register (&jpg_reader); + grub_video_bitmap_reader_register (&jpeg_reader); +#if defined(JPEG_DEBUG) + grub_register_command ("jpegtest", grub_cmd_jpegtest, + GRUB_COMMAND_FLAG_BOTH, "jpegtest FILE", + "Tests loading of JPEG bitmap.", 0); +#endif +} + +GRUB_MOD_FINI (video_reader_jpeg) +{ +#if defined(JPEG_DEBUG) + grub_unregister_command ("jpegtest"); +#endif + grub_video_bitmap_reader_unregister (&jpeg_reader); + grub_video_bitmap_reader_unregister (&jpg_reader); +} -- Bean ^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [PATCH] jpeg image reader 2008-01-10 10:12 ` Bean @ 2008-01-12 8:51 ` Bean 2008-01-13 8:49 ` Bean 0 siblings, 1 reply; 23+ messages in thread From: Bean @ 2008-01-12 8:51 UTC (permalink / raw) To: The development of GRUB 2 Hi, changes in this new version: handle width/height that's not multiple of 8 add support for 1:1:1 sampling skip unrecognized marker instead of error. verify the size of sof, sos, quantization table and huffman table. /* * GRUB -- GRand Unified Bootloader * Copyright (C) 2008 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRUB is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GRUB. If not, see <http://www.gnu.org/licenses/>. */ #include <grub/bitmap.h> #include <grub/types.h> #include <grub/normal.h> #include <grub/dl.h> #include <grub/mm.h> #include <grub/misc.h> #include <grub/arg.h> #include <grub/file.h> #include <grub/setjmp.h> /* Uncomment following define to enable JPEG debug. */ //#define JPEG_DEBUG typedef enum { /* JPEG marker codes */ M_SOF0 = 0xc0, M_SOF1 = 0xc1, M_SOF2 = 0xc2, M_SOF3 = 0xc3, M_SOF5 = 0xc5, M_SOF6 = 0xc6, M_SOF7 = 0xc7, M_JPG = 0xc8, M_SOF9 = 0xc9, M_SOF10 = 0xca, M_SOF11 = 0xcb, M_SOF13 = 0xcd, M_SOF14 = 0xce, M_SOF15 = 0xcf, M_DHT = 0xc4, M_DAC = 0xcc, M_RST0 = 0xd0, M_RST1 = 0xd1, M_RST2 = 0xd2, M_RST3 = 0xd3, M_RST4 = 0xd4, M_RST5 = 0xd5, M_RST6 = 0xd6, M_RST7 = 0xd7, M_SOI = 0xd8, M_EOI = 0xd9, M_SOS = 0xda, M_DQT = 0xdb, M_DNL = 0xdc, M_DRI = 0xdd, M_DHP = 0xde, M_EXP = 0xdf, M_APP0 = 0xe0, M_APP1 = 0xe1, M_APP2 = 0xe2, M_APP3 = 0xe3, M_APP4 = 0xe4, M_APP5 = 0xe5, M_APP6 = 0xe6, M_APP7 = 0xe7, M_APP8 = 0xe8, M_APP9 = 0xe9, M_APP10 = 0xea, M_APP11 = 0xeb, M_APP12 = 0xec, M_APP13 = 0xed, M_APP14 = 0xee, M_APP15 = 0xef, M_JPG0 = 0xf0, M_JPG13 = 0xfd, M_COM = 0xfe, M_TEM = 0x01, M_ERROR = 0x100 } JPEG_MARKER; typedef int jpeg_data_unit[64]; struct grub_jpeg_data { grub_file_t file; grub_jmp_buf jumper; int image_width; int image_height; grub_uint8_t *huff_value[4]; int huff_offset[4][16]; int huff_maxval[4][16]; grub_uint8_t quan_table[2][64]; int comp_index[3][3]; jpeg_data_unit ydu[4]; jpeg_data_unit crdu; jpeg_data_unit cbdu; int Cr_r_tab[256], Cb_b_tab[256], Cr_g_tab[256], Cb_g_tab[256]; int vs, hs; int dc_value[3]; int bit_mask, bit_save; struct grub_video_bitmap **bitmap; }; static grub_uint8_t get_byte (struct grub_jpeg_data *data) { grub_uint8_t r; if (grub_file_read (data->file, (char *) &r, 1) != 1) grub_longjmp (data->jumper, 1); return r; } static grub_uint16_t get_word (struct grub_jpeg_data *data) { grub_uint16_t r; if (grub_file_read (data->file, (char *) &r, 2) != 2) grub_longjmp (data->jumper, 1); return grub_be_to_cpu16 (r); } static int get_bit (struct grub_jpeg_data *data) { int ret; if (data->bit_mask == 0) { data->bit_save = get_byte (data); if (data->bit_save == 0xFF) { if (get_byte (data) != 0) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid 0xFF in data stream"); grub_longjmp (data->jumper, 1); } } data->bit_mask = 0x80; } ret = (data->bit_save & data->bit_mask); data->bit_mask >>= 1; return ret; } static int get_number (struct grub_jpeg_data *data, int num) { int value, i, bit; if (num == 0) return 0; bit = get_bit (data); value = (bit != 0); for (i = 1; i < num; i++) value = value * 2 + (get_bit (data) != 0); if (!bit) value += 1 - (1 << num); return value; } static int get_huff_code (struct grub_jpeg_data *data, int id) { int code, i; code = 0; for (i = 0; i < 16; i++) { code <<= 1; if (get_bit (data)) code++; if (code < data->huff_maxval[id][i]) return data->huff_value[id][code + data->huff_offset[id][i]]; } grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: huffman decode fails"); grub_longjmp (data->jumper, 1); return 0; } static void decode_huff_table (struct grub_jpeg_data *data) { int id, ac, i, n, base, ofs; grub_uint32_t next_marker; grub_uint8_t count[16]; next_marker = data->file->offset; next_marker += get_word (data); id = get_byte (data); ac = (id >> 4); id &= 0xF; if (id > 1) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: too many huffman table"); grub_longjmp (data->jumper, 1); } if (grub_file_read (data->file, (char *) &count, sizeof (count)) != sizeof (count)) grub_longjmp (data->jumper, 1); n = 0; for (i = 0; i < 16; i++) n += count[i]; id += ac * 2; data->huff_value[id] = grub_malloc (n); if (data->huff_value[id] == NULL) grub_longjmp (data->jumper, 1); if (grub_file_read (data->file, (char *) data->huff_value[id], n) != n) grub_longjmp (data->jumper, 1); base = 0; ofs = 0; for (i = 0; i < 16; i++) { base += count[i]; ofs += count[i]; data->huff_maxval[id][i] = base; data->huff_offset[id][i] = ofs - base; base <<= 1; } if (data->file->offset != next_marker) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in huffman table"); grub_longjmp (data->jumper, 1); } } static void decode_quan_table (struct grub_jpeg_data *data) { int id; grub_uint32_t next_marker; next_marker = data->file->offset; next_marker += get_word (data); id = get_byte (data); if (id >= 0x10) /* upper 4-bit is precision */ { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: only 8-bit precision is supported"); grub_longjmp (data->jumper, 1); } if (id > 1) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: too many quantization table"); grub_longjmp (data->jumper, 1); } if (grub_file_read (data->file, (char *) &data->quan_table[id], 64) != 64) grub_longjmp (data->jumper, 1); if (data->file->offset != next_marker) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in quantization table"); grub_longjmp (data->jumper, 1); } } static void decode_sof (struct grub_jpeg_data *data) { int nc, i; grub_uint32_t next_marker; next_marker = data->file->offset; next_marker += get_word (data); if (get_byte (data) != 8) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: only 8-bit precision is supported"); grub_longjmp (data->jumper, 1); } data->image_height = get_word (data); data->image_width = get_word (data); if ((!data->image_height) || (!data->image_width)) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid image size"); grub_longjmp (data->jumper, 1); } nc = get_byte (data); if (nc != 3) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: component count must be 3"); grub_longjmp (data->jumper, 1); } for (i = 0; i < nc; i++) { int id, ss; id = get_byte (data) - 1; if ((id < 0) || (id >= 3)) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index"); grub_longjmp (data->jumper, 1); } ss = get_byte (data); if (!id) { int mask; data->vs = ss & 0xF; data->hs = ss >> 4; if ((data->vs > 2) || (data->hs > 2)) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: sampling method nor supported"); grub_longjmp (data->jumper, 1); } mask = 8 * data->vs - 1; data->image_height = (data->image_height + mask) & (~mask); mask = 8 * data->hs - 1; data->image_width = (data->image_width + mask) & (~mask); } else if (ss != 0x11) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: sampling method nor supported"); grub_longjmp (data->jumper, 1); } data->comp_index[id][0] = get_byte (data); } if (data->file->offset != next_marker) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sof"); grub_longjmp (data->jumper, 1); } } #define DCTSIZE 8 #define CONST_BITS 8 #define PASS1_BITS 2 #define FIX_1_082392200 ((int) 277) /* FIX(1.082392200) */ #define FIX_1_414213562 ((int) 362) /* FIX(1.414213562) */ #define FIX_1_847759065 ((int) 473) /* FIX(1.847759065) */ #define FIX_2_613125930 ((int) 669) /* FIX(2.613125930) */ #define ONE ((long) 1) #define DESCALE(x,n) (((x) + (ONE << ((n)-1))) >> (n)) #define MULTIPLY(var,const) DESCALE((var) * (const), CONST_BITS) static const grub_uint8_t natural_order[64] = { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 }; static const int aanscales[64] = { /* precomputed values scaled up by 14 bits */ 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 }; static void idct_transform (jpeg_data_unit du) { int *pd; int ctr; int tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; int tmp10, tmp11, tmp12, tmp13; int z5, z10, z11, z12, z13; /* Pass 1: process columns from input, store into work array. */ pd = du; for (ctr = DCTSIZE; ctr > 0; ctr--) { if ((pd[DCTSIZE * 1] | pd[DCTSIZE * 2] | pd[DCTSIZE * 3] | pd[DCTSIZE * 4] | pd[DCTSIZE * 5] | pd[DCTSIZE * 6] | pd[DCTSIZE * 7]) == 0) { pd[DCTSIZE * 1] = pd[DCTSIZE * 2] = pd[DCTSIZE * 3] = pd[DCTSIZE * 4] = pd[DCTSIZE * 5] = pd[DCTSIZE * 6] = pd[DCTSIZE * 7] = pd[DCTSIZE * 0]; pd++; /* advance pointers to next column */ continue; } /* Even part */ tmp0 = pd[DCTSIZE * 0]; tmp1 = pd[DCTSIZE * 2]; tmp2 = pd[DCTSIZE * 4]; tmp3 = pd[DCTSIZE * 6]; tmp10 = tmp0 + tmp2; /* phase 3 */ tmp11 = tmp0 - tmp2; tmp13 = tmp1 + tmp3; /* phases 5-3 */ tmp12 = MULTIPLY (tmp1 - tmp3, FIX_1_414213562) - tmp13; /* 2*c4 */ tmp0 = tmp10 + tmp13; /* phase 2 */ tmp3 = tmp10 - tmp13; tmp1 = tmp11 + tmp12; tmp2 = tmp11 - tmp12; /* Odd part */ tmp4 = pd[DCTSIZE * 1]; tmp5 = pd[DCTSIZE * 3]; tmp6 = pd[DCTSIZE * 5]; tmp7 = pd[DCTSIZE * 7]; z13 = tmp6 + tmp5; /* phase 6 */ z10 = tmp6 - tmp5; z11 = tmp4 + tmp7; z12 = tmp4 - tmp7; tmp7 = z11 + z13; /* phase 5 */ tmp11 = MULTIPLY (z11 - z13, FIX_1_414213562); /* 2*c4 */ z5 = MULTIPLY (z10 + z12, FIX_1_847759065); /* 2*c2 */ tmp10 = MULTIPLY (z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */ tmp12 = MULTIPLY (z10, -FIX_2_613125930) + z5; /* -2*(c2+c6) */ tmp6 = tmp12 - tmp7; /* phase 2 */ tmp5 = tmp11 - tmp6; tmp4 = tmp10 + tmp5; pd[DCTSIZE * 0] = (int) (tmp0 + tmp7); pd[DCTSIZE * 7] = (int) (tmp0 - tmp7); pd[DCTSIZE * 1] = (int) (tmp1 + tmp6); pd[DCTSIZE * 6] = (int) (tmp1 - tmp6); pd[DCTSIZE * 2] = (int) (tmp2 + tmp5); pd[DCTSIZE * 5] = (int) (tmp2 - tmp5); pd[DCTSIZE * 4] = (int) (tmp3 + tmp4); pd[DCTSIZE * 3] = (int) (tmp3 - tmp4); pd++; /* advance pointers to next column */ } /* Pass 2: process rows from work array, store into output array. */ /* Note that we must descale the results by a factor of 8 == 2**3, */ /* and also undo the PASS1_BITS scaling. */ pd = du; for (ctr = 0; ctr < DCTSIZE; ctr++) { /* Even part */ tmp10 = pd[0] + pd[4]; tmp11 = pd[0] - pd[4]; tmp13 = pd[2] + pd[6]; tmp12 = MULTIPLY (pd[2] - pd[6], FIX_1_414213562) - tmp13; tmp0 = tmp10 + tmp13; tmp3 = tmp10 - tmp13; tmp1 = tmp11 + tmp12; tmp2 = tmp11 - tmp12; /* Odd part */ z13 = pd[5] + pd[3]; z10 = pd[5] - pd[3]; z11 = pd[1] + pd[7]; z12 = pd[1] - pd[7]; tmp7 = z11 + z13; /* phase 5 */ tmp11 = MULTIPLY (z11 - z13, FIX_1_414213562); /* 2*c4 */ z5 = MULTIPLY (z10 + z12, FIX_1_847759065); /* 2*c2 */ tmp10 = MULTIPLY (z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */ tmp12 = MULTIPLY (z10, -FIX_2_613125930) + z5; /* -2*(c2+c6) */ tmp6 = tmp12 - tmp7; /* phase 2 */ tmp5 = tmp11 - tmp6; tmp4 = tmp10 + tmp5; /* Final output stage: scale down by a factor of 8 and range-limit */ pd[0] = DESCALE (tmp0 + tmp7, PASS1_BITS + 3) + 128; pd[7] = DESCALE (tmp0 - tmp7, PASS1_BITS + 3) + 128; pd[1] = DESCALE (tmp1 + tmp6, PASS1_BITS + 3) + 128; pd[6] = DESCALE (tmp1 - tmp6, PASS1_BITS + 3) + 128; pd[2] = DESCALE (tmp2 + tmp5, PASS1_BITS + 3) + 128; pd[5] = DESCALE (tmp2 - tmp5, PASS1_BITS + 3) + 128; pd[4] = DESCALE (tmp3 + tmp4, PASS1_BITS + 3) + 128; pd[3] = DESCALE (tmp3 - tmp4, PASS1_BITS + 3) + 128; pd += DCTSIZE; /* advance pointer to next row */ } for (ctr = 0; ctr < 64; ctr++) { if (du[ctr] < 0) du[ctr] = 0; if (du[ctr] > 255) du[ctr] = 255; } } static void decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit du) { int pos, h1, h2, qt; grub_memset (du, 0, sizeof (jpeg_data_unit)); qt = data->comp_index[id][0]; h1 = data->comp_index[id][1]; h2 = data->comp_index[id][2]; data->dc_value[id] += get_number (data, get_huff_code (data, h1)); du[0] = data->dc_value[id] * DESCALE ((int) data->quan_table[qt][0] * (int) aanscales[0], 14 - 2); pos = 1; while (pos < 64) { int num, val; num = get_huff_code (data, h2); if (!num) break; val = get_number (data, num & 0xF); num >>= 4; pos += num; du[natural_order[pos]] = val * DESCALE ((int) data->quan_table[qt][pos] * (int) aanscales[natural_order[pos]], 14 - 2); pos++; } idct_transform (du); } #define SCALEBITS 16 /* speediest right-shift on some machines */ #define ONE_HALF ((int) 1 << (SCALEBITS-1)) #define FIX(x) ((int) ((x) * (1L<<SCALEBITS) + 0.5)) static void build_color_table (struct grub_jpeg_data *data) { int i, x; for (i = 0, x = -128; i <= 255; i++, x++) { data->Cr_r_tab[i] = (int) (FIX (1.40200) * x + ONE_HALF) >> SCALEBITS; data->Cb_b_tab[i] = (int) (FIX (1.77200) * x + ONE_HALF) >> SCALEBITS; data->Cr_g_tab[i] = (-FIX (0.71414)) * x; data->Cb_g_tab[i] = (-FIX (0.34414)) * x + ONE_HALF; } } static void decode_sos (struct grub_jpeg_data *data) { int nc, i, r1, c1, vb, hb; grub_uint8_t *ptr; grub_uint32_t data_offset; data_offset = data->file->offset; data_offset += get_word (data); nc = get_byte (data); if (nc != 3) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: component count must be 3"); grub_longjmp (data->jumper, 1); } for (i = 0; i < nc; i++) { int id, ht; id = get_byte (data) - 1; if ((id < 0) || (id >= 3)) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index"); grub_longjmp (data->jumper, 1); } ht = get_byte (data); data->comp_index[id][1] = (ht >> 4); data->comp_index[id][2] = (ht & 0xF) + 2; } get_byte (data); /* skip 3 unused bytes */ get_word (data); if (data->file->offset != data_offset) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sos"); grub_longjmp (data->jumper, 1); } if (grub_video_bitmap_create (data->bitmap, data->image_width, data->image_height, GRUB_VIDEO_BLIT_FORMAT_R8G8B8)) grub_longjmp (data->jumper, 1); ptr = (*data->bitmap)->data; data->bit_mask = 0x0; vb = data->vs * 8; hb = data->hs * 8; for (r1 = 0; r1 < (data->image_height / vb); r1++) for (c1 = 0; c1 < (data->image_width / hb); c1++) { int r2, c2; for (r2 = 0; r2 < data->vs; r2++) for (c2 = 0; c2 < data->hs; c2++) decode_du (data, 0, data->ydu[r2 * 2 + c2]); decode_du (data, 1, data->cbdu); decode_du (data, 2, data->crdu); for (r2 = 0; r2 < vb; r2++) for (c2 = 0; c2 < hb; c2++) { int i0, i1, yy, cr, cb, dd; i0 = ((r1 * vb + r2) * data->image_width + c1 * hb + c2) * 3; i1 = (r2 / data->vs) * 8 + (c2 / data->hs); yy = data->ydu[(r2 / 8) * 2 + (c2 / 8)][(r2 % 8) * 8 + (c2 % 8)]; cr = data->crdu[i1]; cb = data->cbdu[i1]; /* Red */ dd = yy + data->Cr_r_tab[cr]; if (dd < 0) dd = 0; if (dd > 255) dd = 255; ptr[i0] = dd; /* Green */ dd = yy + ((data->Cb_g_tab[cb] + data->Cr_g_tab[cr]) >> SCALEBITS); if (dd < 0) dd = 0; if (dd > 255) dd = 255; ptr[i0 + 1] = dd; /* Blue */ dd = yy + data->Cb_b_tab[cb]; if (dd < 0) dd = 0; if (dd > 255) dd = 255; ptr[i0 + 2] = dd; } } } static grub_uint8_t get_marker (struct grub_jpeg_data *data) { grub_uint8_t r; r = get_byte (data); if (r != 0xFF) /* escape character */ { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid maker"); grub_longjmp (data->jumper, 1); } return get_byte (data); } static void decode_jpeg (struct grub_jpeg_data *data) { build_color_table (data); if (get_marker (data) != M_SOI) /* Start Of Image */ { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid jpeg file"); grub_longjmp (data->jumper, 1); } while (1) { grub_uint8_t marker; marker = get_marker (data); #ifdef JPEG_DEBUG grub_printf ("jpeg marker: %x\n", marker); #endif switch (marker) { case M_DHT: /* Define Huffman Table */ decode_huff_table (data); break; case M_DQT: /* Define Quantization Table */ decode_quan_table (data); break; case M_SOF0: /* Start Of Frame 0 */ decode_sof (data); break; case M_SOS: /* Start Of Scan */ decode_sos (data); break; case M_EOI: /* End Of Image */ return; default: /* Skip unrecognized marker */ { grub_uint16_t sz; sz = get_word (data); grub_file_seek (data->file, data->file->offset + sz - 2); } } } } static grub_err_t grub_video_reader_jpeg (struct grub_video_bitmap **bitmap, const char *filename) { grub_file_t file; struct grub_jpeg_data *data; file = grub_file_open (filename); if (!file) return grub_errno; data = grub_malloc (sizeof (*data)); if (data != NULL) { int i; grub_memset (data, 0, sizeof (*data)); data->file = file; data->bitmap = bitmap; if (!grub_setjmp (data->jumper)) decode_jpeg (data); for (i = 0; i < 4; i++) if (data->huff_value[i]) grub_free (data->huff_value[i]); grub_free (data); } if (grub_errno != GRUB_ERR_NONE) { grub_video_bitmap_destroy (*bitmap); *bitmap = 0; } grub_file_close (file); return grub_errno; } #if defined(JPEG_DEBUG) static grub_err_t grub_cmd_jpegtest (struct grub_arg_list *state __attribute__ ((unused)), int argc, char **args) { struct grub_video_bitmap *bitmap = 0; if (argc != 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); grub_video_reader_jpeg (&bitmap, args[0]); if (grub_errno != GRUB_ERR_NONE) return grub_errno; grub_video_bitmap_destroy (bitmap); return GRUB_ERR_NONE; } #endif static struct grub_video_bitmap_reader jpg_reader = { .extension = ".jpg", .reader = grub_video_reader_jpeg, .next = 0 }; static struct grub_video_bitmap_reader jpeg_reader = { .extension = ".jpeg", .reader = grub_video_reader_jpeg, .next = 0 }; GRUB_MOD_INIT (video_reader_jpeg) { grub_video_bitmap_reader_register (&jpg_reader); grub_video_bitmap_reader_register (&jpeg_reader); #if defined(JPEG_DEBUG) grub_register_command ("jpegtest", grub_cmd_jpegtest, GRUB_COMMAND_FLAG_BOTH, "jpegtest FILE", "Tests loading of JPEG bitmap.", 0); #endif } GRUB_MOD_FINI (video_reader_jpeg) { #if defined(JPEG_DEBUG) grub_unregister_command ("jpegtest"); #endif grub_video_bitmap_reader_unregister (&jpeg_reader); grub_video_bitmap_reader_unregister (&jpg_reader); } -- Bean ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] jpeg image reader 2008-01-12 8:51 ` Bean @ 2008-01-13 8:49 ` Bean 2008-01-13 18:31 ` Marco Gerards 0 siblings, 1 reply; 23+ messages in thread From: Bean @ 2008-01-13 8:49 UTC (permalink / raw) To: The development of GRUB 2 Hi, change the handling of width/height that's not aligned, now it use the exact size instead of padding. /* * GRUB -- GRand Unified Bootloader * Copyright (C) 2008 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRUB is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GRUB. If not, see <http://www.gnu.org/licenses/>. */ #include <grub/bitmap.h> #include <grub/types.h> #include <grub/normal.h> #include <grub/dl.h> #include <grub/mm.h> #include <grub/misc.h> #include <grub/arg.h> #include <grub/file.h> #include <grub/setjmp.h> /* Uncomment following define to enable JPEG debug. */ //#define JPEG_DEBUG typedef enum { /* JPEG marker codes */ M_SOF0 = 0xc0, M_SOF1 = 0xc1, M_SOF2 = 0xc2, M_SOF3 = 0xc3, M_SOF5 = 0xc5, M_SOF6 = 0xc6, M_SOF7 = 0xc7, M_JPG = 0xc8, M_SOF9 = 0xc9, M_SOF10 = 0xca, M_SOF11 = 0xcb, M_SOF13 = 0xcd, M_SOF14 = 0xce, M_SOF15 = 0xcf, M_DHT = 0xc4, M_DAC = 0xcc, M_RST0 = 0xd0, M_RST1 = 0xd1, M_RST2 = 0xd2, M_RST3 = 0xd3, M_RST4 = 0xd4, M_RST5 = 0xd5, M_RST6 = 0xd6, M_RST7 = 0xd7, M_SOI = 0xd8, M_EOI = 0xd9, M_SOS = 0xda, M_DQT = 0xdb, M_DNL = 0xdc, M_DRI = 0xdd, M_DHP = 0xde, M_EXP = 0xdf, M_APP0 = 0xe0, M_APP1 = 0xe1, M_APP2 = 0xe2, M_APP3 = 0xe3, M_APP4 = 0xe4, M_APP5 = 0xe5, M_APP6 = 0xe6, M_APP7 = 0xe7, M_APP8 = 0xe8, M_APP9 = 0xe9, M_APP10 = 0xea, M_APP11 = 0xeb, M_APP12 = 0xec, M_APP13 = 0xed, M_APP14 = 0xee, M_APP15 = 0xef, M_JPG0 = 0xf0, M_JPG13 = 0xfd, M_COM = 0xfe, M_TEM = 0x01, M_ERROR = 0x100 } JPEG_MARKER; typedef int jpeg_data_unit[64]; struct grub_jpeg_data { grub_file_t file; grub_jmp_buf jumper; int image_width; int image_height; grub_uint8_t *huff_value[4]; int huff_offset[4][16]; int huff_maxval[4][16]; grub_uint8_t quan_table[2][64]; int comp_index[3][3]; jpeg_data_unit ydu[4]; jpeg_data_unit crdu; jpeg_data_unit cbdu; int Cr_r_tab[256], Cb_b_tab[256], Cr_g_tab[256], Cb_g_tab[256]; int vs, hs; int dc_value[3]; int bit_mask, bit_save; struct grub_video_bitmap **bitmap; }; static grub_uint8_t get_byte (struct grub_jpeg_data *data) { grub_uint8_t r; if (grub_file_read (data->file, (char *) &r, 1) != 1) grub_longjmp (data->jumper, 1); return r; } static grub_uint16_t get_word (struct grub_jpeg_data *data) { grub_uint16_t r; if (grub_file_read (data->file, (char *) &r, 2) != 2) grub_longjmp (data->jumper, 1); return grub_be_to_cpu16 (r); } static int get_bit (struct grub_jpeg_data *data) { int ret; if (data->bit_mask == 0) { data->bit_save = get_byte (data); if (data->bit_save == 0xFF) { if (get_byte (data) != 0) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid 0xFF in data stream"); grub_longjmp (data->jumper, 1); } } data->bit_mask = 0x80; } ret = (data->bit_save & data->bit_mask); data->bit_mask >>= 1; return ret; } static int get_number (struct grub_jpeg_data *data, int num) { int value, i, bit; if (num == 0) return 0; bit = get_bit (data); value = (bit != 0); for (i = 1; i < num; i++) value = value * 2 + (get_bit (data) != 0); if (!bit) value += 1 - (1 << num); return value; } static int get_huff_code (struct grub_jpeg_data *data, int id) { int code, i; code = 0; for (i = 0; i < 16; i++) { code <<= 1; if (get_bit (data)) code++; if (code < data->huff_maxval[id][i]) return data->huff_value[id][code + data->huff_offset[id][i]]; } grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: huffman decode fails"); grub_longjmp (data->jumper, 1); return 0; } static void decode_huff_table (struct grub_jpeg_data *data) { int id, ac, i, n, base, ofs; grub_uint32_t next_marker; grub_uint8_t count[16]; next_marker = data->file->offset; next_marker += get_word (data); id = get_byte (data); ac = (id >> 4); id &= 0xF; if (id > 1) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: too many huffman table"); grub_longjmp (data->jumper, 1); } if (grub_file_read (data->file, (char *) &count, sizeof (count)) != sizeof (count)) grub_longjmp (data->jumper, 1); n = 0; for (i = 0; i < 16; i++) n += count[i]; id += ac * 2; data->huff_value[id] = grub_malloc (n); if (data->huff_value[id] == NULL) grub_longjmp (data->jumper, 1); if (grub_file_read (data->file, (char *) data->huff_value[id], n) != n) grub_longjmp (data->jumper, 1); base = 0; ofs = 0; for (i = 0; i < 16; i++) { base += count[i]; ofs += count[i]; data->huff_maxval[id][i] = base; data->huff_offset[id][i] = ofs - base; base <<= 1; } if (data->file->offset != next_marker) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in huffman table"); grub_longjmp (data->jumper, 1); } } static void decode_quan_table (struct grub_jpeg_data *data) { int id; grub_uint32_t next_marker; next_marker = data->file->offset; next_marker += get_word (data); id = get_byte (data); if (id >= 0x10) /* upper 4-bit is precision */ { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: only 8-bit precision is supported"); grub_longjmp (data->jumper, 1); } if (id > 1) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: too many quantization table"); grub_longjmp (data->jumper, 1); } if (grub_file_read (data->file, (char *) &data->quan_table[id], 64) != 64) grub_longjmp (data->jumper, 1); if (data->file->offset != next_marker) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in quantization table"); grub_longjmp (data->jumper, 1); } } static void decode_sof (struct grub_jpeg_data *data) { int i, cc; grub_uint32_t next_marker; next_marker = data->file->offset; next_marker += get_word (data); if (get_byte (data) != 8) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: only 8-bit precision is supported"); grub_longjmp (data->jumper, 1); } data->image_height = get_word (data); data->image_width = get_word (data); if ((!data->image_height) || (!data->image_width)) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid image size"); grub_longjmp (data->jumper, 1); } cc = get_byte (data); if (cc != 3) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: component count must be 3"); grub_longjmp (data->jumper, 1); } for (i = 0; i < cc; i++) { int id, ss; id = get_byte (data) - 1; if ((id < 0) || (id >= 3)) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index"); grub_longjmp (data->jumper, 1); } ss = get_byte (data); if (!id) { data->vs = ss & 0xF; data->hs = ss >> 4; if ((data->vs > 2) || (data->hs > 2)) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: sampling method nor supported"); grub_longjmp (data->jumper, 1); } } else if (ss != 0x11) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: sampling method nor supported"); grub_longjmp (data->jumper, 1); } data->comp_index[id][0] = get_byte (data); } if (data->file->offset != next_marker) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sof"); grub_longjmp (data->jumper, 1); } } #define DCTSIZE 8 #define CONST_BITS 8 #define PASS1_BITS 2 #define FIX_1_082392200 ((int) 277) /* FIX(1.082392200) */ #define FIX_1_414213562 ((int) 362) /* FIX(1.414213562) */ #define FIX_1_847759065 ((int) 473) /* FIX(1.847759065) */ #define FIX_2_613125930 ((int) 669) /* FIX(2.613125930) */ #define ONE ((long) 1) #define DESCALE(x,n) (((x) + (ONE << ((n)-1))) >> (n)) #define MULTIPLY(var,const) DESCALE((var) * (const), CONST_BITS) static const grub_uint8_t natural_order[64] = { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 }; static const int aanscales[64] = { /* precomputed values scaled up by 14 bits */ 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 }; static void idct_transform (jpeg_data_unit du) { int *pd; int ctr; int tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; int tmp10, tmp11, tmp12, tmp13; int z5, z10, z11, z12, z13; /* Pass 1: process columns from input, store into work array. */ pd = du; for (ctr = DCTSIZE; ctr > 0; ctr--) { if ((pd[DCTSIZE * 1] | pd[DCTSIZE * 2] | pd[DCTSIZE * 3] | pd[DCTSIZE * 4] | pd[DCTSIZE * 5] | pd[DCTSIZE * 6] | pd[DCTSIZE * 7]) == 0) { pd[DCTSIZE * 1] = pd[DCTSIZE * 2] = pd[DCTSIZE * 3] = pd[DCTSIZE * 4] = pd[DCTSIZE * 5] = pd[DCTSIZE * 6] = pd[DCTSIZE * 7] = pd[DCTSIZE * 0]; pd++; /* advance pointers to next column */ continue; } /* Even part */ tmp0 = pd[DCTSIZE * 0]; tmp1 = pd[DCTSIZE * 2]; tmp2 = pd[DCTSIZE * 4]; tmp3 = pd[DCTSIZE * 6]; tmp10 = tmp0 + tmp2; /* phase 3 */ tmp11 = tmp0 - tmp2; tmp13 = tmp1 + tmp3; /* phases 5-3 */ tmp12 = MULTIPLY (tmp1 - tmp3, FIX_1_414213562) - tmp13; /* 2*c4 */ tmp0 = tmp10 + tmp13; /* phase 2 */ tmp3 = tmp10 - tmp13; tmp1 = tmp11 + tmp12; tmp2 = tmp11 - tmp12; /* Odd part */ tmp4 = pd[DCTSIZE * 1]; tmp5 = pd[DCTSIZE * 3]; tmp6 = pd[DCTSIZE * 5]; tmp7 = pd[DCTSIZE * 7]; z13 = tmp6 + tmp5; /* phase 6 */ z10 = tmp6 - tmp5; z11 = tmp4 + tmp7; z12 = tmp4 - tmp7; tmp7 = z11 + z13; /* phase 5 */ tmp11 = MULTIPLY (z11 - z13, FIX_1_414213562); /* 2*c4 */ z5 = MULTIPLY (z10 + z12, FIX_1_847759065); /* 2*c2 */ tmp10 = MULTIPLY (z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */ tmp12 = MULTIPLY (z10, -FIX_2_613125930) + z5; /* -2*(c2+c6) */ tmp6 = tmp12 - tmp7; /* phase 2 */ tmp5 = tmp11 - tmp6; tmp4 = tmp10 + tmp5; pd[DCTSIZE * 0] = (int) (tmp0 + tmp7); pd[DCTSIZE * 7] = (int) (tmp0 - tmp7); pd[DCTSIZE * 1] = (int) (tmp1 + tmp6); pd[DCTSIZE * 6] = (int) (tmp1 - tmp6); pd[DCTSIZE * 2] = (int) (tmp2 + tmp5); pd[DCTSIZE * 5] = (int) (tmp2 - tmp5); pd[DCTSIZE * 4] = (int) (tmp3 + tmp4); pd[DCTSIZE * 3] = (int) (tmp3 - tmp4); pd++; /* advance pointers to next column */ } /* Pass 2: process rows from work array, store into output array. */ /* Note that we must descale the results by a factor of 8 == 2**3, */ /* and also undo the PASS1_BITS scaling. */ pd = du; for (ctr = 0; ctr < DCTSIZE; ctr++) { /* Even part */ tmp10 = pd[0] + pd[4]; tmp11 = pd[0] - pd[4]; tmp13 = pd[2] + pd[6]; tmp12 = MULTIPLY (pd[2] - pd[6], FIX_1_414213562) - tmp13; tmp0 = tmp10 + tmp13; tmp3 = tmp10 - tmp13; tmp1 = tmp11 + tmp12; tmp2 = tmp11 - tmp12; /* Odd part */ z13 = pd[5] + pd[3]; z10 = pd[5] - pd[3]; z11 = pd[1] + pd[7]; z12 = pd[1] - pd[7]; tmp7 = z11 + z13; /* phase 5 */ tmp11 = MULTIPLY (z11 - z13, FIX_1_414213562); /* 2*c4 */ z5 = MULTIPLY (z10 + z12, FIX_1_847759065); /* 2*c2 */ tmp10 = MULTIPLY (z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */ tmp12 = MULTIPLY (z10, -FIX_2_613125930) + z5; /* -2*(c2+c6) */ tmp6 = tmp12 - tmp7; /* phase 2 */ tmp5 = tmp11 - tmp6; tmp4 = tmp10 + tmp5; /* Final output stage: scale down by a factor of 8 and range-limit */ pd[0] = DESCALE (tmp0 + tmp7, PASS1_BITS + 3) + 128; pd[7] = DESCALE (tmp0 - tmp7, PASS1_BITS + 3) + 128; pd[1] = DESCALE (tmp1 + tmp6, PASS1_BITS + 3) + 128; pd[6] = DESCALE (tmp1 - tmp6, PASS1_BITS + 3) + 128; pd[2] = DESCALE (tmp2 + tmp5, PASS1_BITS + 3) + 128; pd[5] = DESCALE (tmp2 - tmp5, PASS1_BITS + 3) + 128; pd[4] = DESCALE (tmp3 + tmp4, PASS1_BITS + 3) + 128; pd[3] = DESCALE (tmp3 - tmp4, PASS1_BITS + 3) + 128; pd += DCTSIZE; /* advance pointer to next row */ } for (ctr = 0; ctr < 64; ctr++) { if (du[ctr] < 0) du[ctr] = 0; if (du[ctr] > 255) du[ctr] = 255; } } static void decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit du) { int pos, h1, h2, qt; grub_memset (du, 0, sizeof (jpeg_data_unit)); qt = data->comp_index[id][0]; h1 = data->comp_index[id][1]; h2 = data->comp_index[id][2]; data->dc_value[id] += get_number (data, get_huff_code (data, h1)); du[0] = data->dc_value[id] * DESCALE ((int) data->quan_table[qt][0] * (int) aanscales[0], 14 - 2); pos = 1; while (pos < 64) { int num, val; num = get_huff_code (data, h2); if (!num) break; val = get_number (data, num & 0xF); num >>= 4; pos += num; du[natural_order[pos]] = val * DESCALE ((int) data->quan_table[qt][pos] * (int) aanscales[natural_order[pos]], 14 - 2); pos++; } idct_transform (du); } #define SCALEBITS 16 /* speediest right-shift on some machines */ #define ONE_HALF ((int) 1 << (SCALEBITS-1)) #define FIX(x) ((int) ((x) * (1L<<SCALEBITS) + 0.5)) static void build_color_table (struct grub_jpeg_data *data) { int i, x; for (i = 0, x = -128; i <= 255; i++, x++) { data->Cr_r_tab[i] = (int) (FIX (1.40200) * x + ONE_HALF) >> SCALEBITS; data->Cb_b_tab[i] = (int) (FIX (1.77200) * x + ONE_HALF) >> SCALEBITS; data->Cr_g_tab[i] = (-FIX (0.71414)) * x; data->Cb_g_tab[i] = (-FIX (0.34414)) * x + ONE_HALF; } } static void decode_sos (struct grub_jpeg_data *data) { int i, cc, r1, c1, nr1, nc1, vb, hb; grub_uint8_t *ptr1; grub_uint32_t data_offset; data_offset = data->file->offset; data_offset += get_word (data); cc = get_byte (data); if (cc != 3) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: component count must be 3"); grub_longjmp (data->jumper, 1); } for (i = 0; i < cc; i++) { int id, ht; id = get_byte (data) - 1; if ((id < 0) || (id >= 3)) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index"); grub_longjmp (data->jumper, 1); } ht = get_byte (data); data->comp_index[id][1] = (ht >> 4); data->comp_index[id][2] = (ht & 0xF) + 2; } get_byte (data); /* skip 3 unused bytes */ get_word (data); if (data->file->offset != data_offset) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sos"); grub_longjmp (data->jumper, 1); } if (grub_video_bitmap_create (data->bitmap, data->image_width, data->image_height, GRUB_VIDEO_BLIT_FORMAT_R8G8B8)) grub_longjmp (data->jumper, 1); data->bit_mask = 0x0; vb = data->vs * 8; hb = data->hs * 8; nr1 = (data->image_height + vb - 1) / vb; nc1 = (data->image_width + hb - 1) / hb; ptr1 = (*data->bitmap)->data; for (r1 = 0; r1 < nr1; r1++, ptr1 += (vb * data->image_width - hb * nc1) * 3) for (c1 = 0; c1 < nc1; c1++, ptr1 += hb * 3) { int r2, c2, nr2, nc2; grub_uint8_t *ptr2; for (r2 = 0; r2 < data->vs; r2++) for (c2 = 0; c2 < data->hs; c2++) decode_du (data, 0, data->ydu[r2 * 2 + c2]); decode_du (data, 1, data->cbdu); decode_du (data, 2, data->crdu); nr2 = (r1 == nr1 - 1) ? (data->image_height - r1 * vb) : vb; nc2 = (c1 == nc1 - 1) ? (data->image_width - c1 * hb) : hb; ptr2 = ptr1; for (r2 = 0; r2 < nr2; r2++, ptr2 += (data->image_width - nc2) * 3) for (c2 = 0; c2 < nc2; c2++) { int i0, yy, cr, cb, dd; i0 = (r2 / data->vs) * 8 + (c2 / data->hs); cr = data->crdu[i0]; cb = data->cbdu[i0]; yy = data->ydu[(r2 / 8) * 2 + (c2 / 8)][(r2 % 8) * 8 + (c2 % 8)]; /* Red */ dd = yy + data->Cr_r_tab[cr]; if (dd < 0) dd = 0; if (dd > 255) dd = 255; *(ptr2++) = dd; /* Green */ dd = yy + ((data->Cb_g_tab[cb] + data->Cr_g_tab[cr]) >> SCALEBITS); if (dd < 0) dd = 0; if (dd > 255) dd = 255; *(ptr2++) = dd; /* Blue */ dd = yy + data->Cb_b_tab[cb]; if (dd < 0) dd = 0; if (dd > 255) dd = 255; *(ptr2++) = dd; } } } static grub_uint8_t get_marker (struct grub_jpeg_data *data) { grub_uint8_t r; r = get_byte (data); if (r != 0xFF) /* escape character */ { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid maker"); grub_longjmp (data->jumper, 1); } return get_byte (data); } static void decode_jpeg (struct grub_jpeg_data *data) { build_color_table (data); if (get_marker (data) != M_SOI) /* Start Of Image */ { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid jpeg file"); grub_longjmp (data->jumper, 1); } while (1) { grub_uint8_t marker; marker = get_marker (data); #ifdef JPEG_DEBUG grub_printf ("jpeg marker: %x\n", marker); #endif switch (marker) { case M_DHT: /* Define Huffman Table */ decode_huff_table (data); break; case M_DQT: /* Define Quantization Table */ decode_quan_table (data); break; case M_SOF0: /* Start Of Frame 0 */ decode_sof (data); break; case M_SOS: /* Start Of Scan */ decode_sos (data); break; case M_EOI: /* End Of Image */ return; default: /* Skip unrecognized marker */ { grub_uint16_t sz; sz = get_word (data); grub_file_seek (data->file, data->file->offset + sz - 2); } } } } static grub_err_t grub_video_reader_jpeg (struct grub_video_bitmap **bitmap, const char *filename) { grub_file_t file; struct grub_jpeg_data *data; file = grub_file_open (filename); if (!file) return grub_errno; data = grub_malloc (sizeof (*data)); if (data != NULL) { int i; grub_memset (data, 0, sizeof (*data)); data->file = file; data->bitmap = bitmap; if (!grub_setjmp (data->jumper)) decode_jpeg (data); for (i = 0; i < 4; i++) if (data->huff_value[i]) grub_free (data->huff_value[i]); grub_free (data); } if (grub_errno != GRUB_ERR_NONE) { grub_video_bitmap_destroy (*bitmap); *bitmap = 0; } grub_file_close (file); return grub_errno; } #if defined(JPEG_DEBUG) static grub_err_t grub_cmd_jpegtest (struct grub_arg_list *state __attribute__ ((unused)), int argc, char **args) { struct grub_video_bitmap *bitmap = 0; if (argc != 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); grub_video_reader_jpeg (&bitmap, args[0]); if (grub_errno != GRUB_ERR_NONE) return grub_errno; grub_video_bitmap_destroy (bitmap); return GRUB_ERR_NONE; } #endif static struct grub_video_bitmap_reader jpg_reader = { .extension = ".jpg", .reader = grub_video_reader_jpeg, .next = 0 }; static struct grub_video_bitmap_reader jpeg_reader = { .extension = ".jpeg", .reader = grub_video_reader_jpeg, .next = 0 }; GRUB_MOD_INIT (video_reader_jpeg) { grub_video_bitmap_reader_register (&jpg_reader); grub_video_bitmap_reader_register (&jpeg_reader); #if defined(JPEG_DEBUG) grub_register_command ("jpegtest", grub_cmd_jpegtest, GRUB_COMMAND_FLAG_BOTH, "jpegtest FILE", "Tests loading of JPEG bitmap.", 0); #endif } GRUB_MOD_FINI (video_reader_jpeg) { #if defined(JPEG_DEBUG) grub_unregister_command ("jpegtest"); #endif grub_video_bitmap_reader_unregister (&jpeg_reader); grub_video_bitmap_reader_unregister (&jpg_reader); } -- Bean ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] jpeg image reader 2008-01-13 8:49 ` Bean @ 2008-01-13 18:31 ` Marco Gerards 2008-01-14 16:36 ` Bean 0 siblings, 1 reply; 23+ messages in thread From: Marco Gerards @ 2008-01-13 18:31 UTC (permalink / raw) To: The development of GRUB 2 Bean <bean123ch@gmail.com> writes: Hi, > change the handling of width/height that's not aligned, now it use the > exact size instead of padding. You forgot the changelog entry. I'll do a quick review. Especially the longjmp stuff should be changed, IMO. Otherwise the code is of good quality and I hope it can be committed soon. Please see the comments below. -- Marco > /* > * GRUB -- GRand Unified Bootloader > * Copyright (C) 2008 Free Software Foundation, Inc. Did you write all the code yourself? > * GRUB is free software: you can redistribute it and/or modify > * it under the terms of the GNU General Public License as published by > * the Free Software Foundation, either version 3 of the License, or > * (at your option) any later version. > * > * GRUB is distributed in the hope that it will be useful, > * but WITHOUT ANY WARRANTY; without even the implied warranty of > * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > * GNU General Public License for more details. > * > * You should have received a copy of the GNU General Public License > * along with GRUB. If not, see <http://www.gnu.org/licenses/>. > */ > > #include <grub/bitmap.h> > #include <grub/types.h> > #include <grub/normal.h> > #include <grub/dl.h> > #include <grub/mm.h> > #include <grub/misc.h> > #include <grub/arg.h> > #include <grub/file.h> > #include <grub/setjmp.h> setjmp!? > /* Uncomment following define to enable JPEG debug. */ > //#define JPEG_DEBUG > > typedef enum > { /* JPEG marker codes */ > M_SOF0 = 0xc0, > M_SOF1 = 0xc1, > M_SOF2 = 0xc2, > M_SOF3 = 0xc3, > > M_SOF5 = 0xc5, > M_SOF6 = 0xc6, > M_SOF7 = 0xc7, > > M_JPG = 0xc8, > M_SOF9 = 0xc9, > M_SOF10 = 0xca, > M_SOF11 = 0xcb, > > M_SOF13 = 0xcd, > M_SOF14 = 0xce, > M_SOF15 = 0xcf, > > M_DHT = 0xc4, > > M_DAC = 0xcc, > > M_RST0 = 0xd0, > M_RST1 = 0xd1, > M_RST2 = 0xd2, > M_RST3 = 0xd3, > M_RST4 = 0xd4, > M_RST5 = 0xd5, > M_RST6 = 0xd6, > M_RST7 = 0xd7, > > M_SOI = 0xd8, > M_EOI = 0xd9, > M_SOS = 0xda, > M_DQT = 0xdb, > M_DNL = 0xdc, > M_DRI = 0xdd, > M_DHP = 0xde, > M_EXP = 0xdf, > > M_APP0 = 0xe0, > M_APP1 = 0xe1, > M_APP2 = 0xe2, > M_APP3 = 0xe3, > M_APP4 = 0xe4, > M_APP5 = 0xe5, > M_APP6 = 0xe6, > M_APP7 = 0xe7, > M_APP8 = 0xe8, > M_APP9 = 0xe9, > M_APP10 = 0xea, > M_APP11 = 0xeb, > M_APP12 = 0xec, > M_APP13 = 0xed, > M_APP14 = 0xee, > M_APP15 = 0xef, > > M_JPG0 = 0xf0, > M_JPG13 = 0xfd, > M_COM = 0xfe, > > M_TEM = 0x01, > > M_ERROR = 0x100 > } JPEG_MARKER; Please use jpeg_marker_t. > typedef int jpeg_data_unit[64]; jpeg_data_unit_t > struct grub_jpeg_data > { > grub_file_t file; > grub_jmp_buf jumper; > > int image_width; > int image_height; > > grub_uint8_t *huff_value[4]; > int huff_offset[4][16]; > int huff_maxval[4][16]; > > grub_uint8_t quan_table[2][64]; > int comp_index[3][3]; > > jpeg_data_unit ydu[4]; > jpeg_data_unit crdu; > jpeg_data_unit cbdu; > > int Cr_r_tab[256], Cb_b_tab[256], Cr_g_tab[256], Cb_g_tab[256]; I do not like using uppercase for members. > int vs, hs; > > int dc_value[3]; > > int bit_mask, bit_save; > > struct grub_video_bitmap **bitmap; > }; > > > static grub_uint8_t > get_byte (struct grub_jpeg_data *data) How about jpeg_get_byte or so? Or even add grub_. I have the feeling this will clash someday. > { > grub_uint8_t r; > > if (grub_file_read (data->file, (char *) &r, 1) != 1) > grub_longjmp (data->jumper, 1); I don't like having longjmp here, please use the error handling as is used in other parts of GRUB 2. > return r; > } > > static grub_uint16_t > get_word (struct grub_jpeg_data *data) > { > grub_uint16_t r; > > if (grub_file_read (data->file, (char *) &r, 2) != 2) > grub_longjmp (data->jumper, 1); please replace the 2's by sizeof (grub_uint16_t). As for the error handling, see the previous comment. > return grub_be_to_cpu16 (r); > } > > static int > get_bit (struct grub_jpeg_data *data) > { > int ret; > > if (data->bit_mask == 0) > { > data->bit_save = get_byte (data); > if (data->bit_save == 0xFF) > { > if (get_byte (data) != 0) > { > grub_error (GRUB_ERR_BAD_FILE_TYPE, > "jpeg: invalid 0xFF in data stream"); > grub_longjmp (data->jumper, 1); jongjmp... > } > } > data->bit_mask = 0x80; > } > > ret = (data->bit_save & data->bit_mask); > data->bit_mask >>= 1; > return ret; How about "return !!ret" so you can directly use this bit in the other functions that call this one? > } > > static int > get_number (struct grub_jpeg_data *data, int num) > { > int value, i, bit; > > if (num == 0) > return 0; > > bit = get_bit (data); > value = (bit != 0); > for (i = 1; i < num; i++) > value = value * 2 + (get_bit (data) != 0); (value << 1) > if (!bit) > value += 1 - (1 << num); > > return value; > } > > static int > get_huff_code (struct grub_jpeg_data *data, int id) > { > int code, i; > > code = 0; > for (i = 0; i < 16; i++) > { > code <<= 1; > if (get_bit (data)) > code++; > if (code < data->huff_maxval[id][i]) > return data->huff_value[id][code + data->huff_offset[id][i]]; > } > grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: huffman decode fails"); > grub_longjmp (data->jumper, 1); ... > return 0; > } > > static void > decode_huff_table (struct grub_jpeg_data *data) > { > int id, ac, i, n, base, ofs; > grub_uint32_t next_marker; > grub_uint8_t count[16]; > > next_marker = data->file->offset; > next_marker += get_word (data); > > id = get_byte (data); > ac = (id >> 4); > id &= 0xF; > if (id > 1) > { > grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: too many huffman table"); > grub_longjmp (data->jumper, 1); > } How many are normally supported? Max 4, IIRC? > if (grub_file_read (data->file, (char *) &count, sizeof (count)) != > sizeof (count)) > grub_longjmp (data->jumper, 1); > > n = 0; > for (i = 0; i < 16; i++) > n += count[i]; What does this do? > id += ac * 2; > data->huff_value[id] = grub_malloc (n); > if (data->huff_value[id] == NULL) > grub_longjmp (data->jumper, 1); How about "goto fail"? or a return? > > if (grub_file_read (data->file, (char *) data->huff_value[id], n) != n) > grub_longjmp (data->jumper, 1); ... > base = 0; > ofs = 0; > for (i = 0; i < 16; i++) > { > base += count[i]; > ofs += count[i]; > > data->huff_maxval[id][i] = base; > data->huff_offset[id][i] = ofs - base; > > base <<= 1; > } > > if (data->file->offset != next_marker) > { > grub_error (GRUB_ERR_BAD_FILE_TYPE, > "jpeg: extra byte in huffman table"); > grub_longjmp (data->jumper, 1); > } > } > > static void > decode_quan_table (struct grub_jpeg_data *data) > { > int id; > grub_uint32_t next_marker; > > next_marker = data->file->offset; > next_marker += get_word (data); > > id = get_byte (data); > if (id >= 0x10) /* upper 4-bit is precision */ > { > grub_error (GRUB_ERR_BAD_FILE_TYPE, > "jpeg: only 8-bit precision is supported"); > grub_longjmp (data->jumper, 1); > } > > if (id > 1) > { > grub_error (GRUB_ERR_BAD_FILE_TYPE, > "jpeg: too many quantization table"); table -> tables > grub_longjmp (data->jumper, 1); > } > > if (grub_file_read (data->file, (char *) &data->quan_table[id], 64) != 64) > grub_longjmp (data->jumper, 1); > > if (data->file->offset != next_marker) > { > grub_error (GRUB_ERR_BAD_FILE_TYPE, > "jpeg: extra byte in quantization table"); > grub_longjmp (data->jumper, 1); > } > } > > static void > decode_sof (struct grub_jpeg_data *data) > { > int i, cc; > grub_uint32_t next_marker; > > next_marker = data->file->offset; > next_marker += get_word (data); > > if (get_byte (data) != 8) > { > grub_error (GRUB_ERR_BAD_FILE_TYPE, > "jpeg: only 8-bit precision is supported"); > grub_longjmp (data->jumper, 1); > } > > data->image_height = get_word (data); > data->image_width = get_word (data); > > if ((!data->image_height) || (!data->image_width)) > { > grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid image size"); > grub_longjmp (data->jumper, 1); > } > > cc = get_byte (data); > if (cc != 3) > { > grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: component count must be 3"); > grub_longjmp (data->jumper, 1); > } > > for (i = 0; i < cc; i++) > { > int id, ss; > > id = get_byte (data) - 1; > if ((id < 0) || (id >= 3)) > { > grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index"); > grub_longjmp (data->jumper, 1); > } > ss = get_byte (data); > if (!id) > { > data->vs = ss & 0xF; > data->hs = ss >> 4; What's ss, vs, hs? > if ((data->vs > 2) || (data->hs > 2)) > { > grub_error (GRUB_ERR_BAD_FILE_TYPE, > "jpeg: sampling method nor supported"); > grub_longjmp (data->jumper, 1); > } > } > else if (ss != 0x11) Magic value... Can you use a macro for this or so? I do not know what this means. > { > grub_error (GRUB_ERR_BAD_FILE_TYPE, > "jpeg: sampling method nor supported"); > grub_longjmp (data->jumper, 1); > } > data->comp_index[id][0] = get_byte (data); > } > > if (data->file->offset != next_marker) > { > grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sof"); > grub_longjmp (data->jumper, 1); > } > } > > #define DCTSIZE 8 > > #define CONST_BITS 8 > #define PASS1_BITS 2 > > #define FIX_1_082392200 ((int) 277) /* FIX(1.082392200) */ > #define FIX_1_414213562 ((int) 362) /* FIX(1.414213562) */ > #define FIX_1_847759065 ((int) 473) /* FIX(1.847759065) */ > #define FIX_2_613125930 ((int) 669) /* FIX(2.613125930) */ > > #define ONE ((long) 1) > #define DESCALE(x,n) (((x) + (ONE << ((n)-1))) >> (n)) > > #define MULTIPLY(var,const) DESCALE((var) * (const), CONST_BITS) > > static const grub_uint8_t natural_order[64] = { > 0, 1, 8, 16, 9, 2, 3, 10, > 17, 24, 32, 25, 18, 11, 4, 5, > 12, 19, 26, 33, 40, 48, 41, 34, > 27, 20, 13, 6, 7, 14, 21, 28, > 35, 42, 49, 56, 57, 50, 43, 36, > 29, 22, 15, 23, 30, 37, 44, 51, > 58, 59, 52, 45, 38, 31, 39, 46, > 53, 60, 61, 54, 47, 55, 62, 63 > }; > > static const int aanscales[64] = { > /* precomputed values scaled up by 14 bits */ > 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, > 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, > 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, > 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, > 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, > 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, > 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, > 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 > }; > > static void > idct_transform (jpeg_data_unit du) > { > int *pd; > int ctr; > int tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; > int tmp10, tmp11, tmp12, tmp13; > int z5, z10, z11, z12, z13; > > /* Pass 1: process columns from input, store into work array. */ > > pd = du; > for (ctr = DCTSIZE; ctr > 0; ctr--) > { > if ((pd[DCTSIZE * 1] | pd[DCTSIZE * 2] | pd[DCTSIZE * 3] | > pd[DCTSIZE * 4] | pd[DCTSIZE * 5] | pd[DCTSIZE * 6] | > pd[DCTSIZE * 7]) == 0) > { > pd[DCTSIZE * 1] = pd[DCTSIZE * 2] > = pd[DCTSIZE * 3] = pd[DCTSIZE * 4] > = pd[DCTSIZE * 5] = pd[DCTSIZE * 6] > = pd[DCTSIZE * 7] = pd[DCTSIZE * 0]; > > pd++; /* advance pointers to next column */ > continue; > } > > /* Even part */ > > tmp0 = pd[DCTSIZE * 0]; > tmp1 = pd[DCTSIZE * 2]; > tmp2 = pd[DCTSIZE * 4]; > tmp3 = pd[DCTSIZE * 6]; > > tmp10 = tmp0 + tmp2; /* phase 3 */ > tmp11 = tmp0 - tmp2; > > tmp13 = tmp1 + tmp3; /* phases 5-3 */ > tmp12 = MULTIPLY (tmp1 - tmp3, FIX_1_414213562) - tmp13; /* 2*c4 */ > > tmp0 = tmp10 + tmp13; /* phase 2 */ > tmp3 = tmp10 - tmp13; > tmp1 = tmp11 + tmp12; > tmp2 = tmp11 - tmp12; > > /* Odd part */ > > tmp4 = pd[DCTSIZE * 1]; > tmp5 = pd[DCTSIZE * 3]; > tmp6 = pd[DCTSIZE * 5]; > tmp7 = pd[DCTSIZE * 7]; > > z13 = tmp6 + tmp5; /* phase 6 */ > z10 = tmp6 - tmp5; > z11 = tmp4 + tmp7; > z12 = tmp4 - tmp7; > > tmp7 = z11 + z13; /* phase 5 */ > tmp11 = MULTIPLY (z11 - z13, FIX_1_414213562); /* 2*c4 */ > > z5 = MULTIPLY (z10 + z12, FIX_1_847759065); /* 2*c2 */ > tmp10 = MULTIPLY (z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */ > tmp12 = MULTIPLY (z10, -FIX_2_613125930) + z5; /* -2*(c2+c6) */ > > > tmp6 = tmp12 - tmp7; /* phase 2 */ > tmp5 = tmp11 - tmp6; > tmp4 = tmp10 + tmp5; > > pd[DCTSIZE * 0] = (int) (tmp0 + tmp7); > pd[DCTSIZE * 7] = (int) (tmp0 - tmp7); > pd[DCTSIZE * 1] = (int) (tmp1 + tmp6); > pd[DCTSIZE * 6] = (int) (tmp1 - tmp6); > pd[DCTSIZE * 2] = (int) (tmp2 + tmp5); > pd[DCTSIZE * 5] = (int) (tmp2 - tmp5); > pd[DCTSIZE * 4] = (int) (tmp3 + tmp4); > pd[DCTSIZE * 3] = (int) (tmp3 - tmp4); > > pd++; /* advance pointers to next column */ > } > > /* Pass 2: process rows from work array, store into output array. */ > /* Note that we must descale the results by a factor of 8 == 2**3, */ > /* and also undo the PASS1_BITS scaling. */ > > pd = du; > for (ctr = 0; ctr < DCTSIZE; ctr++) > { > /* Even part */ > > tmp10 = pd[0] + pd[4]; > tmp11 = pd[0] - pd[4]; > > tmp13 = pd[2] + pd[6]; > tmp12 = MULTIPLY (pd[2] - pd[6], FIX_1_414213562) - tmp13; > > tmp0 = tmp10 + tmp13; > tmp3 = tmp10 - tmp13; > tmp1 = tmp11 + tmp12; > tmp2 = tmp11 - tmp12; > > /* Odd part */ > > z13 = pd[5] + pd[3]; > z10 = pd[5] - pd[3]; > z11 = pd[1] + pd[7]; > z12 = pd[1] - pd[7]; > > tmp7 = z11 + z13; /* phase 5 */ > tmp11 = MULTIPLY (z11 - z13, FIX_1_414213562); /* 2*c4 */ > > z5 = MULTIPLY (z10 + z12, FIX_1_847759065); /* 2*c2 */ > tmp10 = MULTIPLY (z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */ > tmp12 = MULTIPLY (z10, -FIX_2_613125930) + z5; /* -2*(c2+c6) */ > > tmp6 = tmp12 - tmp7; /* phase 2 */ > tmp5 = tmp11 - tmp6; > tmp4 = tmp10 + tmp5; > > /* Final output stage: scale down by a factor of 8 and range-limit */ > > pd[0] = DESCALE (tmp0 + tmp7, PASS1_BITS + 3) + 128; > pd[7] = DESCALE (tmp0 - tmp7, PASS1_BITS + 3) + 128; > pd[1] = DESCALE (tmp1 + tmp6, PASS1_BITS + 3) + 128; > pd[6] = DESCALE (tmp1 - tmp6, PASS1_BITS + 3) + 128; > pd[2] = DESCALE (tmp2 + tmp5, PASS1_BITS + 3) + 128; > pd[5] = DESCALE (tmp2 - tmp5, PASS1_BITS + 3) + 128; > pd[4] = DESCALE (tmp3 + tmp4, PASS1_BITS + 3) + 128; > pd[3] = DESCALE (tmp3 - tmp4, PASS1_BITS + 3) + 128; > > pd += DCTSIZE; /* advance pointer to next row */ > } > > for (ctr = 0; ctr < 64; ctr++) > { > if (du[ctr] < 0) > du[ctr] = 0; > if (du[ctr] > 255) > du[ctr] = 255; > } > } > > static void > decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit du) > { > int pos, h1, h2, qt; > > grub_memset (du, 0, sizeof (jpeg_data_unit)); > > qt = data->comp_index[id][0]; > h1 = data->comp_index[id][1]; > h2 = data->comp_index[id][2]; > > data->dc_value[id] += get_number (data, get_huff_code (data, h1)); > > du[0] = > data->dc_value[id] * DESCALE ((int) data->quan_table[qt][0] * > (int) aanscales[0], 14 - 2); > pos = 1; > while (pos < 64) > { > int num, val; > > num = get_huff_code (data, h2); > if (!num) > break; > val = get_number (data, num & 0xF); > num >>= 4; > pos += num; > du[natural_order[pos]] = > val * DESCALE ((int) data->quan_table[qt][pos] * > (int) aanscales[natural_order[pos]], 14 - 2); 14 - 2? > pos++; > } > > idct_transform (du); > } > > #define SCALEBITS 16 /* speediest right-shift on some machines */ > #define ONE_HALF ((int) 1 << (SCALEBITS-1)) > #define FIX(x) ((int) ((x) * (1L<<SCALEBITS) + 0.5)) > > static void > build_color_table (struct grub_jpeg_data *data) > { > int i, x; > > for (i = 0, x = -128; i <= 255; i++, x++) > { > data->Cr_r_tab[i] = (int) (FIX (1.40200) * x + ONE_HALF) >> SCALEBITS; > data->Cb_b_tab[i] = (int) (FIX (1.77200) * x + ONE_HALF) >> SCALEBITS; > data->Cr_g_tab[i] = (-FIX (0.71414)) * x; > data->Cb_g_tab[i] = (-FIX (0.34414)) * x + ONE_HALF; > } > } > > static void > decode_sos (struct grub_jpeg_data *data) > { > int i, cc, r1, c1, nr1, nc1, vb, hb; > grub_uint8_t *ptr1; > grub_uint32_t data_offset; > > data_offset = data->file->offset; > data_offset += get_word (data); > > cc = get_byte (data); > > if (cc != 3) > { > grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: component count must be 3"); > grub_longjmp (data->jumper, 1); > } > > for (i = 0; i < cc; i++) > { > int id, ht; > > id = get_byte (data) - 1; > if ((id < 0) || (id >= 3)) > { > grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index"); > grub_longjmp (data->jumper, 1); > } > > ht = get_byte (data); > data->comp_index[id][1] = (ht >> 4); > data->comp_index[id][2] = (ht & 0xF) + 2; > } > > get_byte (data); /* skip 3 unused bytes */ > get_word (data); > > if (data->file->offset != data_offset) > { > grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sos"); > grub_longjmp (data->jumper, 1); > } > > if (grub_video_bitmap_create (data->bitmap, data->image_width, > data->image_height, > GRUB_VIDEO_BLIT_FORMAT_R8G8B8)) > grub_longjmp (data->jumper, 1); > > data->bit_mask = 0x0; > > vb = data->vs * 8; > hb = data->hs * 8; > nr1 = (data->image_height + vb - 1) / vb; > nc1 = (data->image_width + hb - 1) / hb; > > ptr1 = (*data->bitmap)->data; > for (r1 = 0; r1 < nr1; r1++, ptr1 += (vb * data->image_width - hb * nc1) * 3) > for (c1 = 0; c1 < nc1; c1++, ptr1 += hb * 3) > { > int r2, c2, nr2, nc2; > grub_uint8_t *ptr2; > > for (r2 = 0; r2 < data->vs; r2++) > for (c2 = 0; c2 < data->hs; c2++) > decode_du (data, 0, data->ydu[r2 * 2 + c2]); > > decode_du (data, 1, data->cbdu); > decode_du (data, 2, data->crdu); > > nr2 = (r1 == nr1 - 1) ? (data->image_height - r1 * vb) : vb; > nc2 = (c1 == nc1 - 1) ? (data->image_width - c1 * hb) : hb; > > ptr2 = ptr1; > for (r2 = 0; r2 < nr2; r2++, ptr2 += (data->image_width - nc2) * 3) > for (c2 = 0; c2 < nc2; c2++) > { > int i0, yy, cr, cb, dd; > > i0 = (r2 / data->vs) * 8 + (c2 / data->hs); > cr = data->crdu[i0]; > cb = data->cbdu[i0]; > > yy = data->ydu[(r2 / 8) * 2 + (c2 / 8)][(r2 % 8) * 8 + (c2 % 8)]; > > /* Red */ > dd = yy + data->Cr_r_tab[cr]; > if (dd < 0) > dd = 0; > if (dd > 255) > dd = 255; > *(ptr2++) = dd; > > /* Green */ > dd = yy + ((data->Cb_g_tab[cb] + data->Cr_g_tab[cr]) >> SCALEBITS); > if (dd < 0) > dd = 0; > if (dd > 255) > dd = 255; > *(ptr2++) = dd; > > /* Blue */ > dd = yy + data->Cb_b_tab[cb]; > if (dd < 0) > dd = 0; > if (dd > 255) > dd = 255; > *(ptr2++) = dd; Perhaps it's useful to make a separate function for colorspace conversion? (that's what's happening here, right?) Other loaders can use it too. > } > } > } > > > static grub_uint8_t > get_marker (struct grub_jpeg_data *data) > { > grub_uint8_t r; > > r = get_byte (data); > > if (r != 0xFF) /* escape character */ > { > grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid maker"); > grub_longjmp (data->jumper, 1); > } > > return get_byte (data); > } > > static void > decode_jpeg (struct grub_jpeg_data *data) > { > build_color_table (data); > > if (get_marker (data) != M_SOI) /* Start Of Image */ > { > grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid jpeg file"); > grub_longjmp (data->jumper, 1); > } > > while (1) > { > grub_uint8_t marker; > > marker = get_marker (data); > #ifdef JPEG_DEBUG > grub_printf ("jpeg marker: %x\n", marker); > #endif > switch (marker) > { > case M_DHT: /* Define Huffman Table */ > decode_huff_table (data); > break; > case M_DQT: /* Define Quantization Table */ > decode_quan_table (data); > break; > case M_SOF0: /* Start Of Frame 0 */ > decode_sof (data); > break; > case M_SOS: /* Start Of Scan */ > decode_sos (data); > break; > case M_EOI: /* End Of Image */ > return; > default: /* Skip unrecognized marker */ > { > grub_uint16_t sz; > > sz = get_word (data); > grub_file_seek (data->file, data->file->offset + sz - 2); > } > } > } > } > > static grub_err_t > grub_video_reader_jpeg (struct grub_video_bitmap **bitmap, > const char *filename) > { > grub_file_t file; > struct grub_jpeg_data *data; > > file = grub_file_open (filename); > if (!file) > return grub_errno; > > data = grub_malloc (sizeof (*data)); > if (data != NULL) > { > int i; > > grub_memset (data, 0, sizeof (*data)); > data->file = file; > data->bitmap = bitmap; > if (!grub_setjmp (data->jumper)) > decode_jpeg (data); > > for (i = 0; i < 4; i++) > if (data->huff_value[i]) > grub_free (data->huff_value[i]); > grub_free (data); > } > > if (grub_errno != GRUB_ERR_NONE) > { > grub_video_bitmap_destroy (*bitmap); > *bitmap = 0; > } > > grub_file_close (file); > return grub_errno; > } > > #if defined(JPEG_DEBUG) > static grub_err_t > grub_cmd_jpegtest (struct grub_arg_list *state __attribute__ ((unused)), > int argc, char **args) > { > struct grub_video_bitmap *bitmap = 0; > > if (argc != 1) > return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); > > grub_video_reader_jpeg (&bitmap, args[0]); > if (grub_errno != GRUB_ERR_NONE) > return grub_errno; > > grub_video_bitmap_destroy (bitmap); > > return GRUB_ERR_NONE; > } > #endif > > static struct grub_video_bitmap_reader jpg_reader = { > .extension = ".jpg", > .reader = grub_video_reader_jpeg, > .next = 0 > }; > > static struct grub_video_bitmap_reader jpeg_reader = { > .extension = ".jpeg", > .reader = grub_video_reader_jpeg, > .next = 0 > }; > > GRUB_MOD_INIT (video_reader_jpeg) > { > grub_video_bitmap_reader_register (&jpg_reader); > grub_video_bitmap_reader_register (&jpeg_reader); > #if defined(JPEG_DEBUG) > grub_register_command ("jpegtest", grub_cmd_jpegtest, > GRUB_COMMAND_FLAG_BOTH, "jpegtest FILE", > "Tests loading of JPEG bitmap.", 0); > #endif > } > > GRUB_MOD_FINI (video_reader_jpeg) > { > #if defined(JPEG_DEBUG) > grub_unregister_command ("jpegtest"); > #endif > grub_video_bitmap_reader_unregister (&jpeg_reader); > grub_video_bitmap_reader_unregister (&jpg_reader); > } > > > -- > Bean > > > _______________________________________________ > Grub-devel mailing list > Grub-devel@gnu.org > http://lists.gnu.org/mailman/listinfo/grub-devel ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] jpeg image reader 2008-01-13 18:31 ` Marco Gerards @ 2008-01-14 16:36 ` Bean 2008-01-15 11:01 ` Marco Gerards 0 siblings, 1 reply; 23+ messages in thread From: Bean @ 2008-01-14 16:36 UTC (permalink / raw) To: The development of GRUB 2 On Jan 14, 2008 2:31 AM, Marco Gerards <mgerards@xs4all.nl> wrote: > > /* > > * GRUB -- GRand Unified Bootloader > > * Copyright (C) 2008 Free Software Foundation, Inc. > > Did you write all the code yourself? yes, but i take some code segment from Independent JPEG Group's implementation, such as idct transformation and ycrcb -> rgb conversion. > > static grub_uint8_t > > get_byte (struct grub_jpeg_data *data) > > How about jpeg_get_byte or so? Or even add grub_. I have the feeling > this will clash someday. done. > > id = get_byte (data); > > ac = (id >> 4); > > id &= 0xF; > > if (id > 1) > > { > > grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: too many huffman table"); > > grub_longjmp (data->jumper, 1); > > } > > How many are normally supported? Max 4, IIRC? yes, 2 dc and 2 ac table. > > n = 0; > > for (i = 0; i < 16; i++) > > n += count[i]; > > What does this do? it sums up the number of huff codes of length 1 to 16. > > ss = get_byte (data); > > if (!id) > > { > > data->vs = ss & 0xF; > > data->hs = ss >> 4; > > What's ss, vs, hs? ss is sampling factor, vs is vertical sampling, hs is horizontal sampling, i add comment in the source. please remind me if something is left out. /* * GRUB -- GRand Unified Bootloader * Copyright (C) 2008 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRUB is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GRUB. If not, see <http://www.gnu.org/licenses/>. */ #include <grub/bitmap.h> #include <grub/types.h> #include <grub/normal.h> #include <grub/dl.h> #include <grub/mm.h> #include <grub/misc.h> #include <grub/arg.h> #include <grub/file.h> /* Uncomment following define to enable JPEG debug. */ //#define JPEG_DEBUG #define JPEG_ESC_CHAR 0xFF #define JPEG_SAMPLING_1x1 0x11 typedef enum { /* JPEG marker codes */ M_SOF0 = 0xc0, M_SOF1 = 0xc1, M_SOF2 = 0xc2, M_SOF3 = 0xc3, M_SOF5 = 0xc5, M_SOF6 = 0xc6, M_SOF7 = 0xc7, M_JPG = 0xc8, M_SOF9 = 0xc9, M_SOF10 = 0xca, M_SOF11 = 0xcb, M_SOF13 = 0xcd, M_SOF14 = 0xce, M_SOF15 = 0xcf, M_DHT = 0xc4, M_DAC = 0xcc, M_RST0 = 0xd0, M_RST1 = 0xd1, M_RST2 = 0xd2, M_RST3 = 0xd3, M_RST4 = 0xd4, M_RST5 = 0xd5, M_RST6 = 0xd6, M_RST7 = 0xd7, M_SOI = 0xd8, M_EOI = 0xd9, M_SOS = 0xda, M_DQT = 0xdb, M_DNL = 0xdc, M_DRI = 0xdd, M_DHP = 0xde, M_EXP = 0xdf, M_APP0 = 0xe0, M_APP1 = 0xe1, M_APP2 = 0xe2, M_APP3 = 0xe3, M_APP4 = 0xe4, M_APP5 = 0xe5, M_APP6 = 0xe6, M_APP7 = 0xe7, M_APP8 = 0xe8, M_APP9 = 0xe9, M_APP10 = 0xea, M_APP11 = 0xeb, M_APP12 = 0xec, M_APP13 = 0xed, M_APP14 = 0xee, M_APP15 = 0xef, M_JPG0 = 0xf0, M_JPG13 = 0xfd, M_COM = 0xfe, M_TEM = 0x01, M_ERROR = 0x100 } jpeg_marker_t; typedef int jpeg_data_unit_t[64]; struct grub_jpeg_data { grub_file_t file; struct grub_video_bitmap **bitmap; int image_width; int image_height; grub_uint8_t *huff_value[4]; int huff_offset[4][16]; int huff_maxval[4][16]; grub_uint8_t quan_table[2][64]; int comp_index[3][3]; jpeg_data_unit_t ydu[4]; jpeg_data_unit_t crdu; jpeg_data_unit_t cbdu; int crr_tab[256], cbb_tab[256], crg_tab[256], cbg_tab[256]; int vs, hs; int dc_value[3]; int bit_mask, bit_save; }; static grub_uint8_t grub_jpeg_get_byte (struct grub_jpeg_data *data) { grub_uint8_t r; r = 0; grub_file_read (data->file, (char *) &r, 1); return r; } static grub_uint16_t grub_jpeg_get_word (struct grub_jpeg_data *data) { grub_uint16_t r; r = 0; grub_file_read (data->file, (char *) &r, sizeof (grub_uint16_t)); return grub_be_to_cpu16 (r); } static int grub_jpeg_get_bit (struct grub_jpeg_data *data) { int ret; if (data->bit_mask == 0) { data->bit_save = grub_jpeg_get_byte (data); if (data->bit_save == JPEG_ESC_CHAR) { if (grub_jpeg_get_byte (data) != 0) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid 0xFF in data stream"); return 0; } } data->bit_mask = 0x80; } ret = ((data->bit_save & data->bit_mask) != 0); data->bit_mask >>= 1; return ret; } static int grub_jpeg_get_number (struct grub_jpeg_data *data, int num) { int value, i, msb; if (num == 0) return 0; msb = value = grub_jpeg_get_bit (data); for (i = 1; i < num; i++) value = (value << 1) + (grub_jpeg_get_bit (data) != 0); if (!msb) value += 1 - (1 << num); return value; } static int grub_jpeg_get_huff_code (struct grub_jpeg_data *data, int id) { int code, i; code = 0; for (i = 0; i < 16; i++) { code <<= 1; if (grub_jpeg_get_bit (data)) code++; if (code < data->huff_maxval[id][i]) return data->huff_value[id][code + data->huff_offset[id][i]]; } grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: huffman decode fails"); return 0; } static grub_err_t grub_jpeg_decode_huff_table (struct grub_jpeg_data *data) { int id, ac, i, n, base, ofs; grub_uint32_t next_marker; grub_uint8_t count[16]; next_marker = data->file->offset; next_marker += grub_jpeg_get_word (data); id = grub_jpeg_get_byte (data); ac = (id >> 4); id &= 0xF; if (id > 1) return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: too many huffman tables"); if (grub_file_read (data->file, (char *) &count, sizeof (count)) != sizeof (count)) return grub_errno; n = 0; for (i = 0; i < 16; i++) n += count[i]; id += ac * 2; data->huff_value[id] = grub_malloc (n); if (grub_errno) return grub_errno; if (grub_file_read (data->file, (char *) data->huff_value[id], n) != n) return grub_errno; base = 0; ofs = 0; for (i = 0; i < 16; i++) { base += count[i]; ofs += count[i]; data->huff_maxval[id][i] = base; data->huff_offset[id][i] = ofs - base; base <<= 1; } if (data->file->offset != next_marker) grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in huffman table"); return grub_errno; } static grub_err_t grub_jpeg_decode_quan_table (struct grub_jpeg_data *data) { int id; grub_uint32_t next_marker; next_marker = data->file->offset; next_marker += grub_jpeg_get_word (data); id = grub_jpeg_get_byte (data); if (id >= 0x10) /* upper 4-bit is precision */ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: only 8-bit precision is supported"); if (id > 1) return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: too many quantization tables"); if (grub_file_read (data->file, (char *) &data->quan_table[id], 64) != 64) return grub_errno; if (data->file->offset != next_marker) grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in quantization table"); return grub_errno; } static grub_err_t grub_jpeg_decode_sof (struct grub_jpeg_data *data) { int i, cc; grub_uint32_t next_marker; next_marker = data->file->offset; next_marker += grub_jpeg_get_word (data); if (grub_jpeg_get_byte (data) != 8) return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: only 8-bit precision is supported"); data->image_height = grub_jpeg_get_word (data); data->image_width = grub_jpeg_get_word (data); if ((!data->image_height) || (!data->image_width)) return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid image size"); cc = grub_jpeg_get_byte (data); if (cc != 3) return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: component count must be 3"); for (i = 0; i < cc; i++) { int id, ss; id = grub_jpeg_get_byte (data) - 1; if ((id < 0) || (id >= 3)) return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index"); ss = grub_jpeg_get_byte (data); /* sampling factor */ if (!id) { data->vs = ss & 0xF; /* vertical sampling */ data->hs = ss >> 4; /* horizontal sampling */ if ((data->vs > 2) || (data->hs > 2)) return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: sampling method nor supported"); } else if (ss != JPEG_SAMPLING_1x1) return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: sampling method nor supported"); data->comp_index[id][0] = grub_jpeg_get_byte (data); } if (data->file->offset != next_marker) grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sof"); return grub_errno; } #define DCTSIZE 8 #define CONST_BITS 8 #define PASS1_BITS 2 #define AANSCONST_BITS 14 #define IFAST_SCALE_BITS 2 #define FIX_1_082392200 ((int) 277) /* FIX(1.082392200) */ #define FIX_1_414213562 ((int) 362) /* FIX(1.414213562) */ #define FIX_1_847759065 ((int) 473) /* FIX(1.847759065) */ #define FIX_2_613125930 ((int) 669) /* FIX(2.613125930) */ #define ONE ((long) 1) #define DESCALE(x,n) (((x) + (ONE << ((n)-1))) >> (n)) #define MULTIPLY(var,const) DESCALE((var) * (const), CONST_BITS) static const grub_uint8_t natural_order[64] = { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 }; static const int aanscales[64] = { /* precomputed values scaled up by 14 bits */ 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 }; static void grub_jpeg_idct_transform (jpeg_data_unit_t du) { int *pd; int ctr; int tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; int tmp10, tmp11, tmp12, tmp13; int z5, z10, z11, z12, z13; /* Pass 1: process columns from input, store into work array. */ pd = du; for (ctr = DCTSIZE; ctr > 0; ctr--) { if ((pd[DCTSIZE * 1] | pd[DCTSIZE * 2] | pd[DCTSIZE * 3] | pd[DCTSIZE * 4] | pd[DCTSIZE * 5] | pd[DCTSIZE * 6] | pd[DCTSIZE * 7]) == 0) { pd[DCTSIZE * 1] = pd[DCTSIZE * 2] = pd[DCTSIZE * 3] = pd[DCTSIZE * 4] = pd[DCTSIZE * 5] = pd[DCTSIZE * 6] = pd[DCTSIZE * 7] = pd[DCTSIZE * 0]; pd++; /* advance pointers to next column */ continue; } /* Even part */ tmp0 = pd[DCTSIZE * 0]; tmp1 = pd[DCTSIZE * 2]; tmp2 = pd[DCTSIZE * 4]; tmp3 = pd[DCTSIZE * 6]; tmp10 = tmp0 + tmp2; /* phase 3 */ tmp11 = tmp0 - tmp2; tmp13 = tmp1 + tmp3; /* phases 5-3 */ tmp12 = MULTIPLY (tmp1 - tmp3, FIX_1_414213562) - tmp13; /* 2*c4 */ tmp0 = tmp10 + tmp13; /* phase 2 */ tmp3 = tmp10 - tmp13; tmp1 = tmp11 + tmp12; tmp2 = tmp11 - tmp12; /* Odd part */ tmp4 = pd[DCTSIZE * 1]; tmp5 = pd[DCTSIZE * 3]; tmp6 = pd[DCTSIZE * 5]; tmp7 = pd[DCTSIZE * 7]; z13 = tmp6 + tmp5; /* phase 6 */ z10 = tmp6 - tmp5; z11 = tmp4 + tmp7; z12 = tmp4 - tmp7; tmp7 = z11 + z13; /* phase 5 */ tmp11 = MULTIPLY (z11 - z13, FIX_1_414213562); /* 2*c4 */ z5 = MULTIPLY (z10 + z12, FIX_1_847759065); /* 2*c2 */ tmp10 = MULTIPLY (z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */ tmp12 = MULTIPLY (z10, -FIX_2_613125930) + z5; /* -2*(c2+c6) */ tmp6 = tmp12 - tmp7; /* phase 2 */ tmp5 = tmp11 - tmp6; tmp4 = tmp10 + tmp5; pd[DCTSIZE * 0] = (int) (tmp0 + tmp7); pd[DCTSIZE * 7] = (int) (tmp0 - tmp7); pd[DCTSIZE * 1] = (int) (tmp1 + tmp6); pd[DCTSIZE * 6] = (int) (tmp1 - tmp6); pd[DCTSIZE * 2] = (int) (tmp2 + tmp5); pd[DCTSIZE * 5] = (int) (tmp2 - tmp5); pd[DCTSIZE * 4] = (int) (tmp3 + tmp4); pd[DCTSIZE * 3] = (int) (tmp3 - tmp4); pd++; /* advance pointers to next column */ } /* Pass 2: process rows from work array, store into output array. */ /* Note that we must descale the results by a factor of 8 == 2**3, */ /* and also undo the PASS1_BITS scaling. */ pd = du; for (ctr = 0; ctr < DCTSIZE; ctr++) { /* Even part */ tmp10 = pd[0] + pd[4]; tmp11 = pd[0] - pd[4]; tmp13 = pd[2] + pd[6]; tmp12 = MULTIPLY (pd[2] - pd[6], FIX_1_414213562) - tmp13; tmp0 = tmp10 + tmp13; tmp3 = tmp10 - tmp13; tmp1 = tmp11 + tmp12; tmp2 = tmp11 - tmp12; /* Odd part */ z13 = pd[5] + pd[3]; z10 = pd[5] - pd[3]; z11 = pd[1] + pd[7]; z12 = pd[1] - pd[7]; tmp7 = z11 + z13; /* phase 5 */ tmp11 = MULTIPLY (z11 - z13, FIX_1_414213562); /* 2*c4 */ z5 = MULTIPLY (z10 + z12, FIX_1_847759065); /* 2*c2 */ tmp10 = MULTIPLY (z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */ tmp12 = MULTIPLY (z10, -FIX_2_613125930) + z5; /* -2*(c2+c6) */ tmp6 = tmp12 - tmp7; /* phase 2 */ tmp5 = tmp11 - tmp6; tmp4 = tmp10 + tmp5; /* Final output stage: scale down by a factor of 8 and range-limit */ pd[0] = DESCALE (tmp0 + tmp7, PASS1_BITS + 3) + 128; pd[7] = DESCALE (tmp0 - tmp7, PASS1_BITS + 3) + 128; pd[1] = DESCALE (tmp1 + tmp6, PASS1_BITS + 3) + 128; pd[6] = DESCALE (tmp1 - tmp6, PASS1_BITS + 3) + 128; pd[2] = DESCALE (tmp2 + tmp5, PASS1_BITS + 3) + 128; pd[5] = DESCALE (tmp2 - tmp5, PASS1_BITS + 3) + 128; pd[4] = DESCALE (tmp3 + tmp4, PASS1_BITS + 3) + 128; pd[3] = DESCALE (tmp3 - tmp4, PASS1_BITS + 3) + 128; pd += DCTSIZE; /* advance pointer to next row */ } for (ctr = 0; ctr < 64; ctr++) { if (du[ctr] < 0) du[ctr] = 0; if (du[ctr] > 255) du[ctr] = 255; } } static void grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) { int pos, h1, h2, qt; grub_memset (du, 0, sizeof (jpeg_data_unit_t)); qt = data->comp_index[id][0]; h1 = data->comp_index[id][1]; h2 = data->comp_index[id][2]; data->dc_value[id] += grub_jpeg_get_number (data, grub_jpeg_get_huff_code (data, h1)); du[0] = data->dc_value[id] * DESCALE ((int) data->quan_table[qt][0] * (int) aanscales[0], AANSCONST_BITS - IFAST_SCALE_BITS); pos = 1; while (pos < 64) { int num, val; num = grub_jpeg_get_huff_code (data, h2); if (!num) break; val = grub_jpeg_get_number (data, num & 0xF); num >>= 4; pos += num; du[natural_order[pos]] = val * DESCALE ((int) data->quan_table[qt][pos] * (int) aanscales[natural_order[pos]], 14 - 2); pos++; } grub_jpeg_idct_transform (du); } #define SCALEBITS 16 /* speediest right-shift on some machines */ #define ONE_HALF ((int) 1 << (SCALEBITS-1)) #define FIX(x) ((int) ((x) * (1L<<SCALEBITS) + 0.5)) static void grub_jpeg_build_color_table (struct grub_jpeg_data *data) { int i, x; for (i = 0, x = -128; i <= 255; i++, x++) { data->crr_tab[i] = (int) (FIX (1.40200) * x + ONE_HALF) >> SCALEBITS; data->cbb_tab[i] = (int) (FIX (1.77200) * x + ONE_HALF) >> SCALEBITS; data->crg_tab[i] = (-FIX (0.71414)) * x; data->cbg_tab[i] = (-FIX (0.34414)) * x + ONE_HALF; } } static void grub_jpeg_ycrcb_to_rgb (struct grub_jpeg_data *data, int yy, int cr, int cb, grub_uint8_t * rgb) { int dd; /* Red */ dd = yy + data->crr_tab[cr]; if (dd < 0) dd = 0; if (dd > 255) dd = 255; *(rgb++) = dd; /* Green */ dd = yy + ((data->cbg_tab[cb] + data->crg_tab[cr]) >> SCALEBITS); if (dd < 0) dd = 0; if (dd > 255) dd = 255; *(rgb++) = dd; /* Blue */ dd = yy + data->cbb_tab[cb]; if (dd < 0) dd = 0; if (dd > 255) dd = 255; *(rgb++) = dd; } static grub_err_t grub_jpeg_decode_sos (struct grub_jpeg_data *data) { int i, cc, r1, c1, nr1, nc1, vb, hb; grub_uint8_t *ptr1; grub_uint32_t data_offset; data_offset = data->file->offset; data_offset += grub_jpeg_get_word (data); cc = grub_jpeg_get_byte (data); if (cc != 3) return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: component count must be 3"); for (i = 0; i < cc; i++) { int id, ht; id = grub_jpeg_get_byte (data) - 1; if ((id < 0) || (id >= 3)) return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index"); ht = grub_jpeg_get_byte (data); data->comp_index[id][1] = (ht >> 4); data->comp_index[id][2] = (ht & 0xF) + 2; } grub_jpeg_get_byte (data); /* skip 3 unused bytes */ grub_jpeg_get_word (data); if (data->file->offset != data_offset) return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sos"); if (grub_video_bitmap_create (data->bitmap, data->image_width, data->image_height, GRUB_VIDEO_BLIT_FORMAT_R8G8B8)) return grub_errno; data->bit_mask = 0x0; vb = data->vs * 8; hb = data->hs * 8; nr1 = (data->image_height + vb - 1) / vb; nc1 = (data->image_width + hb - 1) / hb; ptr1 = (*data->bitmap)->data; for (r1 = 0; r1 < nr1; r1++, ptr1 += (vb * data->image_width - hb * nc1) * 3) for (c1 = 0; c1 < nc1; c1++, ptr1 += hb * 3) { int r2, c2, nr2, nc2; grub_uint8_t *ptr2; for (r2 = 0; r2 < data->vs; r2++) for (c2 = 0; c2 < data->hs; c2++) grub_jpeg_decode_du (data, 0, data->ydu[r2 * 2 + c2]); grub_jpeg_decode_du (data, 1, data->cbdu); grub_jpeg_decode_du (data, 2, data->crdu); if (grub_errno) return grub_errno; nr2 = (r1 == nr1 - 1) ? (data->image_height - r1 * vb) : vb; nc2 = (c1 == nc1 - 1) ? (data->image_width - c1 * hb) : hb; ptr2 = ptr1; for (r2 = 0; r2 < nr2; r2++, ptr2 += (data->image_width - nc2) * 3) for (c2 = 0; c2 < nc2; c2++, ptr2 += 3) { int i0, yy, cr, cb; i0 = (r2 / data->vs) * 8 + (c2 / data->hs); cr = data->crdu[i0]; cb = data->cbdu[i0]; yy = data->ydu[(r2 / 8) * 2 + (c2 / 8)][(r2 % 8) * 8 + (c2 % 8)]; grub_jpeg_ycrcb_to_rgb (data, yy, cr, cb, ptr2); } } return grub_errno; } static grub_uint8_t grub_jpeg_get_marker (struct grub_jpeg_data *data) { grub_uint8_t r; r = grub_jpeg_get_byte (data); if (r != JPEG_ESC_CHAR) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid maker"); return 0; } return grub_jpeg_get_byte (data); } static grub_err_t grub_jpeg_decode_jpeg (struct grub_jpeg_data *data) { grub_jpeg_build_color_table (data); if (grub_jpeg_get_marker (data) != M_SOI) /* Start Of Image */ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid jpeg file"); while (grub_errno == 0) { grub_uint8_t marker; marker = grub_jpeg_get_marker (data); if (grub_errno) break; #ifdef JPEG_DEBUG grub_printf ("jpeg marker: %x\n", marker); #endif switch (marker) { case M_DHT: /* Define Huffman Table */ grub_jpeg_decode_huff_table (data); break; case M_DQT: /* Define Quantization Table */ grub_jpeg_decode_quan_table (data); break; case M_SOF0: /* Start Of Frame 0 */ grub_jpeg_decode_sof (data); break; case M_SOS: /* Start Of Scan */ grub_jpeg_decode_sos (data); break; case M_EOI: /* End Of Image */ return grub_errno; default: /* Skip unrecognized marker */ { grub_uint16_t sz; sz = grub_jpeg_get_word (data); if (grub_errno) return (grub_errno); grub_file_seek (data->file, data->file->offset + sz - 2); } } } return grub_errno; } static grub_err_t grub_video_reader_jpeg (struct grub_video_bitmap **bitmap, const char *filename) { grub_file_t file; struct grub_jpeg_data *data; file = grub_file_open (filename); if (!file) return grub_errno; data = grub_malloc (sizeof (*data)); if (data != NULL) { int i; grub_memset (data, 0, sizeof (*data)); data->file = file; data->bitmap = bitmap; grub_jpeg_decode_jpeg (data); for (i = 0; i < 4; i++) if (data->huff_value[i]) grub_free (data->huff_value[i]); grub_free (data); } if (grub_errno != GRUB_ERR_NONE) { grub_video_bitmap_destroy (*bitmap); *bitmap = 0; } grub_file_close (file); return grub_errno; } #if defined(JPEG_DEBUG) static grub_err_t grub_cmd_jpegtest (struct grub_arg_list *state __attribute__ ((unused)), int argc, char **args) { struct grub_video_bitmap *bitmap = 0; if (argc != 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); grub_video_reader_jpeg (&bitmap, args[0]); if (grub_errno != GRUB_ERR_NONE) return grub_errno; grub_video_bitmap_destroy (bitmap); return GRUB_ERR_NONE; } #endif static struct grub_video_bitmap_reader jpg_reader = { .extension = ".jpg", .reader = grub_video_reader_jpeg, .next = 0 }; static struct grub_video_bitmap_reader jpeg_reader = { .extension = ".jpeg", .reader = grub_video_reader_jpeg, .next = 0 }; GRUB_MOD_INIT (video_reader_jpeg) { grub_video_bitmap_reader_register (&jpg_reader); grub_video_bitmap_reader_register (&jpeg_reader); #if defined(JPEG_DEBUG) grub_register_command ("jpegtest", grub_cmd_jpegtest, GRUB_COMMAND_FLAG_BOTH, "jpegtest FILE", "Tests loading of JPEG bitmap.", 0); #endif } GRUB_MOD_FINI (video_reader_jpeg) { #if defined(JPEG_DEBUG) grub_unregister_command ("jpegtest"); #endif grub_video_bitmap_reader_unregister (&jpeg_reader); grub_video_bitmap_reader_unregister (&jpg_reader); } -- Bean ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] jpeg image reader 2008-01-14 16:36 ` Bean @ 2008-01-15 11:01 ` Marco Gerards 2008-01-15 11:52 ` Robert Millan 2008-01-15 13:54 ` Bean 0 siblings, 2 replies; 23+ messages in thread From: Marco Gerards @ 2008-01-15 11:01 UTC (permalink / raw) To: The development of GRUB 2 Bean <bean123ch@gmail.com> writes: > On Jan 14, 2008 2:31 AM, Marco Gerards <mgerards@xs4all.nl> wrote: >> > /* >> > * GRUB -- GRand Unified Bootloader >> > * Copyright (C) 2008 Free Software Foundation, Inc. >> >> Did you write all the code yourself? > > yes, but i take some code segment from Independent JPEG Group's > implementation, such as idct transformation and ycrcb -> rgb > conversion. I do not think these algorithms can be copyrighted and are in the public domain? Can you check this? Colorspace convertion can be easily done. I might even have some self written code for this. As for the IDCT, I could do that too, if it is problematic? > please remind me if something is left out. I don't see anything you missed. Please see this last comment below. > static grub_err_t > grub_jpeg_decode_sof (struct grub_jpeg_data *data) > { > int i, cc; > grub_uint32_t next_marker; > > next_marker = data->file->offset; > next_marker += grub_jpeg_get_word (data); > > if (grub_jpeg_get_byte (data) != 8) > return grub_error (GRUB_ERR_BAD_FILE_TYPE, > "jpeg: only 8-bit precision is supported"); > > data->image_height = grub_jpeg_get_word (data); > data->image_width = grub_jpeg_get_word (data); > > if ((!data->image_height) || (!data->image_width)) > return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid image size"); > > cc = grub_jpeg_get_byte (data); > if (cc != 3) > return grub_error (GRUB_ERR_BAD_FILE_TYPE, > "jpeg: component count must be 3"); > > for (i = 0; i < cc; i++) > { > int id, ss; > > id = grub_jpeg_get_byte (data) - 1; > if ((id < 0) || (id >= 3)) > return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index"); > > ss = grub_jpeg_get_byte (data); /* sampling factor */ > if (!id) > { > data->vs = ss & 0xF; /* vertical sampling */ > data->hs = ss >> 4; /* horizontal sampling */ Please use correct interpunction. -- Marco ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] jpeg image reader 2008-01-15 11:01 ` Marco Gerards @ 2008-01-15 11:52 ` Robert Millan 2008-01-15 12:21 ` Marco Gerards 2008-01-15 13:54 ` Bean 1 sibling, 1 reply; 23+ messages in thread From: Robert Millan @ 2008-01-15 11:52 UTC (permalink / raw) To: The development of GRUB 2 On Tue, Jan 15, 2008 at 12:01:47PM +0100, Marco Gerards wrote: > Bean <bean123ch@gmail.com> writes: > > > On Jan 14, 2008 2:31 AM, Marco Gerards <mgerards@xs4all.nl> wrote: > >> > /* > >> > * GRUB -- GRand Unified Bootloader > >> > * Copyright (C) 2008 Free Software Foundation, Inc. > >> > >> Did you write all the code yourself? > > > > yes, but i take some code segment from Independent JPEG Group's > > implementation, such as idct transformation and ycrcb -> rgb > > conversion. > > I do not think these algorithms can be copyrighted and are in the > public domain? Can you check this? Only actual code can be copyrighted. Algorithms can only be patented. Copyright expires into public domain, but this is only theoretical since they reform copyright law every 20 years to extend it. I think only patents actually expire in practice. -- Robert Millan <GPLv2> I know my rights; I want my phone call! <DRM> What use is a phone call, if you are unable to speak? (as seen on /.) ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] jpeg image reader 2008-01-15 11:52 ` Robert Millan @ 2008-01-15 12:21 ` Marco Gerards 2008-01-15 12:29 ` Robert Millan 0 siblings, 1 reply; 23+ messages in thread From: Marco Gerards @ 2008-01-15 12:21 UTC (permalink / raw) To: The development of GRUB 2 Robert Millan <rmh@aybabtu.com> writes: > On Tue, Jan 15, 2008 at 12:01:47PM +0100, Marco Gerards wrote: >> Bean <bean123ch@gmail.com> writes: >> >> > On Jan 14, 2008 2:31 AM, Marco Gerards <mgerards@xs4all.nl> wrote: >> >> > /* >> >> > * GRUB -- GRand Unified Bootloader >> >> > * Copyright (C) 2008 Free Software Foundation, Inc. >> >> >> >> Did you write all the code yourself? >> > >> > yes, but i take some code segment from Independent JPEG Group's >> > implementation, such as idct transformation and ycrcb -> rgb >> > conversion. >> >> I do not think these algorithms can be copyrighted and are in the >> public domain? Can you check this? > > Only actual code can be copyrighted. Algorithms can only be patented. > > Copyright expires into public domain, but this is only theoretical since > they reform copyright law every 20 years to extend it. > > I think only patents actually expire in practice. What I meant was, that the code Bean used is public domain already. AFAIK that's not uncommon for reference implementations. OTOH, color space convertion is trivial, IMO. In these cases you cannot claim copyright, I think? I just do not know the official definition of trivial and if this is true in any case? -- Marco ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] jpeg image reader 2008-01-15 12:21 ` Marco Gerards @ 2008-01-15 12:29 ` Robert Millan 2008-01-15 12:46 ` Marco Gerards 0 siblings, 1 reply; 23+ messages in thread From: Robert Millan @ 2008-01-15 12:29 UTC (permalink / raw) To: The development of GRUB 2 On Tue, Jan 15, 2008 at 01:21:04PM +0100, Marco Gerards wrote: > >> > >> I do not think these algorithms can be copyrighted and are in the > >> public domain? Can you check this? > > > > Only actual code can be copyrighted. Algorithms can only be patented. > > > > Copyright expires into public domain, but this is only theoretical since > > they reform copyright law every 20 years to extend it. > > > > I think only patents actually expire in practice. > > What I meant was, that the code Bean used is public domain already. > AFAIK that's not uncommon for reference implementations. It shouldn't be. I wouldn't be too sure though. -- Robert Millan <GPLv2> I know my rights; I want my phone call! <DRM> What use is a phone call, if you are unable to speak? (as seen on /.) ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] jpeg image reader 2008-01-15 12:29 ` Robert Millan @ 2008-01-15 12:46 ` Marco Gerards 2008-01-15 13:36 ` Bean 0 siblings, 1 reply; 23+ messages in thread From: Marco Gerards @ 2008-01-15 12:46 UTC (permalink / raw) To: The development of GRUB 2 Robert Millan <rmh@aybabtu.com> writes: > On Tue, Jan 15, 2008 at 01:21:04PM +0100, Marco Gerards wrote: >> >> >> >> I do not think these algorithms can be copyrighted and are in the >> >> public domain? Can you check this? >> > >> > Only actual code can be copyrighted. Algorithms can only be patented. >> > >> > Copyright expires into public domain, but this is only theoretical since >> > they reform copyright law every 20 years to extend it. >> > >> > I think only patents actually expire in practice. >> >> What I meant was, that the code Bean used is public domain already. >> AFAIK that's not uncommon for reference implementations. > > It shouldn't be. I wouldn't be too sure though. Bean will know :-) -- Marco ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] jpeg image reader 2008-01-15 12:46 ` Marco Gerards @ 2008-01-15 13:36 ` Bean 2008-01-15 14:25 ` Marco Gerards 0 siblings, 1 reply; 23+ messages in thread From: Bean @ 2008-01-15 13:36 UTC (permalink / raw) To: The development of GRUB 2 On Jan 15, 2008 8:46 PM, Marco Gerards <mgerards@xs4all.nl> wrote: > Robert Millan <rmh@aybabtu.com> writes: > > > On Tue, Jan 15, 2008 at 01:21:04PM +0100, Marco Gerards wrote: > >> >> > >> >> I do not think these algorithms can be copyrighted and are in the > >> >> public domain? Can you check this? > >> > > >> > Only actual code can be copyrighted. Algorithms can only be patented. > >> > > >> > Copyright expires into public domain, but this is only theoretical since > >> > they reform copyright law every 20 years to extend it. > >> > > >> > I think only patents actually expire in practice. > >> > >> What I meant was, that the code Bean used is public domain already. > >> AFAIK that's not uncommon for reference implementations. > > > > It shouldn't be. I wouldn't be too sure though. > > Bean will know :-) I think copyright should not be the problem, the IJG's version can practically be used in anyway you wanted. -- Bean ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] jpeg image reader 2008-01-15 13:36 ` Bean @ 2008-01-15 14:25 ` Marco Gerards 0 siblings, 0 replies; 23+ messages in thread From: Marco Gerards @ 2008-01-15 14:25 UTC (permalink / raw) To: The development of GRUB 2 Bean <bean123ch@gmail.com> writes: > On Jan 15, 2008 8:46 PM, Marco Gerards <mgerards@xs4all.nl> wrote: >> Robert Millan <rmh@aybabtu.com> writes: >> >> > On Tue, Jan 15, 2008 at 01:21:04PM +0100, Marco Gerards wrote: >> >> >> >> >> >> I do not think these algorithms can be copyrighted and are in the >> >> >> public domain? Can you check this? >> >> > >> >> > Only actual code can be copyrighted. Algorithms can only be patented. >> >> > >> >> > Copyright expires into public domain, but this is only theoretical since >> >> > they reform copyright law every 20 years to extend it. >> >> > >> >> > I think only patents actually expire in practice. >> >> >> >> What I meant was, that the code Bean used is public domain already. >> >> AFAIK that's not uncommon for reference implementations. >> > >> > It shouldn't be. I wouldn't be too sure though. >> >> Bean will know :-) > > I think copyright should not be the problem, the IJG's version can > practically be used in anyway you wanted. What's the copyright statement or is it public domain? Can you point me to the actual license or statement? -- Marco ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] jpeg image reader 2008-01-15 11:01 ` Marco Gerards 2008-01-15 11:52 ` Robert Millan @ 2008-01-15 13:54 ` Bean 2008-01-15 14:27 ` Marco Gerards 1 sibling, 1 reply; 23+ messages in thread From: Bean @ 2008-01-15 13:54 UTC (permalink / raw) To: The development of GRUB 2 On Jan 15, 2008 7:01 PM, Marco Gerards <mgerards@xs4all.nl> wrote: > > static grub_err_t > > grub_jpeg_decode_sof (struct grub_jpeg_data *data) > > { > > int i, cc; > > grub_uint32_t next_marker; > > > > next_marker = data->file->offset; > > next_marker += grub_jpeg_get_word (data); > > > > if (grub_jpeg_get_byte (data) != 8) > > return grub_error (GRUB_ERR_BAD_FILE_TYPE, > > "jpeg: only 8-bit precision is supported"); > > > > data->image_height = grub_jpeg_get_word (data); > > data->image_width = grub_jpeg_get_word (data); > > > > if ((!data->image_height) || (!data->image_width)) > > return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid image size"); > > > > cc = grub_jpeg_get_byte (data); > > if (cc != 3) > > return grub_error (GRUB_ERR_BAD_FILE_TYPE, > > "jpeg: component count must be 3"); > > > > for (i = 0; i < cc; i++) > > { > > int id, ss; > > > > id = grub_jpeg_get_byte (data) - 1; > > if ((id < 0) || (id >= 3)) > > return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index"); > > > > ss = grub_jpeg_get_byte (data); /* sampling factor */ > > if (!id) > > { > > data->vs = ss & 0xF; /* vertical sampling */ > > data->hs = ss >> 4; /* horizontal sampling */ > > Please use correct interpunction. I'm sorry, what do you mean by correct interpunction ? -- Bean ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] jpeg image reader 2008-01-15 13:54 ` Bean @ 2008-01-15 14:27 ` Marco Gerards 2008-01-15 14:36 ` Bean 0 siblings, 1 reply; 23+ messages in thread From: Marco Gerards @ 2008-01-15 14:27 UTC (permalink / raw) To: The development of GRUB 2 Bean <bean123ch@gmail.com> writes: [...] >> > for (i = 0; i < cc; i++) >> > { >> > int id, ss; >> > >> > id = grub_jpeg_get_byte (data) - 1; >> > if ((id < 0) || (id >= 3)) >> > return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index"); >> > >> > ss = grub_jpeg_get_byte (data); /* sampling factor */ >> > if (!id) >> > { >> > data->vs = ss & 0xF; /* vertical sampling */ >> > data->hs = ss >> 4; /* horizontal sampling */ >> >> Please use correct interpunction. > > I'm sorry, what do you mean by correct interpunction ? That I prefer: /* vertical sampling */ -> /* Vertical sampling. */ Same for the other two lines. With this change, only the legal question remains. -- Marco ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] jpeg image reader 2008-01-15 14:27 ` Marco Gerards @ 2008-01-15 14:36 ` Bean 2008-01-15 16:01 ` Marco Gerards 0 siblings, 1 reply; 23+ messages in thread From: Bean @ 2008-01-15 14:36 UTC (permalink / raw) To: The development of GRUB 2 On Jan 15, 2008 10:27 PM, Marco Gerards <mgerards@xs4all.nl> wrote: > Bean <bean123ch@gmail.com> writes: > > > [...] > > >> > for (i = 0; i < cc; i++) > >> > { > >> > int id, ss; > >> > > >> > id = grub_jpeg_get_byte (data) - 1; > >> > if ((id < 0) || (id >= 3)) > >> > return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index"); > >> > > >> > ss = grub_jpeg_get_byte (data); /* sampling factor */ > >> > if (!id) > >> > { > >> > data->vs = ss & 0xF; /* vertical sampling */ > >> > data->hs = ss >> 4; /* horizontal sampling */ > >> > >> Please use correct interpunction. > > > > I'm sorry, what do you mean by correct interpunction ? > > That I prefer: > > /* vertical sampling */ -> /* Vertical sampling. */ > > Same for the other two lines. With this change, only the legal > question remains. oh, i see. The IJG's source code: http://www.ijg.org/files/jpegsrc.v6b.tar.gz there is a legal issue section in the README file. -- Bean ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] jpeg image reader 2008-01-15 14:36 ` Bean @ 2008-01-15 16:01 ` Marco Gerards 2008-01-15 16:15 ` Bean 0 siblings, 1 reply; 23+ messages in thread From: Marco Gerards @ 2008-01-15 16:01 UTC (permalink / raw) To: The development of GRUB 2 Bean <bean123ch@gmail.com> writes: [...] >> Same for the other two lines. With this change, only the legal >> question remains. > > oh, i see. > > The IJG's source code: > > http://www.ijg.org/files/jpegsrc.v6b.tar.gz > > there is a legal issue section in the README file. The license state that their README should be distributed together with GRUB 2, if I understand it correctly. As you might guess, this is not acceptable. Please be careful when using code from other projects (or even better: totally avoid it!), at least tell us you did so when submitting a patch. Are you sure only the color space conversion and the IDCT are the only things from the jpeg group you used? Please double check... If it is only color space conversion and IDCT, I am sure we can write our own code for this. If you do now have the knowledge, I can help you with this or point you to some documentation, if you'd like. I hope you understand my situation... I really like your code and I want to help in any way to integrate it into GRUB 2. -- Marco ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] jpeg image reader 2008-01-15 16:01 ` Marco Gerards @ 2008-01-15 16:15 ` Bean 2008-01-15 20:48 ` Bean 0 siblings, 1 reply; 23+ messages in thread From: Bean @ 2008-01-15 16:15 UTC (permalink / raw) To: The development of GRUB 2 On Jan 16, 2008 12:01 AM, Marco Gerards <mgerards@xs4all.nl> wrote: > The license state that their README should be distributed together > with GRUB 2, if I understand it correctly. As you might guess, this > is not acceptable. Please be careful when using code from other > projects (or even better: totally avoid it!), at least tell us you did > so when submitting a patch. Are you sure only the color space > conversion and the IDCT are the only things from the jpeg group you > used? Please double check... > > If it is only color space conversion and IDCT, I am sure we can write > our own code for this. If you do now have the knowledge, I can help > you with this or point you to some documentation, if you'd like. > > I hope you understand my situation... I really like your code and I > want to help in any way to integrate it into GRUB 2. I think the color conversion is easy, i can change it myself. but idct is tricky, it use AA&N algorithm, which is the only effective solution. besides, the code is not exactly the same, i just take the basic idea. (it's in jidctfst.c) -- Bean ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] jpeg image reader 2008-01-15 16:15 ` Bean @ 2008-01-15 20:48 ` Bean 2008-01-21 10:21 ` Marco Gerards 0 siblings, 1 reply; 23+ messages in thread From: Bean @ 2008-01-15 20:48 UTC (permalink / raw) To: The development of GRUB 2 Hi, i finish converting the idct and color code, now it should be ok. /* * GRUB -- GRand Unified Bootloader * Copyright (C) 2008 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * GRUB is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GRUB. If not, see <http://www.gnu.org/licenses/>. */ #include <grub/bitmap.h> #include <grub/types.h> #include <grub/normal.h> #include <grub/dl.h> #include <grub/mm.h> #include <grub/misc.h> #include <grub/arg.h> #include <grub/file.h> /* Uncomment following define to enable JPEG debug. */ //#define JPEG_DEBUG #define JPEG_ESC_CHAR 0xFF #define JPEG_SAMPLING_1x1 0x11 #define JPEG_MARKER_SOI 0xd8 #define JPEG_MARKER_EOI 0xd9 #define JPEG_MARKER_DHT 0xc4 #define JPEG_MARKER_DQT 0xdb #define JPEG_MARKER_SOF0 0xc0 #define JPEG_MARKER_SOS 0xda #define SHIFT_BITS 8 #define CONST(x) ((int) ((x) * (1L << SHIFT_BITS) + 0.5)) #define JPEG_UNIT_SIZE 8 static const grub_uint8_t jpeg_zigzag_order[64] = { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 }; typedef int jpeg_data_unit_t[64]; struct grub_jpeg_data { grub_file_t file; struct grub_video_bitmap **bitmap; int image_width; int image_height; grub_uint8_t *huff_value[4]; int huff_offset[4][16]; int huff_maxval[4][16]; grub_uint8_t quan_table[2][64]; int comp_index[3][3]; jpeg_data_unit_t ydu[4]; jpeg_data_unit_t crdu; jpeg_data_unit_t cbdu; int vs, hs; int dc_value[3]; int bit_mask, bit_save; }; static grub_uint8_t grub_jpeg_get_byte (struct grub_jpeg_data *data) { grub_uint8_t r; r = 0; grub_file_read (data->file, (char *) &r, 1); return r; } static grub_uint16_t grub_jpeg_get_word (struct grub_jpeg_data *data) { grub_uint16_t r; r = 0; grub_file_read (data->file, (char *) &r, sizeof (grub_uint16_t)); return grub_be_to_cpu16 (r); } static int grub_jpeg_get_bit (struct grub_jpeg_data *data) { int ret; if (data->bit_mask == 0) { data->bit_save = grub_jpeg_get_byte (data); if (data->bit_save == JPEG_ESC_CHAR) { if (grub_jpeg_get_byte (data) != 0) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid 0xFF in data stream"); return 0; } } data->bit_mask = 0x80; } ret = ((data->bit_save & data->bit_mask) != 0); data->bit_mask >>= 1; return ret; } static int grub_jpeg_get_number (struct grub_jpeg_data *data, int num) { int value, i, msb; if (num == 0) return 0; msb = value = grub_jpeg_get_bit (data); for (i = 1; i < num; i++) value = (value << 1) + (grub_jpeg_get_bit (data) != 0); if (!msb) value += 1 - (1 << num); return value; } static int grub_jpeg_get_huff_code (struct grub_jpeg_data *data, int id) { int code, i; code = 0; for (i = 0; i < 16; i++) { code <<= 1; if (grub_jpeg_get_bit (data)) code++; if (code < data->huff_maxval[id][i]) return data->huff_value[id][code + data->huff_offset[id][i]]; } grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: huffman decode fails"); return 0; } static grub_err_t grub_jpeg_decode_huff_table (struct grub_jpeg_data *data) { int id, ac, i, n, base, ofs; grub_uint32_t next_marker; grub_uint8_t count[16]; next_marker = data->file->offset; next_marker += grub_jpeg_get_word (data); id = grub_jpeg_get_byte (data); ac = (id >> 4); id &= 0xF; if (id > 1) return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: too many huffman tables"); if (grub_file_read (data->file, (char *) &count, sizeof (count)) != sizeof (count)) return grub_errno; n = 0; for (i = 0; i < 16; i++) n += count[i]; id += ac * 2; data->huff_value[id] = grub_malloc (n); if (grub_errno) return grub_errno; if (grub_file_read (data->file, (char *) data->huff_value[id], n) != n) return grub_errno; base = 0; ofs = 0; for (i = 0; i < 16; i++) { base += count[i]; ofs += count[i]; data->huff_maxval[id][i] = base; data->huff_offset[id][i] = ofs - base; base <<= 1; } if (data->file->offset != next_marker) grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in huffman table"); return grub_errno; } static grub_err_t grub_jpeg_decode_quan_table (struct grub_jpeg_data *data) { int id; grub_uint32_t next_marker; next_marker = data->file->offset; next_marker += grub_jpeg_get_word (data); id = grub_jpeg_get_byte (data); if (id >= 0x10) /* upper 4-bit is precision */ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: only 8-bit precision is supported"); if (id > 1) return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: too many quantization tables"); if (grub_file_read (data->file, (char *) &data->quan_table[id], 64) != 64) return grub_errno; if (data->file->offset != next_marker) grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in quantization table"); return grub_errno; } static grub_err_t grub_jpeg_decode_sof (struct grub_jpeg_data *data) { int i, cc; grub_uint32_t next_marker; next_marker = data->file->offset; next_marker += grub_jpeg_get_word (data); if (grub_jpeg_get_byte (data) != 8) return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: only 8-bit precision is supported"); data->image_height = grub_jpeg_get_word (data); data->image_width = grub_jpeg_get_word (data); if ((!data->image_height) || (!data->image_width)) return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid image size"); cc = grub_jpeg_get_byte (data); if (cc != 3) return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: component count must be 3"); for (i = 0; i < cc; i++) { int id, ss; id = grub_jpeg_get_byte (data) - 1; if ((id < 0) || (id >= 3)) return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index"); ss = grub_jpeg_get_byte (data); /* Sampling factor. */ if (!id) { data->vs = ss & 0xF; /* Vertical sampling. */ data->hs = ss >> 4; /* Horizontal sampling. */ if ((data->vs > 2) || (data->hs > 2)) return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: sampling method not supported"); } else if (ss != JPEG_SAMPLING_1x1) return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: sampling method not supported"); data->comp_index[id][0] = grub_jpeg_get_byte (data); } if (data->file->offset != next_marker) grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sof"); return grub_errno; } static void grub_jpeg_idct_transform (jpeg_data_unit_t du) { int *pd; int i; int t0, t1, t2, t3, t4, t5, t6, t7; int v0, v1, v2, v3, v4; pd = du; for (i = 0; i < JPEG_UNIT_SIZE; i++, pd++) { if ((pd[JPEG_UNIT_SIZE * 1] | pd[JPEG_UNIT_SIZE * 2] | pd[JPEG_UNIT_SIZE * 3] | pd[JPEG_UNIT_SIZE * 4] | pd[JPEG_UNIT_SIZE * 5] | pd[JPEG_UNIT_SIZE * 6] | pd[JPEG_UNIT_SIZE * 7]) == 0) { pd[JPEG_UNIT_SIZE * 0] <<= SHIFT_BITS; pd[JPEG_UNIT_SIZE * 1] = pd[JPEG_UNIT_SIZE * 2] = pd[JPEG_UNIT_SIZE * 3] = pd[JPEG_UNIT_SIZE * 4] = pd[JPEG_UNIT_SIZE * 5] = pd[JPEG_UNIT_SIZE * 6] = pd[JPEG_UNIT_SIZE * 7] = pd[JPEG_UNIT_SIZE * 0]; continue; } t0 = pd[JPEG_UNIT_SIZE * 0]; t1 = pd[JPEG_UNIT_SIZE * 2]; t2 = pd[JPEG_UNIT_SIZE * 4]; t3 = pd[JPEG_UNIT_SIZE * 6]; v4 = (t1 + t3) * CONST (0.541196100); v0 = ((t0 + t2) << SHIFT_BITS); v1 = ((t0 - t2) << SHIFT_BITS); v2 = v4 - t3 * CONST (1.847759065); v3 = v4 + t1 * CONST (0.765366865); t0 = v0 + v3; t3 = v0 - v3; t1 = v1 + v2; t2 = v1 - v2; t4 = pd[JPEG_UNIT_SIZE * 7]; t5 = pd[JPEG_UNIT_SIZE * 5]; t6 = pd[JPEG_UNIT_SIZE * 3]; t7 = pd[JPEG_UNIT_SIZE * 1]; v0 = t4 + t7; v1 = t5 + t6; v2 = t4 + t6; v3 = t5 + t7; v4 = (v2 + v3) * CONST (1.175875602); v0 *= CONST (0.899976223); v1 *= CONST (2.562915447); v2 = v2 * CONST (1.961570560) - v4; v3 = v3 * CONST (0.390180644) - v4; t4 = t4 * CONST (0.298631336) - v0 - v2; t5 = t5 * CONST (2.053119869) - v1 - v3; t6 = t6 * CONST (3.072711026) - v1 - v2; t7 = t7 * CONST (1.501321110) - v0 - v3; pd[JPEG_UNIT_SIZE * 0] = t0 + t7; pd[JPEG_UNIT_SIZE * 7] = t0 - t7; pd[JPEG_UNIT_SIZE * 1] = t1 + t6; pd[JPEG_UNIT_SIZE * 6] = t1 - t6; pd[JPEG_UNIT_SIZE * 2] = t2 + t5; pd[JPEG_UNIT_SIZE * 5] = t2 - t5; pd[JPEG_UNIT_SIZE * 3] = t3 + t4; pd[JPEG_UNIT_SIZE * 4] = t3 - t4; } pd = du; for (i = 0; i < JPEG_UNIT_SIZE; i++, pd += JPEG_UNIT_SIZE) { if ((pd[1] | pd[2] | pd[3] | pd[4] | pd[5] | pd[6] | pd[7]) == 0) { pd[0] >>= (SHIFT_BITS + 3); pd[1] = pd[2] = pd[3] = pd[4] = pd[5] = pd[6] = pd[7] = pd[0]; continue; } v4 = (pd[2] + pd[6]) * CONST (0.541196100); v0 = (pd[0] + pd[4]) << SHIFT_BITS; v1 = (pd[0] - pd[4]) << SHIFT_BITS; v2 = v4 - pd[6] * CONST (1.847759065); v3 = v4 + pd[2] * CONST (0.765366865); t0 = v0 + v3; t3 = v0 - v3; t1 = v1 + v2; t2 = v1 - v2; t4 = pd[7]; t5 = pd[5]; t6 = pd[3]; t7 = pd[1]; v0 = t4 + t7; v1 = t5 + t6; v2 = t4 + t6; v3 = t5 + t7; v4 = (v2 + v3) * CONST (1.175875602); v0 *= CONST (0.899976223); v1 *= CONST (2.562915447); v2 = v2 * CONST (1.961570560) - v4; v3 = v3 * CONST (0.390180644) - v4; t4 = t4 * CONST (0.298631336) - v0 - v2; t5 = t5 * CONST (2.053119869) - v1 - v3; t6 = t6 * CONST (3.072711026) - v1 - v2; t7 = t7 * CONST (1.501321110) - v0 - v3; pd[0] = (t0 + t7) >> (SHIFT_BITS * 2 + 3); pd[7] = (t0 - t7) >> (SHIFT_BITS * 2 + 3); pd[1] = (t1 + t6) >> (SHIFT_BITS * 2 + 3); pd[6] = (t1 - t6) >> (SHIFT_BITS * 2 + 3); pd[2] = (t2 + t5) >> (SHIFT_BITS * 2 + 3); pd[5] = (t2 - t5) >> (SHIFT_BITS * 2 + 3); pd[3] = (t3 + t4) >> (SHIFT_BITS * 2 + 3); pd[4] = (t3 - t4) >> (SHIFT_BITS * 2 + 3); } for (i = 0; i < JPEG_UNIT_SIZE * JPEG_UNIT_SIZE; i++) { du[i] += 128; if (du[i] < 0) du[i] = 0; if (du[i] > 255) du[i] = 255; } } static void grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) { int pos, h1, h2, qt; grub_memset (du, 0, sizeof (jpeg_data_unit_t)); qt = data->comp_index[id][0]; h1 = data->comp_index[id][1]; h2 = data->comp_index[id][2]; data->dc_value[id] += grub_jpeg_get_number (data, grub_jpeg_get_huff_code (data, h1)); du[0] = data->dc_value[id] * (int) data->quan_table[qt][0]; pos = 1; while (pos < 64) { int num, val; num = grub_jpeg_get_huff_code (data, h2); if (!num) break; val = grub_jpeg_get_number (data, num & 0xF); num >>= 4; pos += num; du[jpeg_zigzag_order[pos]] = val * (int) data->quan_table[qt][pos]; pos++; } grub_jpeg_idct_transform (du); } static void grub_jpeg_ycrcb_to_rgb (int yy, int cr, int cb, grub_uint8_t * rgb) { int dd; cr -= 128; cb -= 128; /* Red */ dd = yy + ((cr * CONST (1.402)) >> SHIFT_BITS); if (dd < 0) dd = 0; if (dd > 255) dd = 255; *(rgb++) = dd; /* Green */ dd = yy - ((cb * CONST (0.34414) + cr * CONST (0.71414)) >> SHIFT_BITS); if (dd < 0) dd = 0; if (dd > 255) dd = 255; *(rgb++) = dd; /* Blue */ dd = yy + ((cb * CONST (1.772)) >> SHIFT_BITS); if (dd < 0) dd = 0; if (dd > 255) dd = 255; *(rgb++) = dd; } static grub_err_t grub_jpeg_decode_sos (struct grub_jpeg_data *data) { int i, cc, r1, c1, nr1, nc1, vb, hb; grub_uint8_t *ptr1; grub_uint32_t data_offset; data_offset = data->file->offset; data_offset += grub_jpeg_get_word (data); cc = grub_jpeg_get_byte (data); if (cc != 3) return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: component count must be 3"); for (i = 0; i < cc; i++) { int id, ht; id = grub_jpeg_get_byte (data) - 1; if ((id < 0) || (id >= 3)) return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index"); ht = grub_jpeg_get_byte (data); data->comp_index[id][1] = (ht >> 4); data->comp_index[id][2] = (ht & 0xF) + 2; } grub_jpeg_get_byte (data); /* skip 3 unused bytes */ grub_jpeg_get_word (data); if (data->file->offset != data_offset) return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sos"); if (grub_video_bitmap_create (data->bitmap, data->image_width, data->image_height, GRUB_VIDEO_BLIT_FORMAT_R8G8B8)) return grub_errno; data->bit_mask = 0x0; vb = data->vs * 8; hb = data->hs * 8; nr1 = (data->image_height + vb - 1) / vb; nc1 = (data->image_width + hb - 1) / hb; ptr1 = (*data->bitmap)->data; for (r1 = 0; r1 < nr1; r1++, ptr1 += (vb * data->image_width - hb * nc1) * 3) for (c1 = 0; c1 < nc1; c1++, ptr1 += hb * 3) { int r2, c2, nr2, nc2; grub_uint8_t *ptr2; for (r2 = 0; r2 < data->vs; r2++) for (c2 = 0; c2 < data->hs; c2++) grub_jpeg_decode_du (data, 0, data->ydu[r2 * 2 + c2]); grub_jpeg_decode_du (data, 1, data->cbdu); grub_jpeg_decode_du (data, 2, data->crdu); if (grub_errno) return grub_errno; nr2 = (r1 == nr1 - 1) ? (data->image_height - r1 * vb) : vb; nc2 = (c1 == nc1 - 1) ? (data->image_width - c1 * hb) : hb; ptr2 = ptr1; for (r2 = 0; r2 < nr2; r2++, ptr2 += (data->image_width - nc2) * 3) for (c2 = 0; c2 < nc2; c2++, ptr2 += 3) { int i0, yy, cr, cb; i0 = (r2 / data->vs) * 8 + (c2 / data->hs); cr = data->crdu[i0]; cb = data->cbdu[i0]; yy = data->ydu[(r2 / 8) * 2 + (c2 / 8)][(r2 % 8) * 8 + (c2 % 8)]; grub_jpeg_ycrcb_to_rgb (yy, cr, cb, ptr2); } } return grub_errno; } static grub_uint8_t grub_jpeg_get_marker (struct grub_jpeg_data *data) { grub_uint8_t r; r = grub_jpeg_get_byte (data); if (r != JPEG_ESC_CHAR) { grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid maker"); return 0; } return grub_jpeg_get_byte (data); } static grub_err_t grub_jpeg_decode_jpeg (struct grub_jpeg_data *data) { if (grub_jpeg_get_marker (data) != JPEG_MARKER_SOI) /* Start Of Image. */ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid jpeg file"); while (grub_errno == 0) { grub_uint8_t marker; marker = grub_jpeg_get_marker (data); if (grub_errno) break; #ifdef JPEG_DEBUG grub_printf ("jpeg marker: %x\n", marker); #endif switch (marker) { case JPEG_MARKER_DHT: /* Define Huffman Table. */ grub_jpeg_decode_huff_table (data); break; case JPEG_MARKER_DQT: /* Define Quantization Table. */ grub_jpeg_decode_quan_table (data); break; case JPEG_MARKER_SOF0: /* Start Of Frame 0. */ grub_jpeg_decode_sof (data); break; case JPEG_MARKER_SOS: /* Start Of Scan. */ grub_jpeg_decode_sos (data); break; case JPEG_MARKER_EOI: /* End Of Image. */ return grub_errno; default: /* Skip unrecognized marker. */ { grub_uint16_t sz; sz = grub_jpeg_get_word (data); if (grub_errno) return (grub_errno); grub_file_seek (data->file, data->file->offset + sz - 2); } } } return grub_errno; } static grub_err_t grub_video_reader_jpeg (struct grub_video_bitmap **bitmap, const char *filename) { grub_file_t file; struct grub_jpeg_data *data; file = grub_file_open (filename); if (!file) return grub_errno; data = grub_malloc (sizeof (*data)); if (data != NULL) { int i; grub_memset (data, 0, sizeof (*data)); data->file = file; data->bitmap = bitmap; grub_jpeg_decode_jpeg (data); for (i = 0; i < 4; i++) if (data->huff_value[i]) grub_free (data->huff_value[i]); grub_free (data); } if (grub_errno != GRUB_ERR_NONE) { grub_video_bitmap_destroy (*bitmap); *bitmap = 0; } grub_file_close (file); return grub_errno; } #if defined(JPEG_DEBUG) static grub_err_t grub_cmd_jpegtest (struct grub_arg_list *state __attribute__ ((unused)), int argc, char **args) { struct grub_video_bitmap *bitmap = 0; if (argc != 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required"); grub_video_reader_jpeg (&bitmap, args[0]); if (grub_errno != GRUB_ERR_NONE) return grub_errno; grub_video_bitmap_destroy (bitmap); return GRUB_ERR_NONE; } #endif static struct grub_video_bitmap_reader jpg_reader = { .extension = ".jpg", .reader = grub_video_reader_jpeg, .next = 0 }; static struct grub_video_bitmap_reader jpeg_reader = { .extension = ".jpeg", .reader = grub_video_reader_jpeg, .next = 0 }; GRUB_MOD_INIT (video_reader_jpeg) { grub_video_bitmap_reader_register (&jpg_reader); grub_video_bitmap_reader_register (&jpeg_reader); #if defined(JPEG_DEBUG) grub_register_command ("jpegtest", grub_cmd_jpegtest, GRUB_COMMAND_FLAG_BOTH, "jpegtest FILE", "Tests loading of JPEG bitmap.", 0); #endif } GRUB_MOD_FINI (video_reader_jpeg) { #if defined(JPEG_DEBUG) grub_unregister_command ("jpegtest"); #endif grub_video_bitmap_reader_unregister (&jpeg_reader); grub_video_bitmap_reader_unregister (&jpg_reader); } -- Bean ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] jpeg image reader 2008-01-15 20:48 ` Bean @ 2008-01-21 10:21 ` Marco Gerards 2008-01-22 14:04 ` Bean 0 siblings, 1 reply; 23+ messages in thread From: Marco Gerards @ 2008-01-21 10:21 UTC (permalink / raw) To: The development of GRUB 2 Bean <bean123ch@gmail.com> writes: Hi, > i finish converting the idct and color code, now it should be ok. If you are 100% sure all code is yours and there are no legal issues, feel free to commit it. Your code looks good to me :-) -- Marco ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] jpeg image reader 2008-01-21 10:21 ` Marco Gerards @ 2008-01-22 14:04 ` Bean 0 siblings, 0 replies; 23+ messages in thread From: Bean @ 2008-01-22 14:04 UTC (permalink / raw) To: The development of GRUB 2 On Jan 21, 2008 6:21 PM, Marco Gerards <mgerards@xs4all.nl> wrote: > Bean <bean123ch@gmail.com> writes: > > Hi, > > > i finish converting the idct and color code, now it should be ok. > > If you are 100% sure all code is yours and there are no legal issues, > feel free to commit it. Your code looks good to me :-) Committed. when you have time, please review my png patch as well. -- Bean ^ permalink raw reply [flat|nested] 23+ messages in thread
end of thread, other threads:[~2008-01-22 14:04 UTC | newest] Thread overview: 23+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2008-01-09 17:21 [PATCH] jpeg image reader Bean 2008-01-09 17:56 ` Bean 2008-01-09 20:33 ` Vesa Jääskeläinen 2008-01-10 10:12 ` Bean 2008-01-12 8:51 ` Bean 2008-01-13 8:49 ` Bean 2008-01-13 18:31 ` Marco Gerards 2008-01-14 16:36 ` Bean 2008-01-15 11:01 ` Marco Gerards 2008-01-15 11:52 ` Robert Millan 2008-01-15 12:21 ` Marco Gerards 2008-01-15 12:29 ` Robert Millan 2008-01-15 12:46 ` Marco Gerards 2008-01-15 13:36 ` Bean 2008-01-15 14:25 ` Marco Gerards 2008-01-15 13:54 ` Bean 2008-01-15 14:27 ` Marco Gerards 2008-01-15 14:36 ` Bean 2008-01-15 16:01 ` Marco Gerards 2008-01-15 16:15 ` Bean 2008-01-15 20:48 ` Bean 2008-01-21 10:21 ` Marco Gerards 2008-01-22 14:04 ` Bean
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.