aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjcid <devnull@localhost>2008-01-16 01:17:20 +0100
committerjcid <devnull@localhost>2008-01-16 01:17:20 +0100
commitf09fce92f37ced2a53c96c09792906e2771f0e17 (patch)
tree6a2af7914d69e33a0ef7476e5334856e100457a7
parent17e6f35cfbfa7a73e986fcd11617db12898d740f (diff)
- Added support for progressive display of progressive jpegs.
- Fixed progressive display of interlaced pngs.
-rw-r--r--ChangeLog2
-rw-r--r--src/bitvec.c8
-rw-r--r--src/bitvec.h1
-rw-r--r--src/dicache.c43
-rw-r--r--src/dicache.h2
-rw-r--r--src/image.cc11
-rw-r--r--src/image.hh2
-rw-r--r--src/jpeg.c104
-rw-r--r--src/png.c7
9 files changed, 156 insertions, 24 deletions
diff --git a/ChangeLog b/ChangeLog
index ce591465..0aef39ff 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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);
diff --git a/src/jpeg.c b/src/jpeg.c
index 58baf5f4..9219937f 100644
--- a/src/jpeg.c
+++ b/src/jpeg.c
@@ -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 */
diff --git a/src/png.c b/src/png.c
index 43ef5519..d6a97f56 100644
--- a/src/png.c
+++ b/src/png.c
@@ -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;
}