From 31e521a02edc7da6229dc348754c557b97ba83c9 Mon Sep 17 00:00:00 2001 From: James Bursa Date: Tue, 23 Mar 2004 22:17:08 +0000 Subject: [project @ 2004-03-23 22:17:08 by bursa] Remove usage of OS JPEG module; convert all JPEGs to 32bpp and plot with Tinct; speed improvements and cleanup. svn path=/import/netsurf/; revision=656 --- riscos/jpeg.c | 473 ++++++++++++++++++++--------------------------------- riscos/jpeg.h | 6 +- riscos/save_draw.c | 62 +------ 3 files changed, 182 insertions(+), 359 deletions(-) diff --git a/riscos/jpeg.c b/riscos/jpeg.c index b0ae9a801..2319c15cd 100644 --- a/riscos/jpeg.c +++ b/riscos/jpeg.c @@ -2,357 +2,244 @@ * This file is part of NetSurf, http://netsurf.sourceforge.net/ * Licensed under the GNU General Public License, * http://www.opensource.org/licenses/gpl-license - * Copyright 2003 James Bursa + * Copyright 2004 James Bursa * Copyright 2004 John M Bell */ +/** \file + * Content for image/jpeg (implementation). + * + * This implementation uses the IJG JPEG library. + */ + #include #include #include #include #include +#include +#define JPEG_INTERNAL_OPTIONS #include "libjpeg/jpeglib.h" #include "oslib/colourtrans.h" -#include "oslib/jpeg.h" -#include "oslib/osbyte.h" -#include "oslib/osfile.h" #include "oslib/osspriteop.h" #include "netsurf/utils/config.h" #include "netsurf/content/content.h" #include "netsurf/desktop/gui.h" #include "netsurf/riscos/jpeg.h" +#include "netsurf/riscos/options.h" +#include "netsurf/riscos/tinct.h" #include "netsurf/utils/log.h" #include "netsurf/utils/messages.h" #include "netsurf/utils/utils.h" -/** - * screen mode image result - * 8bpp or less 8, 16 or 24bpp dither to 8bpp - * 16 or 24bpp 8, 16 or 24bpp 24bpp sprite - */ -#ifdef WITH_JPEG +/* We require a the library to be configured with these options to save + * copying data during decoding. */ +#if RGB_RED != 0 || RGB_GREEN != 1 || RGB_BLUE != 2 || RGB_PIXELSIZE != 4 +#error JPEG library incorrectly configured. +#endif + + +struct nsjpeg_error_mgr { + struct jpeg_error_mgr pub; + jmp_buf setjmp_buffer; +}; + + +static void nsjpeg_error_exit(j_common_ptr cinfo); +static void nsjpeg_init_source(j_decompress_ptr cinfo); +static boolean nsjpeg_fill_input_buffer(j_decompress_ptr cinfo); +static void nsjpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes); +static void nsjpeg_term_source(j_decompress_ptr cinfo); + + /** - * Input source initalisation routine - * Does nothing. + * Create a CONTENT_JPEG. */ -static void init_source(j_decompress_ptr cinfo) { + +void nsjpeg_create(struct content *c, const char *params[]) +{ + c->data.jpeg.sprite_area = 0; } + /** - * Routine to fill the input buffer. - * Filling buffer is not possible => return false. + * Convert a CONTENT_JPEG for display. */ -static boolean fill_input_buffer(j_decompress_ptr cinfo) { - return FALSE; -} -static void skip_input_data(j_decompress_ptr cinfo, long num_bytes) { - if ((int)num_bytes > (int)cinfo->src->bytes_in_buffer) { - cinfo->src->next_input_byte = NULL; - cinfo->src->bytes_in_buffer = 0; - } else { - cinfo->src->next_input_byte += (int) num_bytes; - cinfo->src->bytes_in_buffer -= (int) num_bytes; - } +int nsjpeg_convert(struct content *c, unsigned int w, unsigned int h) +{ + struct jpeg_decompress_struct cinfo; + struct nsjpeg_error_mgr jerr; + struct jpeg_source_mgr source_mgr = { 0, 0, + nsjpeg_init_source, nsjpeg_fill_input_buffer, + nsjpeg_skip_input_data, jpeg_resync_to_restart, + nsjpeg_term_source }; + unsigned int height; + unsigned int width; + unsigned int area_size; + osspriteop_area *sprite_area = 0; + osspriteop_header *sprite; + + cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.error_exit = nsjpeg_error_exit; + if (setjmp(jerr.setjmp_buffer)) { + jpeg_destroy_decompress(&cinfo); + free(sprite_area); + return 1; + } + jpeg_create_decompress(&cinfo); + source_mgr.next_input_byte = c->source_data; + source_mgr.bytes_in_buffer = c->source_size; + cinfo.src = &source_mgr; + jpeg_read_header(&cinfo, TRUE); + cinfo.out_color_space = JCS_RGB; + cinfo.dct_method = JDCT_ISLOW; + jpeg_start_decompress(&cinfo); + + width = cinfo.output_width; + height = cinfo.output_height; + + area_size = 16 + 44 + width * height * 4; + sprite_area = malloc(area_size); + if (!sprite_area) { + LOG(("malloc failed")); + return 1; + } + + /* area control block */ + sprite_area->size = area_size; + sprite_area->sprite_count = 1; + sprite_area->first = 16; + sprite_area->used = area_size; + + /* sprite control block */ + sprite = (osspriteop_header *) (sprite_area + 1); + sprite->size = area_size - 16; + strncpy(sprite->name, "jpeg", 12); + sprite->width = width - 1; + sprite->height = height - 1; + sprite->left_bit = 0; + sprite->right_bit = 31; + sprite->image = sprite->mask = 44; + sprite->mode = (os_mode) 0x301680b5; + + do { + JSAMPROW scanlines[1]; + scanlines[0] = (JSAMPROW) ((char *) sprite + 44 + + width * cinfo.output_scanline * 4); + jpeg_read_scanlines(&cinfo, scanlines, 1); + } while (cinfo.output_scanline != cinfo.output_height); + + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + + /*xosspriteop_save_sprite_file(osspriteop_USER_AREA, + sprite_area, "jpeg");*/ + + c->width = width; + c->height = height; + c->data.jpeg.sprite_area = sprite_area; + c->title = malloc(100); + if (c->title) + sprintf(c->title, messages_get("JPEGTitle"), + width, height, c->source_size); + c->status = CONTENT_STATUS_DONE; + return 0; } + /** - * Input source termination routine - * Does nothing + * Fatal error handler for JPEG library. + * + * This prevents jpeglib calling exit() on a fatal error. */ -static void term_source(j_decompress_ptr cinfo) { + +void nsjpeg_error_exit(j_common_ptr cinfo) +{ + struct nsjpeg_error_mgr *err = (struct nsjpeg_error_mgr *) cinfo->err; + (*cinfo->err->output_message) (cinfo); + longjmp(err->setjmp_buffer, 1); } + /** - * Input source manager. - * Sets up jpeglib appropriately + * JPEG data source manager: initialize source. */ -static void jpeg_memory_src(j_decompress_ptr cinfo, char *ptr, unsigned long length) { - - struct jpeg_source_mgr *src; - src = cinfo->src = (struct jpeg_source_mgr *) - (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, - JPOOL_IMAGE, - sizeof(*src)); - src->init_source = init_source; - src->fill_input_buffer = fill_input_buffer; - src->skip_input_data = skip_input_data; - src->resync_to_restart = jpeg_resync_to_restart; - src->term_source = term_source; - src->next_input_byte = ptr; - src->bytes_in_buffer = length; -} - -/* Error handling stuff. - This prevents jpeglib calling exit() on a fatal error */ -struct nsjpeg_error_mgr { - struct jpeg_error_mgr pub; - jmp_buf setjmp_buffer; -}; -typedef struct nsjpeg_error_mgr * nsjpeg_err_ptr; +void nsjpeg_init_source(j_decompress_ptr cinfo) +{ +} -METHODDEF (void) nsjpeg_error_exit (j_common_ptr cinfo) { - nsjpeg_err_ptr myerr = (nsjpeg_err_ptr)cinfo->err; +static char nsjpeg_eoi[] = { 0xff, JPEG_EOI }; - (*cinfo->err->output_message) (cinfo); +/** + * JPEG data source manager: fill the input buffer. + * + * This can only occur if the JPEG data was truncated or corrupted. Insert a + * fake EOI marker to allow the decompressor to output as much as possible. + */ - longjmp(myerr->setjmp_buffer, 1); +boolean nsjpeg_fill_input_buffer(j_decompress_ptr cinfo) +{ + cinfo->src->next_input_byte = nsjpeg_eoi; + cinfo->src->bytes_in_buffer = 2; + return TRUE; } -/** maps colours to 256 mode colour numbers */ -static os_colour_number colour_table[4096]; /** - * Initialises the jpeg loader. - * Currently creates the 8bpp lookup table + * JPEG data source manager: skip num_bytes worth of data. */ -void nsjpeg_init(void) { - - unsigned int red, green, blue; - /* generate colour lookup table for reducing to 8bpp */ - for (red = 0; red != 0x10; red++) - for (green = 0; green != 0x10; green++) - for (blue = 0; blue != 0x10; blue++) - colour_table[red << 8 | green << 4 | blue] = - colourtrans_return_colour_number_for_mode( - blue << 28 | blue << 24 | - green << 20 | green << 16 | - red << 12 | red << 8, - (os_mode)21, 0); -} -void nsjpeg_create(struct content *c, const char *params[]) +void nsjpeg_skip_input_data(j_decompress_ptr cinfo, long num_bytes) { - c->data.jpeg.sprite_area = 0; - c->data.jpeg.use_module = true; /* assume the OS can cope */ + if ((long) cinfo->src->bytes_in_buffer < num_bytes) { + cinfo->src->next_input_byte = 0; + cinfo->src->bytes_in_buffer = 0; + } else { + cinfo->src->next_input_byte += num_bytes; + cinfo->src->bytes_in_buffer -= num_bytes; + } } -int nsjpeg_convert(struct content *c, unsigned int width, unsigned int height) +/** + * JPEG data source manager: terminate source. + */ + +void nsjpeg_term_source(j_decompress_ptr cinfo) { - struct jpeg_decompress_struct cinfo; - struct nsjpeg_error_mgr jerr; - unsigned int line_size; - unsigned char *dstcur; - os_mode_block curr_mode; - - /* get screenmode (RO3.1 compliant) */ - xos_byte(osbyte_SCREEN_CHAR, 0, 0, 0, (int*)&curr_mode); - - /* Try to use OS routines */ - { - os_error *e; - int w,h; - e = xjpeginfo_dimensions((jpeg_image const*)c->source_data, - (int) c->source_size, - 0, &w, &h, 0, 0, 0); - - if (!e) { - LOG(("Using inbuilt OS routines")); - c->width = w; - c->height = h; - c->title = xcalloc(100, 1); - sprintf(c->title, messages_get("JPEGTitle"), w, h, c->source_size); - c->status = CONTENT_STATUS_DONE; - return 0; - } - /* failed, for whatever reason -> use jpeglib */ - c->data.jpeg.use_module = false; - } - - LOG(("beginning conversion")); - cinfo.err = jpeg_std_error(&jerr.pub); - jerr.pub.error_exit = nsjpeg_error_exit; - if (setjmp(jerr.setjmp_buffer)) { - jpeg_destroy_decompress(&cinfo); - return 1; - } - jpeg_create_decompress(&cinfo); - jpeg_memory_src(&cinfo, c->source_data, c->source_size); - jpeg_read_header(&cinfo, TRUE); - jpeg_start_decompress(&cinfo); - - c->width = cinfo.output_width; - c->height = cinfo.output_height; - line_size = cinfo.output_width*cinfo.output_components; - - LOG(("creating sprite area")); - { - struct osspriteop_header *spr; - unsigned int abw; - unsigned int nBytes; - - if ((curr_mode.size < 256 && curr_mode.size >= 0) || - curr_mode.log2_bpp <= 3 /*256*/) { - abw = ((c->width + 3) &~ 3u) * c->height; /* sprite */ - nBytes = abw + 44 + 16; - } - else { - abw = ((c->width + 3) &~ 3u) * 4 * c->height; /* sprite */ - nBytes = abw + 44 + 16; - } - /* nBytes = spr + spr ctrl blk + area ctrl blk */ - - c->data.jpeg.sprite_area = xcalloc(1, nBytes); - spr = (osspriteop_header*) (c->data.jpeg.sprite_area + 1); - - /* area control block */ - c->data.jpeg.sprite_area->size = nBytes; - c->data.jpeg.sprite_area->sprite_count = 1; - c->data.jpeg.sprite_area->first = sizeof(*c->data.jpeg.sprite_area); - c->data.jpeg.sprite_area->used = nBytes; - - /* sprite control block */ - spr->size = nBytes-sizeof(*c->data.jpeg.sprite_area); - strncpy(spr->name, "jpeg", 12); - - if ((curr_mode.size < 256 && curr_mode.size >= 0) || - curr_mode.log2_bpp <= 3 /*256*/) { - spr->width = ((c->width+3)>>2)-1; /* in words-1 */ - } - else { - spr->width = c->width - 1; - } - - spr->height = c->height-1; /* in scanlines-1 */ - spr->left_bit = 0; - spr->right_bit = ((c->width & 3) * 8 - 1) & 31; - spr->image = sizeof(*spr); - spr->mask = sizeof(*spr); - - if ((curr_mode.size < 256 && curr_mode.size >= 0) || - curr_mode.log2_bpp <= 3 /*256*/) { - spr->mode = os_MODE8BPP90X90; /* 28 */ - } - else { - spr->mode = (os_mode)((osspriteop_TYPE32BPP<<27) | (90<<14) | (90<<1) | 1); - } - - c->data.jpeg.sprite_image = ((char*)spr) + spr->image; - - LOG(("done")); - } - - LOG(("processing image: %ldx%ld,%d", c->width, c->height, cinfo.actual_number_of_colors)); - - if ((curr_mode.size < 256 && curr_mode.size >= 0) || - curr_mode.log2_bpp <= 3 /*256*/) { - JSAMPARRAY buf = (*cinfo.mem->alloc_sarray) - ((j_common_ptr)&cinfo, JPOOL_IMAGE, line_size, 1); - unsigned int col; - JSAMPROW row; - - gui_multitask(); /* this takes some time so poll the wimp */ - while (cinfo.output_scanline < cinfo.output_height) { - - jpeg_read_scanlines(&cinfo, buf, 1); - - row = buf[0]; - dstcur = c->data.jpeg.sprite_image + - cinfo.output_scanline * ((c->width +3) & ~3u); - for (col = 0; col != cinfo.output_width; col++) { - dstcur[col] = colour_table[((GETJSAMPLE(row[0])>>4)<<8) /* R */ - | ((GETJSAMPLE(row[1])>>4)<<4) /* G */ - | (GETJSAMPLE(row[2])>>4)]; /* B */ - row += 3; - } - } - } - else { - JSAMPARRAY buf = (*cinfo.mem->alloc_sarray) - ((j_common_ptr)&cinfo, JPOOL_IMAGE, line_size, 1); - unsigned int col; - JSAMPROW row; - - gui_multitask(); /* this takes some time so poll the wimp */ - dstcur = c->data.jpeg.sprite_image; - while (cinfo.output_scanline < cinfo.output_height) { - - jpeg_read_scanlines(&cinfo, buf, 1); - - row = buf[0]; - for (col = 0; col != cinfo.output_width; col++) { - dstcur[0] = GETJSAMPLE(row[0]); /* R */ - dstcur[1] = GETJSAMPLE(row[1]); /* G */ - dstcur[2] = GETJSAMPLE(row[2]); /* B */ - dstcur[3] = 0; /* A */ - row += 3; dstcur += 4; - } - } - } - - jpeg_finish_decompress(&cinfo); - jpeg_destroy_decompress(&cinfo); - LOG(("image decompressed")); - - /*{ - os_error *e; - e = xosspriteop_save_sprite_file(osspriteop_USER_AREA, - c->data.jpeg.sprite_area, "jpeg"); - }*/ - - c->status = CONTENT_STATUS_DONE; - return 0; } +/** + * Destroy a CONTENT_JPEG and free all resources it owns. + */ + void nsjpeg_destroy(struct content *c) { - xfree(c->data.jpeg.sprite_area); - xfree(c->title); + free(c->data.jpeg.sprite_area); + free(c->title); } + +/** + * Redraw a CONTENT_JPEG. + */ + void nsjpeg_redraw(struct content *c, long x, long y, - unsigned long width, unsigned long height, - long clip_x0, long clip_y0, long clip_x1, long clip_y1, - float scale) + unsigned long width, unsigned long height, + long clip_x0, long clip_y0, long clip_x1, long clip_y1, + float scale) { - unsigned int size; - osspriteop_trans_tab *table; - os_factors factors; - - factors.xmul = width; - factors.ymul = height; - factors.xdiv = c->width * 2; - factors.ydiv = c->height * 2; - - if (c->data.jpeg.use_module) { /* we can use the OS for this one */ - xjpeg_plot_scaled((jpeg_image *) c->source_data, - x, (int)(y - height), - &factors, (int) c->source_size, - jpeg_SCALE_DITHERED); - return; - } - - xcolourtrans_generate_table_for_sprite(c->data.jpeg.sprite_area, - (osspriteop_id) ((char*)c->data.jpeg.sprite_area + - c->data.jpeg.sprite_area->first), - colourtrans_CURRENT_MODE, colourtrans_CURRENT_PALETTE, - 0, colourtrans_GIVEN_SPRITE, 0, 0, &size); - - table = xcalloc(size, 1); - - xcolourtrans_generate_table_for_sprite(c->data.jpeg.sprite_area, - (osspriteop_id) ((char*)c->data.jpeg.sprite_area + - c->data.jpeg.sprite_area->first), - colourtrans_CURRENT_MODE, colourtrans_CURRENT_PALETTE, - table, colourtrans_GIVEN_SPRITE, 0, 0, 0); - - xosspriteop_put_sprite_scaled(osspriteop_PTR, - c->data.jpeg.sprite_area, - (osspriteop_id) ((char*)c->data.jpeg.sprite_area + - c->data.jpeg.sprite_area->first), - x, (int)(y - height), - /* osspriteop_USE_PALETTE is RO 3.5+ only. - * behaviour on RO < 3.5 is unknown... - */ - (osspriteop_action)(osspriteop_USE_MASK | - osspriteop_USE_PALETTE), - &factors, table); - - xfree(table); + _swix(Tinct_PlotScaled, + _IN(2) | _IN(3) | _IN(4) | _IN(5) | _IN(6) | _IN(7), + (char *) c->data.jpeg.sprite_area + + c->data.jpeg.sprite_area->first, + x, (int) (y - height), + width, height, + (option_filter_sprites ? (1<<1) : 0) | + (option_dither_sprites ? (1<<2) : 0)); } -#endif diff --git a/riscos/jpeg.h b/riscos/jpeg.h index 2f6c8d211..928ec252f 100644 --- a/riscos/jpeg.h +++ b/riscos/jpeg.h @@ -2,24 +2,20 @@ * This file is part of NetSurf, http://netsurf.sourceforge.net/ * Licensed under the GNU General Public License, * http://www.opensource.org/licenses/gpl-license - * Copyright 2003 James Bursa + * Copyright 2004 James Bursa */ #ifndef _NETSURF_RISCOS_JPEG_H_ #define _NETSURF_RISCOS_JPEG_H_ -#include #include "oslib/osspriteop.h" struct content; struct content_jpeg_data { osspriteop_area *sprite_area; - char *sprite_image; - bool use_module; }; -void nsjpeg_init(void); void nsjpeg_create(struct content *c, const char *params[]); int nsjpeg_convert(struct content *c, unsigned int width, unsigned int height); void nsjpeg_destroy(struct content *c); diff --git a/riscos/save_draw.c b/riscos/save_draw.c index 095af4851..9fbbda88e 100644 --- a/riscos/save_draw.c +++ b/riscos/save_draw.c @@ -41,8 +41,6 @@ static void add_objects(struct content *content, struct box *box, unsigned long cbc, long x, long y); static void add_graphic(struct content *content, struct box *box, unsigned long cbc, long x, long y); -static void add_jpeg(struct content *content, struct box *box, - unsigned long cbc, long x, long y); static void add_rect(struct content *content, struct box *box, unsigned long cbc, long x, long y, bool bg); static void add_line(struct content *content, struct box *box, @@ -319,12 +317,7 @@ void add_graphic(struct content *content, struct box *box, /* cast-tastic... */ switch (content->type) { case CONTENT_JPEG: - if (content->data.jpeg.use_module) { - sprite_length = -1; - } - else { - sprite_length = ((osspriteop_header*)((char*)content->data.jpeg.sprite_area+content->data.jpeg.sprite_area->first))->size; - } + sprite_length = ((osspriteop_header*)((char*)content->data.jpeg.sprite_area+content->data.jpeg.sprite_area->first))->size; break; case CONTENT_PNG: sprite_length = ((osspriteop_header*)((char*)content->data.png.sprite_area+content->data.png.sprite_area->first))->size; @@ -339,11 +332,6 @@ void add_graphic(struct content *content, struct box *box, break; } - if (sprite_length == -1 && content->type == CONTENT_JPEG) { - add_jpeg(content, box, cbc, x, y); - return; - } - dro = xcalloc((unsigned)8 + 16 + sprite_length, sizeof(char)); ds = xcalloc((unsigned)16 + sprite_length, sizeof(char)); @@ -387,54 +375,6 @@ void add_graphic(struct content *content, struct box *box, xfree(dro); } -/** - * Add jpeg objects which the OS can cope with. - * Jpegs the OS doesn't understand are added as sprites - * This may still be a little buggy. - */ -void add_jpeg(struct content *content, struct box *box, - unsigned long cbc, long x, long y) { - - drawfile_object *dro = xcalloc(8+60+((content->source_size+3)/4*4), sizeof(char)); - drawfile_jpeg *dj = xcalloc(60+((content->source_size+3)/4*4), sizeof(char)); - int flags; - - dj->bbox.x0 = x+(box->padding[LEFT]*512); - dj->bbox.y0 = y-((box->padding[TOP] + box->height)*512); - dj->bbox.x1 = x+((box->padding[LEFT] + box->width)*512); - dj->bbox.y1 = y-(box->padding[TOP]*512); - - xjpeginfo_dimensions((jpeg_image const*)content->source_data, - (int)content->source_size, - &flags, &dj->width, &dj->height, - &dj->xdpi, &dj->ydpi, 0); - dj->width *= 512; - dj->height *= 512; - if (flags & 4) { /* pixel density is a ratio */ - dj->ydpi = 90 * (dj->ydpi / dj->xdpi); - dj->xdpi = 90; - } - dj->trfm.entries[0][0] = (dj->width*256) / ((dj->bbox.x1-dj->bbox.x0)/256); - dj->trfm.entries[0][1] = 0; - dj->trfm.entries[1][0] = 0; - dj->trfm.entries[1][1] = (dj->height*256) / ((dj->bbox.y1-dj->bbox.y0)/256); - dj->trfm.entries[2][0] = dj->bbox.x0; - dj->trfm.entries[2][1] = dj->bbox.y0; - dj->len = content->source_size; - memcpy((char*)&dj->image, content->source_data, (unsigned)dj->len); - - dro->type = drawfile_TYPE_JPEG; - dro->size = 8 + 60 + ((dj->len+3)/4*4); - memcpy((char*)&dro->data.jpeg, dj, (unsigned)dro->size-8); - - d = xrealloc(d, length+dro->size); - memcpy((char*)d+length, dro, (unsigned)dro->size); - - length += dro->size; - - xfree(dj); - xfree(dro); -} /** * Add a filled, borderless rectangle to the diagram -- cgit v1.2.3