From 1f438d82b40310f7261fe3a48d0b00e3d796c436 Mon Sep 17 00:00:00 2001 From: Alexander Egorov Date: Thu, 13 Mar 2008 01:04:19 +0100 Subject: [PATCH] png support --- makefiles/arch/desktop.mk | 2 +- makefiles/arch/lbook.mk | 2 +- zlibrary/ui/src/nanox/image/ZLNXImageManager.cpp | 369 ++++++++++++++++------- zlibrary/ui/src/nanox/image/ZLNXImageManager.h | 2 + 4 files changed, 267 insertions(+), 108 deletions(-) diff --git a/makefiles/arch/desktop.mk b/makefiles/arch/desktop.mk index 6204bce..3061d6c 100644 --- a/makefiles/arch/desktop.mk +++ b/makefiles/arch/desktop.mk @@ -36,7 +36,7 @@ ifeq "$(UI_TYPE)" "gtk" endif ifeq "$(UI_TYPE)" "nanox" - UILIBS = -ljpeg -lrt -L$(ROOTDIR)/v3/i386/lib -lfreetype + UILIBS = -ljpeg -lpng -lrt -L$(ROOTDIR)/v3/i386/lib -lfreetype NXINCLUDE = -I$(ROOTDIR)/v3/include/ ZLSHARED = no endif diff --git a/makefiles/arch/lbook.mk b/makefiles/arch/lbook.mk index 24aa426..6037570 100644 --- a/makefiles/arch/lbook.mk +++ b/makefiles/arch/lbook.mk @@ -14,7 +14,7 @@ CFLAGS = -pipe -fno-exceptions -Wall -Wno-ctor-dtor-privacy -W -DLIBICONV_PLUG - LDFLAGS = ifeq "$(UI_TYPE)" "nanox" - UILIBS = -L$(ROOTDIR)/v3/arm/lib -lfreetype -lrt -lpthread -ljpeg + UILIBS = -L$(ROOTDIR)/v3/arm/lib -lfreetype -lrt -lpthread -ljpeg -lpng NXINCLUDE = -I$(ROOTDIR)/v3/include/ EXTERNALINCLUDE = -I$(ROOTDIR)/v3/include/ ZLSHARED = no diff --git a/zlibrary/ui/src/nanox/image/ZLNXImageManager.cpp b/zlibrary/ui/src/nanox/image/ZLNXImageManager.cpp index a22882f..454ef60 100644 --- a/zlibrary/ui/src/nanox/image/ZLNXImageManager.cpp +++ b/zlibrary/ui/src/nanox/image/ZLNXImageManager.cpp @@ -1,7 +1,7 @@ /* * Copyright (C) 2008 Alexander Egorov * - * dithering algorithm from coolreader engine + * dithering algorithm and jpeg/png handling are from coolreader engine * Copyright (C) Vadim Lopatin, 2000-2006 * * @@ -31,118 +31,152 @@ extern "C" { #include } +#include + + static const short dither_2bpp_8x8[] = { -0, 32, 12, 44, 2, 34, 14, 46, -48, 16, 60, 28, 50, 18, 62, 30, -8, 40, 4, 36, 10, 42, 6, 38, -56, 24, 52, 20, 58, 26, 54, 22, -3, 35, 15, 47, 1, 33, 13, 45, -51, 19, 63, 31, 49, 17, 61, 29, -11, 43, 7, 39, 9, 41, 5, 37, -59, 27, 55, 23, 57, 25, 53, 21, + 0, 32, 12, 44, 2, 34, 14, 46, + 48, 16, 60, 28, 50, 18, 62, 30, + 8, 40, 4, 36, 10, 42, 6, 38, + 56, 24, 52, 20, 58, 26, 54, 22, + 3, 35, 15, 47, 1, 33, 13, 45, + 51, 19, 63, 31, 49, 17, 61, 29, + 11, 43, 7, 39, 9, 41, 5, 37, + 59, 27, 55, 23, 57, 25, 53, 21, }; int Dither2BitColor( int color, int x, int y ) { - int cl = ((((color>>16) & 255) + ((color>>8) & 255) + ((color) & 255)) * (256/3)) >> 8; - if (cl<5) - return 0; - else if (cl>=250) - return 3<<6; - int d = dither_2bpp_8x8[(x&7) | ( (y&7) << 3 )] - 1; - - cl = ( cl + d - 32 ); - if (cl<5) - return 0; - else if (cl>=250) - return 3<<6; - return cl & 0xc0; + int cl = ((((color>>16) & 255) + ((color>>8) & 255) + ((color) & 255)) * (256/3)) >> 8; + if (cl<5) + return 0; + else if (cl>=250) + return 3<<6; + int d = dither_2bpp_8x8[(x&7) | ( (y&7) << 3 )] - 1; + + cl = ( cl + d - 32 ); + if (cl<5) + return 0; + else if (cl>=250) + return 3<<6; + return cl & 0xc0; } typedef struct { - struct jpeg_source_mgr pub; /* public fields */ + struct jpeg_source_mgr pub; /* public fields */ int len; - JOCTET *buffer; /* start of buffer */ - bool start_of_file; /* have we gotten any data yet? */ + JOCTET *buffer; /* start of buffer */ + bool start_of_file; /* have we gotten any data yet? */ } my_jpeg_source_mgr; struct my_error_mgr { - struct jpeg_error_mgr pub; /* "public" fields */ - - jmp_buf setjmp_buffer; /* for return to caller */ + struct jpeg_error_mgr pub; /* "public" fields */ + jmp_buf setjmp_buffer; /* for return to caller */ }; typedef struct my_error_mgr * my_error_ptr; void my_jpeg_error (j_common_ptr cinfo) { - printf("jpeg error huj\n"); - my_error_ptr myerr = (my_error_ptr) cinfo->err; + my_error_ptr myerr = (my_error_ptr) cinfo->err; - char buffer[JMSG_LENGTH_MAX]; + char buffer[JMSG_LENGTH_MAX]; - /* Create the message */ - (*cinfo->err->format_message) (cinfo, buffer); - - fprintf( stderr, "message: %s\n", buffer ); - - /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ - //my_error_ptr myerr = (my_error_ptr) cinfo->err; + /* Create the message */ + (*cinfo->err->format_message) (cinfo, buffer); - /* Always display the message. */ - /* We could postpone this until after returning, if we chose. */ - (*cinfo->err->output_message) (cinfo); + /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ + //my_error_ptr myerr = (my_error_ptr) cinfo->err; - /* Return control to the setjmp point */ - longjmp(myerr->setjmp_buffer, 1); + /* Always display the message. */ + /* We could postpone this until after returning, if we chose. */ + (*cinfo->err->output_message) (cinfo); + + /* Return control to the setjmp point */ + longjmp(myerr->setjmp_buffer, 1); } void my_init_source (j_decompress_ptr cinfo) { - printf("init_source\n"); - my_jpeg_source_mgr * src = (my_jpeg_source_mgr*) cinfo->src; - src->start_of_file = true; + my_jpeg_source_mgr * src = (my_jpeg_source_mgr*) cinfo->src; + src->start_of_file = true; } boolean my_fill_input_buffer (j_decompress_ptr cinfo) { - printf("my_fill_input_buffer\n"); - - my_jpeg_source_mgr * src = (my_jpeg_source_mgr *) cinfo->src; + my_jpeg_source_mgr * src = (my_jpeg_source_mgr *) cinfo->src; - src->pub.next_input_byte = src->buffer; - src->pub.bytes_in_buffer = src->len; + src->pub.next_input_byte = src->buffer; + src->pub.bytes_in_buffer = src->len; - src->start_of_file = false; + src->start_of_file = false; - return true; + return true; } -void my_skip_input_data (j_decompress_ptr cinfo, long num_bytes) { - printf("my_skip_input_data %d\n", num_bytes); - my_jpeg_source_mgr * src = (my_jpeg_source_mgr *) cinfo->src; - src->pub.next_input_byte += num_bytes; - src->pub.bytes_in_buffer -= num_bytes; +void my_skip_input_data (j_decompress_ptr cinfo, long num_bytes) +{ + my_jpeg_source_mgr * src = (my_jpeg_source_mgr *) cinfo->src; + src->pub.next_input_byte += num_bytes; + src->pub.bytes_in_buffer -= num_bytes; } -boolean my_resync_to_restart (j_decompress_ptr cinfo, int desired) { - printf("my_resync_to_restart\n"); +boolean my_resync_to_restart (j_decompress_ptr cinfo, int desired) +{ return false; } -void my_term_source (j_decompress_ptr cinfo) { - printf("my_term_source\n"); +void my_term_source (j_decompress_ptr cinfo) +{ + my_jpeg_source_mgr * src = (my_jpeg_source_mgr *) cinfo->src; + if ( src && src->buffer ) + { + delete[] src->buffer; + src->buffer = NULL; + } + if(src) + delete src; } -void + void my_jpeg_src_free (j_decompress_ptr cinfo) { - my_jpeg_source_mgr * src = (my_jpeg_source_mgr *) cinfo->src; - if ( src && src->buffer ) - { - delete[] src->buffer; - src->buffer = NULL; - } - delete src; + my_jpeg_source_mgr * src = (my_jpeg_source_mgr *) cinfo->src; + if ( src && src->buffer ) + { + delete[] src->buffer; + src->buffer = NULL; + } + delete src; +} + +struct s_my_png { + char *p; + int size; +}; + +static void mypng_error_func (png_structp png, png_const_charp msg) +{ + longjmp(png_jmpbuf(png), 1); +} + +static void mypng_warning_func (png_structp png, png_const_charp msg) +{ + longjmp(png_jmpbuf(png), 1); +} + +static void mypng_read_func(png_structp png, png_bytep buf, png_size_t len) +{ + struct s_my_png *obj = (struct s_my_png *) png_get_io_ptr(png); + size_t bytesRead = obj->size; + + if(bytesRead >= len) + bytesRead = len; + else + longjmp(png_jmpbuf(png), 1); + + memcpy(buf, (const unsigned char*)obj->p, bytesRead); + obj->p += bytesRead; + obj->size -= bytesRead; } @@ -226,23 +260,46 @@ shared_ptr ZLNXImageManager::createData() const { void ZLNXImageManager::convertImageDirect(const std::string &stringData, ZLImageData &data) const { + printf("convertImageDirect\n"); + + unsigned char m0, m1; + m0 = *(stringData.data()); + m1 = *(stringData.data()+1); + if((m0 == 0xff) && (m1 == 0xd8)) + convertImageDirectJpeg(stringData, data); + else if(!png_sig_cmp((unsigned char *)stringData.data(), (png_size_t)0, 4) ) + convertImageDirectPng(stringData, data); + else { + printf("unsupported image format: %d %d\n", m0, m1); + + /* FILE *f; + f = fopen("/tmp/unknown_img", "w+"); + fwrite(stringData.data(), 1, stringData.length(), f); + fclose(f); + + printf("image dumped to /tmp/unknown_img\n"); + */ + + data.init(1, 1); + + return; + } +} + +void ZLNXImageManager::convertImageDirectJpeg(const std::string &stringData, ZLImageData &data) const { struct jpeg_decompress_struct cinfo; - JSAMPARRAY buffer; /* Output row buffer */ + JSAMPARRAY buffer; /* Output row buffer */ int row_stride; /* physical row width in output buffer */ - printf("=> %d\n", sizeof(struct jpeg_decompress_struct)); - - struct my_error_mgr jerr; + struct my_error_mgr jerr; jpeg_create_decompress(&cinfo); - jpeg_error_mgr errmgr; cinfo.err = jpeg_std_error(&errmgr); errmgr.error_exit = my_jpeg_error; - /* Establish the setjmp return context for my_error_exit to use. */ if (setjmp(jerr.setjmp_buffer)) { /* If we get here, the JPEG code has signaled an error. @@ -254,8 +311,7 @@ void ZLNXImageManager::convertImageDirect(const std::string &stringData, ZLImage return; } - - my_jpeg_source_mgr *src; + my_jpeg_source_mgr *src; src = (my_jpeg_source_mgr *) new my_jpeg_source_mgr; cinfo.src = (struct jpeg_source_mgr *) src; @@ -263,43 +319,42 @@ void ZLNXImageManager::convertImageDirect(const std::string &stringData, ZLImage src->len = stringData.length() + 2; src->buffer = new JOCTET[src->len]; - - printf("len: %d\n", stringData.length()); memcpy(src->buffer, (const unsigned char*)stringData.data(), stringData.length()); - src->buffer[stringData.length()] = (JOCTET) 0xFF; - src->buffer[stringData.length() + 1] = (JOCTET) JPEG_EOI; - - src->pub.init_source = my_init_source; - src->pub.fill_input_buffer = my_fill_input_buffer; - src->pub.skip_input_data = my_skip_input_data; - src->pub.resync_to_restart = my_resync_to_restart; - src->pub.term_source = my_term_source; - src->pub.bytes_in_buffer = src->len; - src->pub.next_input_byte = src->buffer; - + src->buffer[stringData.length()] = (JOCTET) 0xFF; + src->buffer[stringData.length() + 1] = (JOCTET) JPEG_EOI; + + src->pub.init_source = my_init_source; + src->pub.fill_input_buffer = my_fill_input_buffer; + src->pub.skip_input_data = my_skip_input_data; + src->pub.resync_to_restart = my_resync_to_restart; + src->pub.term_source = my_term_source; + src->pub.bytes_in_buffer = src->len; + src->pub.next_input_byte = src->buffer; + (void) jpeg_read_header(&cinfo, true); data.init(cinfo.image_width, cinfo.image_height); - cinfo.out_color_space = JCS_RGB; -// cinfo.out_color_space = JCS_GRAYSCALE; + cinfo.out_color_space = JCS_RGB; + // cinfo.out_color_space = JCS_GRAYSCALE; (void) jpeg_start_decompress(&cinfo); - + row_stride = cinfo.output_width * cinfo.output_components; - buffer = (*cinfo.mem->alloc_sarray) + buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); + char *p, *c; + int pixel, s, j; while (cinfo.output_scanline < cinfo.output_height) { (void) jpeg_read_scanlines(&cinfo, buffer, 1); - char *p = (char*)buffer[0]; - char *c; - int pixel, s; - int j = cinfo.output_scanline; + p = (char*)buffer[0]; + j = cinfo.output_scanline; + for(int i = 0; i < cinfo.output_width; i++) { - pixel = Dither2BitColor( + pixel = Dither2BitColor( p[0] << 16 | p[1] << 8 | p[2] << 0, i, j); @@ -313,13 +368,115 @@ void ZLNXImageManager::convertImageDirect(const std::string &stringData, ZLImage } } - (void) jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); +} - if(src->buffer) - delete[] src->buffer; - if(src) - delete src; +void ZLNXImageManager::convertImageDirectPng(const std::string &stringData, ZLImageData &data) const { + struct s_my_png my_png; + my_png.p = (char*)stringData.data(); + my_png.size = stringData.length(); - jpeg_destroy_decompress(&cinfo); + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; + unsigned int *row = NULL; + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, + (png_voidp)&my_png, mypng_error_func, mypng_warning_func); + if ( !png_ptr ) + return; + + if (setjmp( png_ptr->jmpbuf )) { + data.init(0, 0); + if (png_ptr) + { + png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); + } + if ( row ) + delete row; + return; + } + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + mypng_error_func(png_ptr, "cannot create png info struct"); + png_set_read_fn(png_ptr, + (voidp)&my_png, mypng_read_func); + png_read_info( png_ptr, info_ptr ); + + + png_uint_32 width, height; + int bit_depth, color_type, interlace_type; + png_get_IHDR(png_ptr, info_ptr, &width, &height, + &bit_depth, &color_type, &interlace_type, + NULL, NULL); + + data.init(width, height); + + row = new unsigned int[ width ]; + + // SET TRANSFORMS + if (color_type & PNG_COLOR_MASK_PALETTE) + png_set_palette_to_rgb(png_ptr); + + if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) + png_set_gray_1_2_4_to_8(png_ptr); + + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_tRNS_to_alpha(png_ptr); + + if (bit_depth == 16) + png_set_strip_16(png_ptr); + + png_set_invert_alpha(png_ptr); + + if (bit_depth < 8) + png_set_packing(png_ptr); + + //if (color_type == PNG_COLOR_TYPE_RGB) + png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); + + //if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) + // png_set_swap_alpha(png_ptr); + + if (color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png_ptr); + + int number_passes = png_set_interlace_handling(png_ptr); + //if (color_type == PNG_COLOR_TYPE_RGB_ALPHA || + // color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + + //if (color_type == PNG_COLOR_TYPE_RGB || + // color_type == PNG_COLOR_TYPE_RGB_ALPHA) + png_set_bgr(png_ptr); + + + char *c; + unsigned int *p; + int pixel, s; + for(int pass = 0; pass < number_passes; pass++) { + for(int y = 0; y < height; y++) { + + png_read_rows(png_ptr, (unsigned char **)&row, png_bytepp_NULL, 1); + + p = row; + + for(int i = 0; i < width; i++) { + pixel = Dither2BitColor(*p, i, y); + + c = ((ZLNXImageData&)data).getImageData() + i / 4 + width * y / 4; + s = (i & 3) << 1; + + *c &= ~(0xc0 >> s); + *c |= (pixel >> s); + + p++; + } + } + } + + png_read_end(png_ptr, info_ptr); + + png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); } diff --git a/zlibrary/ui/src/nanox/image/ZLNXImageManager.h b/zlibrary/ui/src/nanox/image/ZLNXImageManager.h index b633856..d1ba9c6 100644 --- a/zlibrary/ui/src/nanox/image/ZLNXImageManager.h +++ b/zlibrary/ui/src/nanox/image/ZLNXImageManager.h @@ -67,6 +67,8 @@ class ZLNXImageManager : public ZLImageManager { protected: shared_ptr createData() const; void convertImageDirect(const std::string &stringData, ZLImageData &imageData) const; + void convertImageDirectJpeg(const std::string &stringData, ZLImageData &imageData) const; + void convertImageDirectPng(const std::string &stringData, ZLImageData &imageData) const; }; #endif /* __ZLNXIMAGEMANAGER_H__ */ -- 2.11.4.GIT