| Summary: | PNG export does not allow lower bit depths for smaller images | ||
|---|---|---|---|
| Product: | [Applications] krita | Reporter: | Thomas Zander <zander> |
| Component: | General | Assignee: | Halla Rempt <halla> |
| Status: | RESOLVED FIXED | ||
| Severity: | normal | ||
| Priority: | NOR | ||
| Version First Reported In: | unspecified | ||
| Target Milestone: | --- | ||
| Platform: | unspecified | ||
| OS: | Linux | ||
| Latest Commit: | Version Fixed/Implemented In: | ||
| Sentry Crash Report: | |||
|
Description
Thomas Zander
2006-07-08 23:27:34 UTC
SVN commit 582298 by berger:
forward port of: analyse the image and try to create a palette to reduce the size of the png
CCBUG:130483
M +109 -11 kis_png_converter.cc
--- trunk/koffice/filters/krita/png/kis_png_converter.cc #582297:582298
@@ -122,7 +122,7 @@
class KisPNGStream {
public:
- KisPNGStream(Q_UINT8* buf, Q_UINT32 depth ) : m_depth(depth), m_posinc(8), m_buf(buf) {};
+ KisPNGStream(quint8* buf, quint32 depth ) : m_posinc(8),m_depth(depth), m_buf(buf) {};
int nextValue()
{
if( m_posinc == 0)
@@ -133,9 +133,20 @@
m_posinc -= m_depth;
return (( (*m_buf) >> (m_posinc) ) & ( ( 1 << m_depth ) - 1 ) );
}
+ void setNextValue(int v)
+ {
+ if( m_posinc == 0)
+ {
+ m_posinc = 8;
+ m_buf++;
+ *m_buf = 0;
+ }
+ m_posinc -= m_depth;
+ *m_buf = (v << m_posinc) | *m_buf;
+ }
private:
- Q_UINT32 m_posinc, m_depth;
- Q_UINT8* m_buf;
+ quint32 m_posinc, m_depth;
+ quint8* m_buf;
};
KisImageBuilder_Result KisPNGConverter::decode(const KURL& uri)
@@ -342,13 +353,13 @@
case PNG_COLOR_TYPE_GRAY_ALPHA:
if(color_nb_bits == 16)
{
- Q_UINT16 *src = reinterpret_cast<Q_UINT16 *>(row_pointer);
+ quint16 *src = reinterpret_cast<quint16 *>(row_pointer);
while (!it.isDone()) {
- Q_UINT16 *d = reinterpret_cast<Q_UINT16 *>(it.rawData());
+ quint16 *d = reinterpret_cast<quint16 *>(it.rawData());
d[0] = *(src++);
if(transform) cmsDoTransform(transform, d, d, 1);
if(hasalpha) d[1] = *(src++);
- else d[1] = Q_UINT16_MAX;
+ else d[1] = quint16_MAX;
++it;
}
} else {
@@ -368,15 +379,15 @@
case PNG_COLOR_TYPE_RGB_ALPHA:
if(color_nb_bits == 16)
{
- Q_UINT16 *src = reinterpret_cast<Q_UINT16 *>(row_pointer);
+ quint16 *src = reinterpret_cast<quint16 *>(row_pointer);
while (!it.isDone()) {
- Q_UINT16 *d = reinterpret_cast<Q_UINT16 *>(it.rawData());
+ quint16 *d = reinterpret_cast<quint16 *>(it.rawData());
d[2] = *(src++);
d[1] = *(src++);
d[0] = *(src++);
if(transform) cmsDoTransform(transform, d, d, 1);
if(hasalpha) d[3] = *(src++);
- else d[3] = Q_UINT16_MAX;
+ else d[3] = quint16_MAX;
++it;
}
} else {
@@ -522,13 +533,70 @@
png_set_compression_buffer_size(png_ptr, 8192);
int color_nb_bits = 8 * layer->paintDevice()->pixelSize() / layer->paintDevice()->nChannels();
- int color_type = getColorTypeforColorSpace(img->colorSpace(), alpha);
+ int color_type = getColorTypeforColorSpace(layer->paintDevice()->colorSpace(), alpha);
if(color_type == -1)
{
return KisImageBuilder_RESULT_UNSUPPORTED;
}
+ // Try to compute a table of color if the colorspace is RGB8f
+ png_colorp palette ;
+ int num_palette = 0;
+ if(!alpha && layer->paintDevice()->colorSpace()->id() == KisID("RGBA") )
+ { // png doesn't handle indexed images and alpha, and only have indexed for RGB8
+ palette = new png_color[255];
+ KisRectIteratorPixel it = layer->paintDevice()->createRectIterator(0,0, img->width(), img->height(), false);
+ bool toomuchcolor = false;
+ while( !it.isDone() )
+ {
+ const Q_UINT8* c = it.rawData();
+ bool findit = false;
+ for(int i = 0; i < num_palette; i++)
+ {
+ if(palette[i].red == c[2] &&
+ palette[i].green == c[1] &&
+ palette[i].blue == c[0] )
+ {
+ findit = true;
+ break;
+ }
+ }
+ if(!findit)
+ {
+ if( num_palette == 255)
+ {
+ toomuchcolor = true;
+ break;
+ }
+ palette[num_palette].red = c[2];
+ palette[num_palette].green = c[1];
+ palette[num_palette].blue = c[0];
+ num_palette++;
+ }
+ ++it;
+ }
+ if(!toomuchcolor)
+ {
+ kdDebug(41008) << "Found a palette of " << num_palette << " colors" << endl;
+ color_type = PNG_COLOR_TYPE_PALETTE;
+ if( num_palette <= 2)
+ {
+ color_nb_bits = 1;
+ } else if( num_palette <= 4)
+ {
+ color_nb_bits = 2;
+ } else if( num_palette <= 16)
+ {
+ color_nb_bits = 4;
+ } else {
+ color_nb_bits = 8;
+ }
+ } else {
+ delete palette;
+ }
+ }
+
int interlacetype = interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE;
png_set_IHDR(png_ptr, info_ptr,
@@ -539,7 +607,11 @@
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_ABSOLUTE);
-
+ // set the palette
+ if( color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_set_PLTE(png_ptr, info_ptr, palette, num_palette);
+ }
// Save annotation
vKisAnnotationSP_it it = annotationsStart;
while(it != annotationsEnd) {
@@ -654,6 +726,27 @@
}
}
break;
+ case PNG_COLOR_TYPE_PALETTE:
+ {
+ Q_UINT8 *dst = row_pointers[y];
+ KisPNGStream writestream(dst, color_nb_bits);
+ while (!it.isDone()) {
+ const Q_UINT8 *d = it.rawData();
+ int i;
+ for(i = 0; i < num_palette; i++)
+ {
+ if(palette[i].red == d[2] &&
+ palette[i].green == d[1] &&
+ palette[i].blue == d[0] )
+ {
+ break;
+ }
+ }
+ writestream.setNextValue(i);
+ ++it;
+ }
+ }
+ break;
default:
KIO::del(uri);
return KisImageBuilder_RESULT_UNSUPPORTED;
@@ -672,6 +765,11 @@
}
delete[] row_pointers;
+ if( color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ delete palette;
+ }
+
fclose(fp);
return KisImageBuilder_RESULT_OK;
SVN commit 582299 by berger:
analyse the image and try to create a palette to reduce the size of the png
BUG:130483
M +104 -5 kis_png_converter.cc
--- branches/koffice/1.6/koffice/filters/krita/png/kis_png_converter.cc #582298:582299
@@ -123,7 +123,7 @@
class KisPNGStream {
public:
- KisPNGStream(Q_UINT8* buf, Q_UINT32 depth ) : m_depth(depth), m_posinc(8), m_buf(buf) {};
+ KisPNGStream(Q_UINT8* buf, Q_UINT32 depth ) : m_posinc(8),m_depth(depth), m_buf(buf) {};
int nextValue()
{
if( m_posinc == 0)
@@ -134,6 +134,17 @@
m_posinc -= m_depth;
return (( (*m_buf) >> (m_posinc) ) & ( ( 1 << m_depth ) - 1 ) );
}
+ void setNextValue(int v)
+ {
+ if( m_posinc == 0)
+ {
+ m_posinc = 8;
+ m_buf++;
+ *m_buf = 0;
+ }
+ m_posinc -= m_depth;
+ *m_buf = (v << m_posinc) | *m_buf;
+ }
private:
Q_UINT32 m_posinc, m_depth;
Q_UINT8* m_buf;
@@ -455,7 +466,6 @@
return m_img;
}
-
KisImageBuilder_Result KisPNGConverter::buildFile(const KURL& uri, KisPaintLayerSP layer, vKisAnnotationSP_it annotationsStart, vKisAnnotationSP_it annotationsEnd, int compression, bool interlace, bool alpha)
{
kdDebug(41008) << "Start writing PNG File" << endl;
@@ -508,7 +518,7 @@
// Setup the progress function
// FIXME png_set_write_status_fn(png_ptr, progress);
// setProgressTotalSteps(100/*height*/);
-
+
/* set the zlib compression level */
png_set_compression_level(png_ptr, compression);
@@ -521,13 +531,70 @@
png_set_compression_buffer_size(png_ptr, 8192);
int color_nb_bits = 8 * layer->paintDevice()->pixelSize() / layer->paintDevice()->nChannels();
- int color_type = getColorTypeforColorSpace(img->colorSpace(), alpha);
+ int color_type = getColorTypeforColorSpace(layer->paintDevice()->colorSpace(), alpha);
if(color_type == -1)
{
return KisImageBuilder_RESULT_UNSUPPORTED;
}
+ // Try to compute a table of color if the colorspace is RGB8f
+ png_colorp palette ;
+ int num_palette = 0;
+ if(!alpha && layer->paintDevice()->colorSpace()->id() == KisID("RGBA") )
+ { // png doesn't handle indexed images and alpha, and only have indexed for RGB8
+ palette = new png_color[255];
+ KisRectIteratorPixel it = layer->paintDevice()->createRectIterator(0,0, img->width(), img->height(), false);
+ bool toomuchcolor = false;
+ while( !it.isDone() )
+ {
+ const Q_UINT8* c = it.rawData();
+ bool findit = false;
+ for(int i = 0; i < num_palette; i++)
+ {
+ if(palette[i].red == c[2] &&
+ palette[i].green == c[1] &&
+ palette[i].blue == c[0] )
+ {
+ findit = true;
+ break;
+ }
+ }
+ if(!findit)
+ {
+ if( num_palette == 255)
+ {
+ toomuchcolor = true;
+ break;
+ }
+ palette[num_palette].red = c[2];
+ palette[num_palette].green = c[1];
+ palette[num_palette].blue = c[0];
+ num_palette++;
+ }
+ ++it;
+ }
+ if(!toomuchcolor)
+ {
+ kdDebug(41008) << "Found a palette of " << num_palette << " colors" << endl;
+ color_type = PNG_COLOR_TYPE_PALETTE;
+ if( num_palette <= 2)
+ {
+ color_nb_bits = 1;
+ } else if( num_palette <= 4)
+ {
+ color_nb_bits = 2;
+ } else if( num_palette <= 16)
+ {
+ color_nb_bits = 4;
+ } else {
+ color_nb_bits = 8;
+ }
+ } else {
+ delete palette;
+ }
+ }
+
int interlacetype = interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE;
png_set_IHDR(png_ptr, info_ptr,
@@ -538,7 +605,11 @@
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_ABSOLUTE);
-
+ // set the palette
+ if( color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_set_PLTE(png_ptr, info_ptr, palette, num_palette);
+ }
// Save annotation
vKisAnnotationSP_it it = annotationsStart;
while(it != annotationsEnd) {
@@ -655,7 +726,29 @@
}
}
break;
+ case PNG_COLOR_TYPE_PALETTE:
+ {
+ Q_UINT8 *dst = row_pointers[y];
+ KisPNGStream writestream(dst, color_nb_bits);
+ while (!it.isDone()) {
+ const Q_UINT8 *d = it.rawData();
+ int i;
+ for(i = 0; i < num_palette; i++)
+ {
+ if(palette[i].red == d[2] &&
+ palette[i].green == d[1] &&
+ palette[i].blue == d[0] )
+ {
+ break;
+ }
+ }
+ writestream.setNextValue(i);
+ ++it;
+ }
+ }
+ break;
default:
+ kdDebug(41008) << "Unsupported color type for writting : " << color_type << endl;
KIO::del(uri);
return KisImageBuilder_RESULT_UNSUPPORTED;
}
@@ -663,6 +756,7 @@
png_write_image(png_ptr, row_pointers);
+
// Writting is over
png_write_end(png_ptr, info_ptr);
@@ -673,6 +767,11 @@
}
delete[] row_pointers;
+ if( color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ delete palette;
+ }
+
fclose(fp);
return KisImageBuilder_RESULT_OK;
|