From ee2e7c9c9907008de656773b98e1239a7f1af2a9 Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Sun, 25 Sep 2016 23:59:45 +0200 Subject: Exposes to the user additional PNG settings: Interlacing, grayscale, bit depth, alpha, compression level, PNG pHYs dpi. Fixed bugs: - https://launchpad.net/bugs/170650 (bzr r15131) --- src/display/cairo-utils.cpp | 86 +++++++++++++++++++++++++++++++++++++++++++++ src/display/cairo-utils.h | 2 ++ src/helper/png-write.cpp | 77 ++++++++++++++++++++++++---------------- src/helper/png-write.h | 6 ++-- src/ui/dialog/export.cpp | 61 +++++++++++++++++++++++++++++--- src/ui/dialog/export.h | 14 ++++++++ 6 files changed, 208 insertions(+), 38 deletions(-) (limited to 'src') diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp index 24a75de4c..a7625f4a1 100644 --- a/src/display/cairo-utils.cpp +++ b/src/display/cairo-utils.cpp @@ -13,6 +13,7 @@ #endif #include "display/cairo-utils.h" +#include #include #include @@ -1321,6 +1322,91 @@ guint32 argb32_from_rgba(guint32 in) return px; } + +/** + * Converts a pixbuf to a PNG data structure. + * For 8-but RGBA png, this is like copying. + * + */ +const guchar* pixbuf_to_png(guchar const**rows, guchar* px, int num_rows, int num_cols, int stride, int color_type, int bit_depth) +{ + int n_fields = 1 + (color_type&2) + (color_type&4)/4; + const guchar* new_data = (const guchar*)malloc((n_fields * bit_depth * num_rows * num_cols)/8 + 64); + char* ptr = (char*) new_data; + int pad=0; //used when we write image data smaller than one byte (for instance in black and white images where 1px = 1bit) + for(int row = 0; row < num_rows; ++row){ + rows[row] = (const guchar*)ptr; + for(int col = 0; col < num_cols; ++col){ + guint32 *pixel = reinterpret_cast(px + row*stride)+col; +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + //this part should probably be rewritten as (a tested, working) big endian, using htons() and ntohs() + guint64 a = (*pixel & 0xff000000) >> 24; + guint64 b = (*pixel & 0x00ff0000) >> 16; + guint64 g = (*pixel & 0x0000ff00) >> 8; + guint64 r = (*pixel & 0x000000ff); + + //one of possible rgb to greyscale formulas. This one is called "luminance, "luminosity" or "luma" + guint16 gray = (guint16)((guint32)((0.2126*(r<<24) + 0.7152*(g<<24) + 0.0722*(b<<24)))>>16); + + if (!pad) *((guint64*)ptr)=0; + if (color_type & 2) { //RGB + // for 8bit->16bit transition, I take the FF -> FFFF convention (multiplication by 0x101). + // If you prefer FF -> FF00 (multiplication by 0x100), remove the <<8, <<24, <<40 and <<56 + if (color_type & 4) { //RGBA + if (bit_depth==8) + *((guint32*)ptr) = *pixel; + else + *((guint64*)ptr) = (guint64)((a<<56)+(a<<48)+(b<<40)+(b<<32)+(g<<24)+(g<<16)+(r<<8)+(r)); + } + else{ //no alpha + if(bit_depth==8) + *((guint32*)ptr) = ((*pixel)<<8)>>8; + else + *((guint64*)ptr) = (guint64)((b<<40)+(b<<32)+(g<<24)+(g<<16)+(r<<8)+r); + } + } else { //Grayscale + if(bit_depth==16) + *(guint16*)ptr= ((gray & 0xff00)>>8) + ((gray &0x00ff)<<8); + else *((guint16*)ptr) += guint16(((gray >> (16-bit_depth))<gobj())); + table->attach(interlacing,0,0,1,1); + table->attach(bitdepth_label,0,1,1,1); + table->attach(bitdepth_cb,1,1,1,1); + table->attach(zlib_label,0,2,1,1); + table->attach(zlib_compression,1,2,1,1); + table->attach(phys_label,0,3,1,1); + table->attach(pHYs_sb,1,3,1,1); + table->show(); + /* Main dialog */ Gtk::Box *contents = _getContents(); contents->set_spacing(0); @@ -329,6 +363,7 @@ Export::Export (void) : contents->pack_start(hide_box); contents->pack_end(button_box, false, 0); contents->pack_end(_prog, Gtk::PACK_EXPAND_WIDGET); + contents->pack_end(expander, FALSE, FALSE,0); /* Signal handlers */ filename_entry.signal_changed().connect( sigc::mem_fun(*this, &Export::onFilenameModified) ); @@ -943,6 +978,18 @@ void Export::onExport () bool exportSuccessful = false; bool hide = hide_export.get_active (); + + // Advanced parameters + bool do_interlace = (interlacing.get_active()); + float pHYs = 0; + int zlib = zlib_compression.get_active_row_number() ; + const char* const modes_list[]={"Gray_1", "Gray_2","Gray_4","Gray_8","Gray_16","RGB_8","RGB_16","GrayAlpha_8","GrayAlpha_16","RGBA_8","RGBA_16"}; + int colortypes[] = {0,0,0,0,0,2,2,4,4,6,6}; //keep in sync with modes_list in Export constructor. values are from libpng doc. + int bitdepths[] = {1,2,4,8,16,8,16,8,16,8,16}; + int color_type = colortypes[bitdepth_cb.get_active_row_number()] ; + int bit_depth = bitdepths[bitdepth_cb.get_active_row_number()] ; + + if (batch_export.get_active ()) { // Batch export of selected objects @@ -987,6 +1034,7 @@ void Export::onExport () if (dpi == 0.0) { dpi = getValue(xdpi_adj); } + pHYs = (pHYs_adj->get_value() > 0.01) ? pHYs_adj->get_value() : dpi; Geom::OptRect area = item->desktopVisualBounds(); if (area) { @@ -1003,11 +1051,12 @@ void Export::onExport () std::vector x; std::vector selected(desktop->getSelection()->items().begin(), desktop->getSelection()->items().end()); if (!sp_export_png_file (doc, path.c_str(), - *area, width, height, dpi, dpi, + *area, width, height, pHYs, pHYs, nv->pagecolor, onProgressCallback, (void*)prog_dlg, TRUE, // overwrite without asking - hide ? selected : x + hide ? selected : x, + do_interlace, color_type, bit_depth, zlib )) { gchar * error = g_strdup_printf(_("Could not export to filename %s.\n"), safeFile); @@ -1049,6 +1098,7 @@ void Export::onExport () float const y1 = getValuePx(y1_adj); float const xdpi = getValue(xdpi_adj); float const ydpi = getValue(ydpi_adj); + pHYs = (pHYs_adj->get_value() > 0.01) ? pHYs_adj->get_value() : xdpi; unsigned long int const width = int(getValue(bmwidth_adj) + 0.5); unsigned long int const height = int(getValue(bmheight_adj) + 0.5); @@ -1094,12 +1144,13 @@ void Export::onExport () std::vector x; std::vector selected(desktop->getSelection()->items().begin(), desktop->getSelection()->items().end()); ExportResult status = sp_export_png_file(desktop->getDocument(), path.c_str(), - Geom::Rect(Geom::Point(x0, y0), Geom::Point(x1, y1)), width, height, xdpi, ydpi, + Geom::Rect(Geom::Point(x0, y0), Geom::Point(x1, y1)), width, height, pHYs, pHYs, //previously xdpi, ydpi. nv->pagecolor, onProgressCallback, (void*)prog_dlg, FALSE, - hide ? selected : x - ); + hide ? selected : x, + do_interlace, color_type, bit_depth, zlib + ); if (status == EXPORT_ERROR) { gchar * safeFile = Inkscape::IO::sanitizeString(path.c_str()); gchar * error = g_strdup_printf(_("Could not export to filename %s.\n"), safeFile); diff --git a/src/ui/dialog/export.h b/src/ui/dialog/export.h index a1c44714b..84e1c2362 100644 --- a/src/ui/dialog/export.h +++ b/src/ui/dialog/export.h @@ -13,6 +13,9 @@ #define SP_EXPORT_H #include +#include +#include +#include #include "ui/dialog/desktop-tracker.h" #include "ui/widget/panel.h" @@ -314,6 +317,17 @@ private: Inkscape::UI::Widget::CheckButton closeWhenDone; + /* Advanced */ + Gtk::Expander expander; + Inkscape::UI::Widget::CheckButton interlacing; + Gtk::Label bitdepth_label; + Gtk::ComboBoxText bitdepth_cb; + Gtk::Label zlib_label; + Gtk::ComboBoxText zlib_compression; + Gtk::Label phys_label; + Glib::RefPtr pHYs_adj; + Gtk::SpinButton pHYs_sb; + /* Export Button widgets */ Gtk::HBox button_box; Gtk::Button export_button; -- cgit v1.2.3