diff options
-rw-r--r-- | ChangeLog | 2 | ||||
-rw-r--r-- | src/bitvec.c | 8 | ||||
-rw-r--r-- | src/bitvec.h | 1 | ||||
-rw-r--r-- | src/dicache.c | 43 | ||||
-rw-r--r-- | src/dicache.h | 2 | ||||
-rw-r--r-- | src/image.cc | 11 | ||||
-rw-r--r-- | src/image.hh | 2 | ||||
-rw-r--r-- | src/jpeg.c | 104 | ||||
-rw-r--r-- | src/png.c | 7 |
9 files changed, 156 insertions, 24 deletions
@@ -72,6 +72,8 @@ dillo-fltk2 - Added a MSG_HTTP for HTTP/1.1's warning headers. - Added support for multi-line header fields. - Added support for "charset" in the HTTP header field for Content-Type. + - Added support for progressive display of progressive jpegs. + - Fixed progressive display of interlaced pngs. Patches: place +- Fixed a problem with locally-installed dpis. - Added code for optional image loading (nice interface) very advanced! diff --git a/src/bitvec.c b/src/bitvec.c index fc308fc6..8ca04f58 100644 --- a/src/bitvec.c +++ b/src/bitvec.c @@ -30,6 +30,14 @@ bitvec_t *a_Bitvec_new(int num_bits) } /* + * Clear a bitvec + */ +void a_Bitvec_clear(bitvec_t *bvec) +{ + memset(bvec->vec, 0, sizeof(uchar_t) * bvec->len/BVEC_SIZE + 1); +} + +/* * Free a bitvec */ void a_Bitvec_free(bitvec_t *bvec) diff --git a/src/bitvec.h b/src/bitvec.h index ab6797ce..f9063070 100644 --- a/src/bitvec.h +++ b/src/bitvec.h @@ -21,6 +21,7 @@ bitvec_t *a_Bitvec_new(int bits); void a_Bitvec_free(bitvec_t *bvec); int a_Bitvec_get_bit(bitvec_t *bvec, int pos); void a_Bitvec_set_bit(bitvec_t *bvec, int pos); +void a_Bitvec_clear(bitvec_t *bvec); /* #define a_Bitvec_get_bit(bvec,pos) \ diff --git a/src/dicache.c b/src/dicache.c index 330a5c41..02324f26 100644 --- a/src/dicache.c +++ b/src/dicache.c @@ -84,6 +84,7 @@ static DICacheEntry *Dicache_entry_new(void) entry->RefCount = 1; entry->TotalSize = 0; entry->Y = 0; + entry->ScanNumber = 0; entry->BitVec = NULL; entry->State = DIC_Empty; entry->version = 0; @@ -263,7 +264,7 @@ void a_Dicache_callback(int Op, CacheClient_t *Client) dReturn_if_fail ( DicEntry != NULL ); - /* when the data stream is not an image 'v_imgbuf' keeps NULL */ + /* when the data stream is not an image 'v_imgbuf' remains NULL */ if (Op == CA_Send && DicEntry->v_imgbuf) { if (Image->height == 0 && DicEntry->State >= DIC_SetParms) { /* Set parms */ @@ -273,11 +274,25 @@ void a_Dicache_callback(int Op, CacheClient_t *Client) DicEntry->type); } if (DicEntry->State == DIC_Write) { - for (i = 0; i < DicEntry->height; ++i) - if (a_Bitvec_get_bit(DicEntry->BitVec, (int)i) && - !a_Bitvec_get_bit(Image->BitVec, (int)i) ) - a_Image_write(Image, DicEntry->v_imgbuf, - DicEntry->linebuf, i, FALSE); + if (DicEntry->ScanNumber == Image->ScanNumber) { + for (i = 0; i < DicEntry->height; ++i) + if (a_Bitvec_get_bit(DicEntry->BitVec, (int)i) && + !a_Bitvec_get_bit(Image->BitVec, (int)i) ) + a_Image_write(Image, DicEntry->v_imgbuf, + DicEntry->linebuf, i, FALSE); + } else { + for (i = 0; i < DicEntry->height; ++i) { + if (a_Bitvec_get_bit(DicEntry->BitVec, (int)i) || + !a_Bitvec_get_bit(Image->BitVec, (int)i) || + DicEntry->ScanNumber > Image->ScanNumber + 1) { + a_Image_write(Image, DicEntry->v_imgbuf, + DicEntry->linebuf, i, FALSE); + } + if (!a_Bitvec_get_bit(DicEntry->BitVec, (int)i)) + a_Bitvec_clear_bit(Image->BitVec, (int)i); + } + Image->ScanNumber = DicEntry->ScanNumber; + } } } else if (Op == CA_Close || Op == CA_Abort) { a_Image_close(Web->Image); @@ -353,6 +368,22 @@ void a_Dicache_set_cmap(DilloUrl *url, int version, DilloImage *Image, } /* + * Reset for a new scan from a multiple-scan image. + */ +void a_Dicache_new_scan(DilloImage *image, const DilloUrl *url, int version) +{ + DICacheEntry *DicEntry; + + dReturn_if_fail ( url != NULL ); + DicEntry = Dicache_get_entry_version(url, version); + dReturn_if_fail ( DicEntry != NULL ); + + a_Bitvec_clear(DicEntry->BitVec); + DicEntry->ScanNumber++; + a_Image_new_scan(image, DicEntry->v_imgbuf); +} + +/* * Implement the write method * (Write a scan line into the Dicache entry) * buf: row buffer diff --git a/src/dicache.h b/src/dicache.h index 9afa5045..a67261c7 100644 --- a/src/dicache.h +++ b/src/dicache.h @@ -31,6 +31,7 @@ struct _DICacheEntry { void *v_imgbuf; /* Void pointer to an Imgbuf object */ size_t TotalSize; /* Amount of memory the image takes up */ int Y; /* Current decoding row */ + uint_t ScanNumber; /* Current decoding scan */ bitvec_t *BitVec; /* Bit vector for decoded rows */ DicEntryState State; /* Current status for this entry */ int RefCount; /* Reference Counter */ @@ -53,6 +54,7 @@ void a_Dicache_set_parms(DilloUrl *url, int version, DilloImage *Image, void a_Dicache_set_cmap(DilloUrl *url, int version, DilloImage *Image, const uchar_t *cmap, uint_t num_colors, int num_colors_max, int bg_index); +void a_Dicache_new_scan(DilloImage *image, const DilloUrl *url, int version); void a_Dicache_write(DilloImage *Image, DilloUrl *url, int version, const uchar_t *buf, int x, uint_t Y); void a_Dicache_close(DilloUrl *url, int version, CacheClient_t *Client); diff --git a/src/image.cc b/src/image.cc index 847b2b93..110d56b3 100644 --- a/src/image.cc +++ b/src/image.cc @@ -55,6 +55,7 @@ DilloImage *a_Image_new(int width, Image->in_type = DILLO_IMG_TYPE_NOTSET; Image->bg_color = bg_color; Image->ProcessedBytes = 0; + Image->ScanNumber = 0; Image->BitVec = NULL; Image->State = IMG_Empty; @@ -155,6 +156,16 @@ void a_Image_set_cmap(DilloImage *Image, const uchar_t *cmap) } /* + * Begin a new scan for a multiple-scan image + */ +void a_Image_new_scan(DilloImage *Image, void *v_imgbuf) +{ + a_Bitvec_clear(Image->BitVec); + Image->ScanNumber++; + ((Imgbuf*)v_imgbuf)->newScan(); +} + +/* * Implement the write method */ void a_Image_write(DilloImage *Image, void *v_imgbuf, diff --git a/src/image.hh b/src/image.hh index 8ed8b081..73b0e5e7 100644 --- a/src/image.hh +++ b/src/image.hh @@ -44,6 +44,7 @@ struct _DilloImage { int ProcessedBytes; /* Amount of bytes already decoded */ bitvec_t *BitVec; /* Bit vector for decoded rows */ + uint_t ScanNumber; /* Current decoding scan */ ImageState State; /* Processing status */ int RefCount; /* Reference counter */ @@ -62,6 +63,7 @@ void a_Image_set_parms(DilloImage *Image, void *v_imgbuf, DilloUrl *url, int version, uint_t width, uint_t height, DilloImgType type); void a_Image_set_cmap(DilloImage *Image, const uchar_t *cmap); +void a_Image_new_scan(DilloImage *image, void *v_imgbuf); void a_Image_write(DilloImage *Image, void *v_imgbuf, const uchar_t *buf, uint_t y, int decode); void a_Image_close(DilloImage *Image); @@ -42,7 +42,9 @@ typedef enum { DILLO_JPEG_INIT, DILLO_JPEG_STARTING, - DILLO_JPEG_READING, + DILLO_JPEG_READ_BEGIN_SCAN, + DILLO_JPEG_READ_IN_SCAN, + DILLO_JPEG_READ_END_SCAN, DILLO_JPEG_DONE, DILLO_JPEG_ERROR } DilloJpegState; @@ -139,10 +141,7 @@ void *a_Jpeg_image(const char *Type, void *P, CA_Callback_t *Call, static void Jpeg_close(DilloJpeg *jpeg, CacheClient_t *Client) { a_Dicache_close(jpeg->url, jpeg->version, Client); - - if (jpeg->state != DILLO_JPEG_DONE) { - jpeg_destroy_decompress(&(jpeg->cinfo)); - } + jpeg_destroy_decompress(&(jpeg->cinfo)); dFree(jpeg); } @@ -288,6 +287,15 @@ static void Jpeg_write(DilloJpeg *jpeg, void *Buf, uint_t BufSize) else DEBUG_MSG(5, "jpeg: can't handle %d component images\n", jpeg->cinfo.num_components); + + /* + * TODO: The multiple-scan jpeg code is valuable at download time + * when an image arrives slowly, but should not be used to redisplay + * cached images. + */ + if (jpeg_has_multiple_scans(&jpeg->cinfo)) + jpeg->cinfo.buffered_image = TRUE; + a_Dicache_set_parms(jpeg->url, jpeg->version, jpeg->Image, (uint_t)jpeg->cinfo.image_width, (uint_t)jpeg->cinfo.image_height, @@ -301,34 +309,94 @@ static void Jpeg_write(DilloJpeg *jpeg, void *Buf, uint_t BufSize) /* decompression step 5 (see libjpeg.doc) */ if (jpeg_start_decompress(&(jpeg->cinfo))) { jpeg->y = 0; - jpeg->state = DILLO_JPEG_READING; + jpeg->state = jpeg_has_multiple_scans(&jpeg->cinfo) ? + DILLO_JPEG_READ_BEGIN_SCAN : DILLO_JPEG_READ_IN_SCAN; + } + } + + /* + * A progressive jpeg contains multiple scans that can be used to display + * an increasingly sharp image as it is being received. The reading of each + * scan must be surrounded by jpeg_start_output()/jpeg_finish_output(). + */ + + if (jpeg->state == DILLO_JPEG_READ_END_SCAN) { + if (jpeg_finish_output(&jpeg->cinfo)) { + if (jpeg_input_complete(&jpeg->cinfo)) { + jpeg->state = DILLO_JPEG_DONE; + } else { + jpeg->state = DILLO_JPEG_READ_BEGIN_SCAN; + } } } - if (jpeg->state == DILLO_JPEG_READING) { + + if (jpeg->state == DILLO_JPEG_READ_BEGIN_SCAN) { + if (jpeg_start_output(&jpeg->cinfo, jpeg->cinfo.input_scan_number)) { + a_Dicache_new_scan(jpeg->Image, jpeg->url, jpeg->version); + jpeg->state = DILLO_JPEG_READ_IN_SCAN; + } + } + + if (jpeg->state == DILLO_JPEG_READ_IN_SCAN) { linebuf = dMalloc(jpeg->cinfo.image_width * jpeg->cinfo.num_components); array[0] = linebuf; - while (jpeg->y < jpeg->cinfo.image_height) { + + while (1) { num_read = jpeg_read_scanlines(&(jpeg->cinfo), array, 1); - if (num_read == 0) + if (num_read == 0) { + /* out of input */ break; + } a_Dicache_write(jpeg->Image, jpeg->url, jpeg->version, linebuf, 0, jpeg->y); jpeg->y++; - } - if (jpeg->y == jpeg->cinfo.image_height) { - DEBUG_MSG(5, "height achieved\n"); - jpeg_destroy_decompress(&(jpeg->cinfo)); - jpeg->state = DILLO_JPEG_DONE; + if (jpeg->y == jpeg->cinfo.image_height) { + /* end of scan */ + if (!jpeg_has_multiple_scans(&jpeg->cinfo)) { + jpeg->state = DILLO_JPEG_DONE; + break; + } else { + jpeg->y = 0; + if (jpeg_input_complete(&jpeg->cinfo)) { + if (jpeg->cinfo.input_scan_number == + jpeg->cinfo.output_scan_number) { + jpeg->state = DILLO_JPEG_DONE; + break; + } else { + /* one final loop through the scanlines */ + jpeg_finish_output(&jpeg->cinfo); + jpeg_start_output(&jpeg->cinfo, + jpeg->cinfo.input_scan_number); + continue; + } + } + jpeg->state = DILLO_JPEG_READ_END_SCAN; + if (!jpeg_finish_output(&jpeg->cinfo)) { + /* out of input */ + break; + } else { + if (jpeg_input_complete(&jpeg->cinfo)) { + jpeg->state = DILLO_JPEG_DONE; + break; + } else { + jpeg->state = DILLO_JPEG_READ_BEGIN_SCAN; + } + } + if (!jpeg_start_output(&jpeg->cinfo, + jpeg->cinfo.input_scan_number)) { + /* out of input */ + break; + } + a_Dicache_new_scan(jpeg->Image, jpeg->url, jpeg->version); + jpeg->state = DILLO_JPEG_READ_IN_SCAN; + } + } } dFree(linebuf); } - if (jpeg->state == DILLO_JPEG_ERROR) { - jpeg_destroy_decompress(&(jpeg->cinfo)); - jpeg->state = DILLO_JPEG_DONE; - } } #endif /* ENABLE_JPEG */ @@ -79,6 +79,7 @@ struct _DilloPng { uchar_t **row_pointers; /* pntr to row starts */ jmp_buf jmpbuf; /* png error processing */ int error; /* error flag */ + png_uint_32 previous_row; int rowbytes; /* No. bytes in image row */ short passes; short channels; /* No. image channels */ @@ -230,6 +231,11 @@ static void png_progressive_combine_row(png_ptr, png->row_pointers[row_num], new_row); + if (row_num < png->previous_row) { + a_Dicache_new_scan(png->Image, png->url, png->version); + } + png->previous_row = row_num; + switch (png->channels) { case 3: a_Dicache_write(png->Image, png->url, png->version, @@ -419,6 +425,7 @@ static DilloPng *Png_new(DilloImage *Image, DilloUrl *url, int version) png->linebuf = NULL; png->image_data = NULL; png->row_pointers = NULL; + png->previous_row = 0; return png; } |