diff options
author | Michael Drake <tlsa@netsurf-browser.org> | 2022-03-27 13:25:37 +0100 |
---|---|---|
committer | Michael Drake <tlsa@netsurf-browser.org> | 2022-03-27 13:25:37 +0100 |
commit | d0da09a7ca5a2b7878c0af4aab86efaf38d628ac (patch) | |
tree | c311690ce96703affda4df4da7407bbacf0b223b /content/handlers/image | |
parent | bbfc0ca353bb6a0b6a5ec50044c5c3f8bd714c12 (diff) | |
download | netsurf-d0da09a7ca5a2b7878c0af4aab86efaf38d628ac.tar.gz netsurf-d0da09a7ca5a2b7878c0af4aab86efaf38d628ac.tar.bz2 |
Image: JPEG: Decode to client bitmap format where possible.
Diffstat (limited to 'content/handlers/image')
-rw-r--r-- | content/handlers/image/jpeg.c | 176 |
1 files changed, 125 insertions, 51 deletions
diff --git a/content/handlers/image/jpeg.c b/content/handlers/image/jpeg.c index 7d635f90c..e07fb47bb 100644 --- a/content/handlers/image/jpeg.c +++ b/content/handlers/image/jpeg.c @@ -161,6 +161,94 @@ static void nsjpeg_error_exit(j_common_ptr cinfo) } /** + * Convert scan lines from CMYK to core client bitmap layout. + */ +static inline void nsjpeg__decode_cmyk( + struct jpeg_decompress_struct *cinfo, + uint8_t * volatile pixels, + size_t rowstride) +{ + int width = cinfo->output_width * 4; + + do { + JSAMPROW scanlines[1] = { + [0] = (JSAMPROW) + (pixels + rowstride * cinfo->output_scanline), + }; + jpeg_read_scanlines(cinfo, scanlines, 1); + + for (int i = width - 4; 0 <= i; i -= 4) { + /* Trivial inverse CMYK -> RGBA */ + const int c = scanlines[0][i + 0]; + const int m = scanlines[0][i + 1]; + const int y = scanlines[0][i + 2]; + const int k = scanlines[0][i + 3]; + + const int ck = c * k; + const int mk = m * k; + const int yk = y * k; + +#define DIV255(x) ((x) + 1 + ((x) >> 8)) >> 8 + scanlines[0][i + bitmap_layout.r] = DIV255(ck); + scanlines[0][i + bitmap_layout.g] = DIV255(mk); + scanlines[0][i + bitmap_layout.b] = DIV255(yk); + scanlines[0][i + bitmap_layout.a] = 0xff; +#undef DIV255 + } + } while (cinfo->output_scanline != cinfo->output_height); +} + +/** + * Convert scan lines from CMYK to core client bitmap layout. + */ +static inline void nsjpeg__decode_rgb( + struct jpeg_decompress_struct *cinfo, + uint8_t * volatile pixels, + size_t rowstride) +{ + int width = cinfo->output_width; + + do { + JSAMPROW scanlines[1] = { + [0] = (JSAMPROW) + (pixels + rowstride * cinfo->output_scanline), + }; + jpeg_read_scanlines(cinfo, scanlines, 1); + +#if RGB_RED != 0 || RGB_GREEN != 1 || RGB_BLUE != 2 || RGB_PIXELSIZE != 4 + /* Missmatch between configured libjpeg pixel format and + * NetSurf pixel format. Convert to RGBA */ + for (int i = width - 1; 0 <= i; i--) { + int r = scanlines[0][i * RGB_PIXELSIZE + RGB_RED]; + int g = scanlines[0][i * RGB_PIXELSIZE + RGB_GREEN]; + int b = scanlines[0][i * RGB_PIXELSIZE + RGB_BLUE]; + scanlines[0][i * 4 + bitmap_layout.r] = r; + scanlines[0][i * 4 + bitmap_layout.g] = g; + scanlines[0][i * 4 + bitmap_layout.b] = b; + scanlines[0][i * 4 + bitmap_layout.a] = 0xff; + } +#endif + } while (cinfo->output_scanline != cinfo->output_height); +} + +/** + * Convert scan lines from CMYK to core client bitmap layout. + */ +static inline void nsjpeg__decode_client_fmt( + struct jpeg_decompress_struct *cinfo, + uint8_t * volatile pixels, + size_t rowstride) +{ + do { + JSAMPROW scanlines[1] = { + [0] = (JSAMPROW) + (pixels + rowstride * cinfo->output_scanline), + }; + jpeg_read_scanlines(cinfo, scanlines, 1); + } while (cinfo->output_scanline != cinfo->output_height); +} + +/** * create a bitmap from jpeg content. */ static struct bitmap * @@ -171,8 +259,6 @@ jpeg_cache_convert(struct content *c) struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; jmp_buf setjmp_buffer; - unsigned int height; - unsigned int width; struct bitmap * volatile bitmap = NULL; uint8_t * volatile pixels = NULL; size_t rowstride; @@ -217,21 +303,42 @@ jpeg_cache_convert(struct content *c) /* set output processing parameters */ if (cinfo.jpeg_color_space == JCS_CMYK || - cinfo.jpeg_color_space == JCS_YCCK) { + cinfo.jpeg_color_space == JCS_YCCK) { cinfo.out_color_space = JCS_CMYK; } else { +#ifdef JCS_ALPHA_EXTENSIONS + switch (bitmap_fmt.layout) { + case BITMAP_LAYOUT_R8G8B8A8: + cinfo.out_color_space = JCS_EXT_RGBA; + break; + case BITMAP_LAYOUT_B8G8R8A8: + cinfo.out_color_space = JCS_EXT_BGRA; + break; + case BITMAP_LAYOUT_A8R8G8B8: + cinfo.out_color_space = JCS_EXT_ARGB; + break; + case BITMAP_LAYOUT_A8B8G8R8: + cinfo.out_color_space = JCS_EXT_ABGR; + break; + default: + NSLOG(netsurf, ERROR, "Unexpected bitmap format: %u", + bitmap_fmt.layout); + jpeg_destroy_decompress(&cinfo); + return NULL; + } +#else cinfo.out_color_space = JCS_RGB; +#endif } cinfo.dct_method = JDCT_ISLOW; /* commence the decompression, output parameters now valid */ jpeg_start_decompress(&cinfo); - width = cinfo.output_width; - height = cinfo.output_height; - /* create opaque bitmap (jpegs cannot be transparent) */ - bitmap = guit->bitmap->create(width, height, BITMAP_OPAQUE); + bitmap = guit->bitmap->create( + cinfo.output_width, + cinfo.output_height, BITMAP_OPAQUE); if (bitmap == NULL) { /* empty bitmap could not be created */ jpeg_destroy_decompress(&cinfo); @@ -248,54 +355,21 @@ jpeg_cache_convert(struct content *c) /* Convert scanlines from jpeg into bitmap */ rowstride = guit->bitmap->get_rowstride(bitmap); - do { - JSAMPROW scanlines[1]; - - scanlines[0] = (JSAMPROW) (pixels + - rowstride * cinfo.output_scanline); - jpeg_read_scanlines(&cinfo, scanlines, 1); - if (cinfo.out_color_space == JCS_CMYK) { - int i; - for (i = width - 1; 0 <= i; i--) { - /* Trivial inverse CMYK -> RGBA */ - const int c = scanlines[0][i * 4 + 0]; - const int m = scanlines[0][i * 4 + 1]; - const int y = scanlines[0][i * 4 + 2]; - const int k = scanlines[0][i * 4 + 3]; + switch (cinfo.out_color_space) { + case JCS_CMYK: + nsjpeg__decode_cmyk(&cinfo, pixels, rowstride); + break; - const int ck = c * k; - const int mk = m * k; - const int yk = y * k; + case JCS_RGB: + nsjpeg__decode_rgb(&cinfo, pixels, rowstride); + break; -#define DIV255(x) ((x) + 1 + ((x) >> 8)) >> 8 - scanlines[0][i * 4 + 0] = DIV255(ck); - scanlines[0][i * 4 + 1] = DIV255(mk); - scanlines[0][i * 4 + 2] = DIV255(yk); - scanlines[0][i * 4 + 3] = 0xff; -#undef DIV255 - } - } else { -#if RGB_RED != 0 || RGB_GREEN != 1 || RGB_BLUE != 2 || RGB_PIXELSIZE != 4 - /* Missmatch between configured libjpeg pixel format and - * NetSurf pixel format. Convert to RGBA */ - int i; - for (i = width - 1; 0 <= i; i--) { - int r = scanlines[0][i * RGB_PIXELSIZE + RGB_RED]; - int g = scanlines[0][i * RGB_PIXELSIZE + RGB_GREEN]; - int b = scanlines[0][i * RGB_PIXELSIZE + RGB_BLUE]; - scanlines[0][i * 4 + 0] = r; - scanlines[0][i * 4 + 1] = g; - scanlines[0][i * 4 + 2] = b; - scanlines[0][i * 4 + 3] = 0xff; - } -#endif - } - } while (cinfo.output_scanline != cinfo.output_height); + default: + nsjpeg__decode_client_fmt(&cinfo, pixels, rowstride); + break; + } - bitmap_format_to_client(bitmap, &(bitmap_fmt_t) { - .layout = BITMAP_LAYOUT_R8G8B8A8, - }); guit->bitmap->modified(bitmap); jpeg_finish_decompress(&cinfo); |