From b8238f7b20d401926640824342fe11ff92c6fcf0 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Wed, 9 Oct 2024 19:39:15 +0300 Subject: imageviewer: Initial support for JPEG progressive images. Add decoder Added jpeg decoder jpegp.c using RAINBOW lib. Currently enabled only for pictures not supported by old decoder (as old decoder more optimized for low mem targets) Someone TODO: * Old decoder has optimized downscale logic which new decoder doesn't have (it gives big difference in required memory and time for decoding). This logic should be ported/adapted if possible. * Add smooth downscaling. * Grayscale support Change-Id: Ie96bc62848b51cc6a3942f8e069ec6ab02dc1c56 --- apps/plugins/CATEGORIES | 1 + apps/plugins/imageviewer/SUBDIRS | 1 + apps/plugins/imageviewer/image_decoder.c | 5 +- apps/plugins/imageviewer/image_decoder.h | 2 + apps/plugins/imageviewer/imageviewer.c | 9 + apps/plugins/imageviewer/imageviewer.h | 1 + apps/plugins/imageviewer/jpeg/jpeg.c | 4 + apps/plugins/imageviewer/jpegp/BUFFILEGETC.c | 94 ++++++++++ apps/plugins/imageviewer/jpegp/FILEGETC.c | 71 ++++++++ apps/plugins/imageviewer/jpegp/GETC.h | 14 +- apps/plugins/imageviewer/jpegp/SOURCES | 6 + apps/plugins/imageviewer/jpegp/jpeg81.c | 24 +-- apps/plugins/imageviewer/jpegp/jpeg81.h | 2 +- apps/plugins/imageviewer/jpegp/jpegp.c | 260 +++++++++++++++++++++++++++ apps/plugins/imageviewer/jpegp/jpegp.make | 32 ++++ apps/plugins/imageviewer/jpegp/mempool.c | 50 ++++++ apps/plugins/imageviewer/jpegp/mempool.h | 7 + apps/plugins/imageviewer/jpegp/rb_glue.h | 35 ++++ manual/plugins/imageviewer.tex | 3 +- 19 files changed, 599 insertions(+), 22 deletions(-) create mode 100644 apps/plugins/imageviewer/jpegp/BUFFILEGETC.c create mode 100644 apps/plugins/imageviewer/jpegp/FILEGETC.c create mode 100644 apps/plugins/imageviewer/jpegp/SOURCES create mode 100644 apps/plugins/imageviewer/jpegp/jpegp.c create mode 100644 apps/plugins/imageviewer/jpegp/jpegp.make create mode 100644 apps/plugins/imageviewer/jpegp/mempool.c create mode 100644 apps/plugins/imageviewer/jpegp/mempool.h create mode 100644 apps/plugins/imageviewer/jpegp/rb_glue.h diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES index 79186b7aed..aa7dbf38e5 100644 --- a/apps/plugins/CATEGORIES +++ b/apps/plugins/CATEGORIES @@ -51,6 +51,7 @@ iriverify,viewers jackpot,games jewels,games jpeg,viewers +jpegp,viewers keybox,apps keyremap,apps lamp,apps diff --git a/apps/plugins/imageviewer/SUBDIRS b/apps/plugins/imageviewer/SUBDIRS index 1f7b4d8b52..ea7c304218 100644 --- a/apps/plugins/imageviewer/SUBDIRS +++ b/apps/plugins/imageviewer/SUBDIRS @@ -3,5 +3,6 @@ jpeg png #ifdef HAVE_LCD_COLOR ppm +jpegp #endif gif diff --git a/apps/plugins/imageviewer/image_decoder.c b/apps/plugins/imageviewer/image_decoder.c index 0c1776daaa..c481899bae 100644 --- a/apps/plugins/imageviewer/image_decoder.c +++ b/apps/plugins/imageviewer/image_decoder.c @@ -25,12 +25,13 @@ static const char *decoder_names[MAX_IMAGE_TYPES] = { "bmp", - "jpeg", + "jpeg", // Default decoder for jpeg: Use jpeg for old decoder, jpegp for new "png", #ifdef HAVE_LCD_COLOR "ppm", #endif - "gif" + "gif", + "jpegp", }; /* Check file type by magic number or file extension diff --git a/apps/plugins/imageviewer/image_decoder.h b/apps/plugins/imageviewer/image_decoder.h index c27ed33e8e..7a9cd5d06c 100644 --- a/apps/plugins/imageviewer/image_decoder.h +++ b/apps/plugins/imageviewer/image_decoder.h @@ -33,6 +33,8 @@ enum image_type { IMAGE_PPM, #endif IMAGE_GIF, + IMAGE_JPEG_PROGRESSIVE, + MAX_IMAGE_TYPES }; diff --git a/apps/plugins/imageviewer/imageviewer.c b/apps/plugins/imageviewer/imageviewer.c index b849812508..ba5f8fec16 100644 --- a/apps/plugins/imageviewer/imageviewer.c +++ b/apps/plugins/imageviewer/imageviewer.c @@ -853,6 +853,8 @@ static int load_and_show(char* filename, struct image_info *info) file_pt[curfile] = NULL; return change_filename(direction); } + +reload_decoder: if (image_type != status) /* type of image is changed, load decoder. */ { struct loader_info loader_info = { @@ -881,6 +883,13 @@ static int load_and_show(char* filename, struct image_info *info) else status = imgdec->load_image(filename, info, buf, &remaining); + if (status == PLUGIN_JPEG_PROGRESSIVE) + { + rb->lcd_clear_display(); + status = IMAGE_JPEG_PROGRESSIVE; + goto reload_decoder; + } + if (status == PLUGIN_OUTOFMEM) { #ifdef USE_PLUG_BUF diff --git a/apps/plugins/imageviewer/imageviewer.h b/apps/plugins/imageviewer/imageviewer.h index ac15df5960..44e56c0696 100644 --- a/apps/plugins/imageviewer/imageviewer.h +++ b/apps/plugins/imageviewer/imageviewer.h @@ -55,6 +55,7 @@ enum { PLUGIN_OTHER = 0x200, PLUGIN_ABORT, PLUGIN_OUTOFMEM, + PLUGIN_JPEG_PROGRESSIVE, ZOOM_IN, ZOOM_OUT, diff --git a/apps/plugins/imageviewer/jpeg/jpeg.c b/apps/plugins/imageviewer/jpeg/jpeg.c index 3d8c9c3ac8..c231209beb 100644 --- a/apps/plugins/imageviewer/jpeg/jpeg.c +++ b/apps/plugins/imageviewer/jpeg/jpeg.c @@ -170,8 +170,12 @@ static int load_image(char *filename, struct image_info *info, if (status < 0 || (status & (DQT | SOF0)) != (DQT | SOF0)) { /* bad format or minimum components not contained */ +#ifndef HAVE_LCD_COLOR rb->splashf(HZ, "unsupported %d", status); return PLUGIN_ERROR; +#else + return PLUGIN_JPEG_PROGRESSIVE; +#endif } if (!(status & DHT)) /* if no Huffman table present: */ diff --git a/apps/plugins/imageviewer/jpegp/BUFFILEGETC.c b/apps/plugins/imageviewer/jpegp/BUFFILEGETC.c new file mode 100644 index 0000000000..5124636731 --- /dev/null +++ b/apps/plugins/imageviewer/jpegp/BUFFILEGETC.c @@ -0,0 +1,94 @@ +/* Simple buffered version of file reader. + * JPEG decoding seems to work faster with it. + * Not fully tested. In case of any issues try FILEGETC (see SOURCES) + * */ +#include "rb_glue.h" + +static int fd; +static unsigned char buff[256]; //TODO: Adjust it... +static int length = 0; +static int cur_buff_pos = 0; +static int file_pos = 0; + +extern int GETC(void) +{ + if (cur_buff_pos >= length) + { + length = rb->read(fd, buff, sizeof(buff)); + file_pos += length; + cur_buff_pos = 0; + } + + return buff[cur_buff_pos++]; +} + +// multibyte readers: host-endian independent - if evaluated in right order (ie. don't optimize) + +extern int GETWbi(void) // 16-bit big-endian +{ + return ( GETC()<<8 ) | GETC(); +} + +extern int GETDbi(void) // 32-bit big-endian +{ + return ( GETC()<<24 ) | ( GETC()<<16 ) | ( GETC()<<8 ) | GETC(); +} + +extern int GETWli(void) // 16-bit little-endian +{ + return GETC() | ( GETC()<<8 ); +} + +extern int GETDli(void) // 32-bit little-endian +{ + return GETC() | ( GETC()<<8 ) | ( GETC()<<16 ) | ( GETC()<<24 ); +} + +// seek + +extern void SEEK(int d) +{ + int newPos = cur_buff_pos + d; + if (newPos < length && newPos >= 0) + { + cur_buff_pos = newPos; + return; + } + file_pos = rb->lseek(fd, (cur_buff_pos - length) + d, SEEK_CUR); + cur_buff_pos = length = 0; +} + +extern void POS(int d) +{ + cur_buff_pos = length = 0; + file_pos = d; + rb->lseek(fd, d, SEEK_SET); +} + +extern int TELL(void) +{ + return file_pos + cur_buff_pos - length; +} + +// OPEN/CLOSE file + +extern void *OPEN(char *f) +{ + printf("Opening %s\n", f); + cur_buff_pos = length = file_pos = 0; + fd = rb->open(f,O_RDONLY); + + if ( fd < 0 ) + { + printf("Error opening %s\n", f); + return NULL; + } + + return &fd; +} + +extern int CLOSE(void) +{ + cur_buff_pos = length = file_pos = 0; + return rb->close(fd); +} diff --git a/apps/plugins/imageviewer/jpegp/FILEGETC.c b/apps/plugins/imageviewer/jpegp/FILEGETC.c new file mode 100644 index 0000000000..bb7f0c485f --- /dev/null +++ b/apps/plugins/imageviewer/jpegp/FILEGETC.c @@ -0,0 +1,71 @@ +#include "rb_glue.h" + +static int fd; + +extern int GETC(void) +{ + unsigned char x; + rb->read(fd, &x, 1); + return x; +} + +// multibyte readers: host-endian independent - if evaluated in right order (ie. don't optimize) + +extern int GETWbi(void) // 16-bit big-endian +{ + return ( GETC()<<8 ) | GETC(); +} + +extern int GETDbi(void) // 32-bit big-endian +{ + return ( GETC()<<24 ) | ( GETC()<<16 ) | ( GETC()<<8 ) | GETC(); +} + +extern int GETWli(void) // 16-bit little-endian +{ + return GETC() | ( GETC()<<8 ); +} + +extern int GETDli(void) // 32-bit little-endian +{ + return GETC() | ( GETC()<<8 ) | ( GETC()<<16 ) | ( GETC()<<24 ); +} + +// seek + +extern void SEEK(int d) +{ + rb->lseek(fd, d, SEEK_CUR); +} + +extern void POS(int d) +{ + rb->lseek(fd, d, SEEK_SET); +} + +extern int TELL(void) +{ + return rb->lseek(fd, 0, SEEK_CUR); +} + +// OPEN/CLOSE file + +extern void *OPEN(char *f) +{ + printf("Opening %s\n", f); + + fd = rb->open(f,O_RDONLY); + + if ( fd < 0 ) + { + printf("Error opening %s\n", f); + return NULL; + } + + return &fd; +} + +extern int CLOSE(void) +{ + return rb->close(fd); +} diff --git a/apps/plugins/imageviewer/jpegp/GETC.h b/apps/plugins/imageviewer/jpegp/GETC.h index d17cdb9857..5e8a3c6a9d 100644 --- a/apps/plugins/imageviewer/jpegp/GETC.h +++ b/apps/plugins/imageviewer/jpegp/GETC.h @@ -37,20 +37,20 @@ // For decoders -extern int GETC(); +extern int GETC(void); // Multibyte helpers -extern int GETWbi(); // read word (16-bit) big-endian -extern int GETWli(); // little-endian -extern int GETDbi(); // read double word (32-bit) big-endian -extern int GETDli(); // little-endian +extern int GETWbi(void); // read word (16-bit) big-endian +extern int GETWli(void); // little-endian +extern int GETDbi(void); // read double word (32-bit) big-endian +extern int GETDli(void); // little-endian // positioning extern void SEEK(int); // move relative to current extern void POS(int); // move absolute position (TIFF) -extern int TELL(); // read actual position +extern int TELL(void); // read actual position // For RAINBOW clients to implement outside of Rainbow Library extern void *OPEN(char*); -extern void CLOSE(); +extern void CLOSE(void); diff --git a/apps/plugins/imageviewer/jpegp/SOURCES b/apps/plugins/imageviewer/jpegp/SOURCES new file mode 100644 index 0000000000..dfaf63a42f --- /dev/null +++ b/apps/plugins/imageviewer/jpegp/SOURCES @@ -0,0 +1,6 @@ +jpegp.c +//FILEGETC.c +BUFFILEGETC.c +jpeg81.c +idct.c +mempool.c \ No newline at end of file diff --git a/apps/plugins/imageviewer/jpegp/jpeg81.c b/apps/plugins/imageviewer/jpegp/jpeg81.c index 95e46dbd17..76b36ca950 100644 --- a/apps/plugins/imageviewer/jpegp/jpeg81.c +++ b/apps/plugins/imageviewer/jpegp/jpeg81.c @@ -40,12 +40,12 @@ jpeg81.c * SOFTWARE. */ -#include "GETC.h" +#include "GETC.h" +#include "rb_glue.h" #include "jpeg81.h" -#include // calloc() called once -#include // debug only - +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" ///////////////////////////////////////// LOSSLESS ///////////////////////////////////////// static int P1(struct COMP *C, TSAMP *samp) // Px = Ra @@ -63,17 +63,17 @@ static int P3(struct COMP *C, TSAMP *samp) // Px = Rc return samp[-C->du_width-1]; } -static int P4(struct COMP *C, TSAMP *samp) // Px = Ra + Rb – Rc +static int P4(struct COMP *C, TSAMP *samp) // Px = Ra + Rb - Rc { return samp[-1] + samp[-C->du_width] - samp[-C->du_width-1]; } -static int P5(struct COMP *C, TSAMP *samp) // Px = Ra + ((Rb – Rc)/2) +static int P5(struct COMP *C, TSAMP *samp) // Px = Ra + ((Rb - Rc)/2) { return samp[-1] + ( (samp[-C->du_width] - samp[-C->du_width-1]) >> 1 ); } -static int P6(struct COMP *C, TSAMP *samp) // Px = Rb + ((Ra – Rc)/2) +static int P6(struct COMP *C, TSAMP *samp) // Px = Rb + ((Ra - Rc)/2) { return samp[-C->du_width] + ( (samp[-1] - samp[-C->du_width-1]) >> 1 ); } @@ -215,7 +215,7 @@ static void du_sequential_huff(struct JPEGD *j, struct COMP *sc, TCOEF *coef) { int s, k; dc_decode_huff(j, sc, coef); - for (k=1; s=sc->ACS[ReadHuffmanCode(j, sc->ACB)]; k++) { // EOB? + for (k=1; (s=sc->ACS[ReadHuffmanCode(j, sc->ACB)]); k++) { // EOB? k+= s>>4; if (s==0xf0) continue; // ZRL coef[k]= ReadDiff(j, s&15); @@ -496,7 +496,7 @@ static void Ri(struct JPEGD *j, int n) printf("RST%d\n", Marker&7); printf("%08X: ECS\n", TELL()); } - else printf("STREAM ERROR: expected RSTn missing from ECS\n"); + else { printf("STREAM ERROR: expected RSTn missing from ECS\n"); } j->Reset_decoder(j); } } @@ -832,7 +832,7 @@ extern enum JPEGENUM JPEGDecode(struct JPEGD *j) } } - printf(" Malloc for %d Data Units (%d bytes)\n\n", TotalDU, sizeof(DU)*TotalDU); + printf(" Malloc for %d Data Units (%lu bytes)\n\n", TotalDU, sizeof(DU)*TotalDU); if (j->SOF > 0xC8) { // DCT Arithmetic j->Reset_decoder= Reset_decoder_arith; @@ -953,7 +953,7 @@ extern enum JPEGENUM JPEGDecode(struct JPEGD *j) for (Lq-=2; Lq; Lq -= 65 + 64*Pq) { - int (*get)(); + int (*get)(void); int T= GETC(); int Tq= T&3; int *qt= j->QT[Tq]; @@ -993,3 +993,5 @@ extern enum JPEGENUM JPEGDecode(struct JPEGD *j) } } } + +#pragma GCC diagnostic pop \ No newline at end of file diff --git a/apps/plugins/imageviewer/jpegp/jpeg81.h b/apps/plugins/imageviewer/jpegp/jpeg81.h index fa71b10113..e265d84926 100644 --- a/apps/plugins/imageviewer/jpegp/jpeg81.h +++ b/apps/plugins/imageviewer/jpegp/jpeg81.h @@ -144,4 +144,4 @@ struct JPEGD { // The JPEG DECODER OBJECT }; -extern int JPEGDecode(struct JPEGD *j); +extern enum JPEGENUM JPEGDecode(struct JPEGD *j); diff --git a/apps/plugins/imageviewer/jpegp/jpegp.c b/apps/plugins/imageviewer/jpegp/jpegp.c new file mode 100644 index 0000000000..bb7be314f1 --- /dev/null +++ b/apps/plugins/imageviewer/jpegp/jpegp.c @@ -0,0 +1,260 @@ +#include "jpeg81.h" +#include "idct.h" +#include "GETC.h" +#include "rb_glue.h" + +#include "../imageviewer.h" + + +/**************** begin Application ********************/ + +/************************* Types ***************************/ + +struct t_disp +{ + unsigned char* bitmap; +}; + +/************************* Globals ***************************/ + +/* decompressed image in the possible sizes (1,2,4,8), wasting the other */ +static struct t_disp disp[9]; + +static struct JPEGD jpg; /* too large for stack */ + +/************************* Implementation ***************************/ + +static void draw_image_rect(struct image_info *info, + int x, int y, int width, int height) +{ + struct t_disp* pdisp = (struct t_disp*)info->data; +#ifdef HAVE_LCD_COLOR + rb->lcd_bitmap_part( + (fb_data*)pdisp->bitmap, info->x + x, info->y + y, + STRIDE(SCREEN_MAIN, info->width, info->height), + x + MAX(0, (LCD_WIDTH-info->width)/2), + y + MAX(0, (LCD_HEIGHT-info->height)/2), + width, height); +#else + mylcd_ub_gray_bitmap_part( + pdisp->bitmap, info->x + x, info->y + y, info->width, + x + MAX(0, (LCD_WIDTH-info->width)/2), + y + MAX(0, (LCD_HEIGHT-info->height)/2), + width, height); +#endif +} + +static int img_mem(int ds) +{ + struct JPEGD* j = &jpg; + return j->Y/ds * j->X/ds*sizeof(fb_data); +} + +/* my memory pool (from the mp3 buffer) */ +static char print[32]; /* use a common snprintf() buffer */ + +static void scaled_dequantization_and_idct(void) +{ + struct JPEGD* j = &jpg; + // The following code is based on RAINBOW lib jpeg2bmp example: + // https://github.com/Halicery/vc_rainbow/blob/605c045a564dad8e2df84e48914eac3d2d8d4a9b/jpeg2bmp.c + + printf("Scaled de-quantization and IDCT.. "); + int c, i, n; + + // Pre-scale quant-tables + int SQ[4][64]; + for (c=0; c<4 && j->QT[c][0]; c++) + { + int *q= j->QT[c], *sq= SQ[c]; + for (i=0; i<64; i++) sq[i]= q[i] * SCALEM[zigzag[i]]; + } + + // DEQUANT + IDCT + for (c=0; cNf; c++) + { + struct COMP *C= j->Components+c; + //int *q= j->QT[C->Qi]; + int *sq= SQ[C->Qi]; + + for (n=0; n < C->du_size; n++) + { + /* + // <--- scaled idct + int k, t[64]; + TCOEF *coef= du[x]; + t[0]= coef[0] * q[0] + 1024; // dequant DC and level-shift (8-bit) + for (k=1; k<64; k++) t[zigzag[k]] = coef[k] * q[k]; // dequant AC (+zigzag) + idct_s(t, coef); + */ + + // <--- scaled idct with dequant + idct_sq( C->du[ (n / C->du_w) * C->du_width + n % C->du_w ], sq ); + } + } + printf("done\n"); +} + +static int load_image(char *filename, struct image_info *info, + unsigned char *buf, ssize_t *buf_size) +{ + int status; + struct JPEGD *p_jpg = &jpg; + + memset(&disp, 0, sizeof(disp)); + memset(&jpg, 0, sizeof(jpg)); + + init_mem_pool(buf, *buf_size); + + if (!OPEN(filename)) + { + return PLUGIN_ERROR; + } + + if (!iv->running_slideshow) + { + rb->lcd_puts(0, 0, rb->strrchr(filename,'/')+1); + rb->lcd_puts(0, 2, "decoding..."); + rb->lcd_update(); + } + long time; /* measured ticks */ + + /* the actual decoding */ + time = *rb->current_tick; + status = JPEGDecode(p_jpg); + time = *rb->current_tick - time; + + CLOSE(); + + if (status < 0) + { /* bad format or minimum components not contained */ + if (status == JPEGENUMERR_MALLOC) + { + return PLUGIN_OUTOFMEM; + } + rb->splashf(HZ, "unsupported %d", status); + return PLUGIN_ERROR; + } + + if (!iv->running_slideshow) + { + rb->lcd_putsf(0, 2, "image %dx%d", p_jpg->X, p_jpg->Y); + int w, h; /* used to center output */ + rb->snprintf(print, sizeof(print), "jpegp %ld.%02ld sec ", time/HZ, time%HZ); + rb->lcd_getstringsize(print, &w, &h); /* centered in progress bar */ + rb->lcd_putsxy((LCD_WIDTH - w)/2, LCD_HEIGHT - h, print); + rb->lcd_update(); + //rb->sleep(100); + } + + info->x_size = p_jpg->X; + info->y_size = p_jpg->Y; + +#ifdef DISK_SPINDOWN + if (iv->running_slideshow && iv->immediate_ata_off) + { + /* running slideshow and time is long enough: power down disk */ + rb->storage_sleep(); + } +#endif + + if ( 3 != p_jpg->Nf ) + return PLUGIN_ERROR; + + scaled_dequantization_and_idct(); + + *buf_size = freeze_mem_pool(); + return PLUGIN_OK; +} + +static int get_image(struct image_info *info, int frame, int ds) +{ + (void)frame; + struct JPEGD* p_jpg = &jpg; + struct t_disp* p_disp = &disp[ds]; /* short cut */ + + info->width = p_jpg->X / ds; + info->height = p_jpg->Y / ds; + info->data = p_disp; + + if (p_disp->bitmap != NULL) + { + /* we still have it */ + return PLUGIN_OK; + } + + struct JPEGD* j = p_jpg; + int mem = img_mem(ds); + + p_disp->bitmap = malloc(mem); + + if (!p_disp->bitmap) + { + clear_mem_pool(); + memset(&disp, 0, sizeof(disp)); + p_disp->bitmap = malloc(mem); + if (!p_disp->bitmap) + return PLUGIN_ERROR; + } + + fb_data *bmp = (fb_data *)p_disp->bitmap; + + // The following code is based on RAINBOW lib jpeg2bmp example: + // https://github.com/Halicery/vc_rainbow/blob/605c045a564dad8e2df84e48914eac3d2d8d4a9b/jpeg2bmp.c + // Primitive yuv-rgb converter for all sub-sampling types, 24-bit BMP only + printf("YUV-to-RGB conversion.. "); + int h0 = j->Hmax / j->Components[0].Hi; + int v0 = j->Vmax / j->Components[0].Vi; + int h1 = j->Hmax / j->Components[1].Hi; + int v1 = j->Vmax / j->Components[1].Vi; + int h2 = j->Hmax / j->Components[2].Hi; + int v2 = j->Vmax / j->Components[2].Vi; + + int x, y; + for (y = 0; y < j->Y; y++) + { + if (y%ds != 0) + continue; + + TCOEF *C0 = + j->Components[0].du[j->Components[0].du_width * ((y / v0) / 8)] + 8 * ((y / v0) & 7); + TCOEF *C1 = + j->Components[1].du[j->Components[1].du_width * ((y / v1) / 8)] + 8 * ((y / v1) & 7); + TCOEF *C2 = + j->Components[2].du[j->Components[2].du_width * ((y / v2) / 8)] + 8 * ((y / v2) & 7); + + for (x = 0; x < j->X; x++) + { + if (x%ds != 0) + continue; + + TCOEF c0 = C0[(x / h0 / 8) * 64 + ((x / h0) & 7)]; + TCOEF c1 = C1[(x / h1 / 8) * 64 + ((x / h1) & 7)]; + TCOEF c2 = C2[(x / h2 / 8) * 64 + ((x / h2) & 7)]; + + // ITU BT.601 full-range YUV-to-RGB integer approximation + { + int y = (c0 << 5) + 16; + int u = c1 - 128; + int v = c2 - 128; + + int b = CLIP[(y + 57 * u)>>5]; // B; + int g = CLIP[(y - 11 * u - 23 * v)>>5]; // G + int r = CLIP[(y + 45 * v)>>5]; // R; + *bmp++= FB_RGBPACK(r,g,b); + } + } + } + printf("done\n"); + return 0; +} + +const struct image_decoder image_decoder = { + false, + img_mem, + load_image, + get_image, + draw_image_rect, +}; + +IMGDEC_HEADER diff --git a/apps/plugins/imageviewer/jpegp/jpegp.make b/apps/plugins/imageviewer/jpegp/jpegp.make new file mode 100644 index 0000000000..8d15af3a68 --- /dev/null +++ b/apps/plugins/imageviewer/jpegp/jpegp.make @@ -0,0 +1,32 @@ +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +# $Id$ +# + +JPEGPSRCDIR := $(IMGVSRCDIR)/jpegp +JPEGPBUILDDIR := $(IMGVBUILDDIR)/jpegp + +JPEGP_SRC := $(call preprocess, $(JPEGPSRCDIR)/SOURCES) +JPEGP_OBJ := $(call c2obj, $(JPEGP_SRC)) + +OTHER_SRC += $(JPEGP_SRC) + +ROCKS += $(JPEGPBUILDDIR)/jpegp.ovl + +$(JPEGPBUILDDIR)/jpegp.refmap: $(JPEGP_OBJ) $(TLSFLIB) +$(JPEGPBUILDDIR)/jpegp.link: $(PLUGIN_LDS) $(JPEGPBUILDDIR)/jpegp.refmap +$(JPEGPBUILDDIR)/jpegp.ovl: $(JPEGP_OBJ) $(TLSFLIB) + +JPEGPFLAGS = $(IMGDECFLAGS) +ifndef DEBUG +JPEGPFLAGS += -Os +endif + +# Compile plugin with extra flags (adapted from ZXBox) +$(JPEGPBUILDDIR)/%.o: $(JPEGPSRCDIR)/%.c $(JPEGPSRCDIR)/jpegp.make + $(SILENT)mkdir -p $(dir $@) + $(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) -I$(dir $<) $(JPEGPFLAGS) -c $< -o $@ diff --git a/apps/plugins/imageviewer/jpegp/mempool.c b/apps/plugins/imageviewer/jpegp/mempool.c new file mode 100644 index 0000000000..f777ff230a --- /dev/null +++ b/apps/plugins/imageviewer/jpegp/mempool.c @@ -0,0 +1,50 @@ +#include +#include "plugin.h" + +static unsigned char *mem_pool; +static unsigned char *mem_pool_start; +static size_t memory_size; + +extern void *malloc(size_t size) +{ + if (size > memory_size) + return NULL; + + memory_size -= size; + unsigned char* ptr = mem_pool; + + mem_pool+= size; + return ptr; +} + +extern void *calloc(size_t nelem, size_t elem_size) +{ + unsigned char* ptr = malloc(nelem*elem_size); + if (!ptr) + return NULL; + rb->memset(ptr, 0, nelem*elem_size); + return ptr; +} + +extern void init_mem_pool(const unsigned char *buf, const ssize_t buf_size) +{ + //TODO: do we need this alignment? (copied from gif lib) + unsigned char *memory_max; + + /* align buffer */ + mem_pool_start = mem_pool = (unsigned char *)((intptr_t)(buf + 3) & ~3); + memory_max = (unsigned char *)((intptr_t)(mem_pool + buf_size) & ~3); + memory_size = memory_max - mem_pool; +} + +extern ssize_t freeze_mem_pool(void) +{ + mem_pool_start = mem_pool; + return memory_size; +} + +extern void clear_mem_pool(void) +{ + memory_size += mem_pool - mem_pool_start; + mem_pool = mem_pool_start; +} \ No newline at end of file diff --git a/apps/plugins/imageviewer/jpegp/mempool.h b/apps/plugins/imageviewer/jpegp/mempool.h new file mode 100644 index 0000000000..55bbdaf363 --- /dev/null +++ b/apps/plugins/imageviewer/jpegp/mempool.h @@ -0,0 +1,7 @@ +#include + +extern void init_mem_pool(const unsigned char *buf, const ssize_t buf_size); +extern void *malloc(size_t size); +extern void *calloc(size_t nelem, size_t elem_size); +extern ssize_t freeze_mem_pool(void); +extern void clear_mem_pool(void); diff --git a/apps/plugins/imageviewer/jpegp/rb_glue.h b/apps/plugins/imageviewer/jpegp/rb_glue.h new file mode 100644 index 0000000000..ce08483deb --- /dev/null +++ b/apps/plugins/imageviewer/jpegp/rb_glue.h @@ -0,0 +1,35 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * + * $Id$ + * + * This program 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 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "plugin.h" +#include "mempool.h" + +//define from rbunicode.h clashes with jpeg81.h struct +#undef COMP + +#undef memset +#define memset(a,b,c) rb->memset((a),(b),(c)) + +#if defined(DEBUG) || defined(SIMULATOR) +#define printf rb->debugf +#else +#undef printf +#define printf(...) +#endif \ No newline at end of file diff --git a/manual/plugins/imageviewer.tex b/manual/plugins/imageviewer.tex index cc5b27eee4..0676f21a9f 100644 --- a/manual/plugins/imageviewer.tex +++ b/manual/plugins/imageviewer.tex @@ -161,7 +161,8 @@ for JPEG images. \end{description} \note{ -Progressive scan and other unusual JPEG files are not supported, and will +\opt{lcd_color}{Progressive scan is supported. Unsupported JPEG files} +\nopt{lcd_color}{Progressive scan and other unusual JPEG files are not supported, and} will result in various ``unsupported xx'' messages. Processing could also fail if the image is too big to decode which will be explained by a respective message. -- cgit v1.2.3