Support creating paletted images for any number of pixels e.g < 3 (ref #3466)
This commit is contained in:
parent
d17f1f076d
commit
7fa35f481e
3 changed files with 66 additions and 40 deletions
|
@ -43,6 +43,7 @@ using rgba_hash_table = std::unordered_map<unsigned int, unsigned char>;
|
|||
|
||||
// stl
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
|
||||
#define U2RED(x) ((x)&0xff)
|
||||
#define U2GREEN(x) (((x)>>8)&0xff)
|
||||
|
@ -53,7 +54,8 @@ namespace mapnik {
|
|||
|
||||
struct rgba;
|
||||
|
||||
struct MAPNIK_DECL rgb {
|
||||
struct MAPNIK_DECL rgb
|
||||
{
|
||||
std::uint8_t r;
|
||||
std::uint8_t g;
|
||||
std::uint8_t b;
|
||||
|
@ -92,7 +94,7 @@ struct MAPNIK_DECL rgba
|
|||
b(U2BLUE(c)),
|
||||
a(U2ALPHA(c)) {}
|
||||
|
||||
inline bool operator==(const rgba& y) const
|
||||
inline bool operator==(rgba const& y) const
|
||||
{
|
||||
return r == y.r && g == y.g && b == y.b && a == y.a;
|
||||
}
|
||||
|
@ -103,18 +105,27 @@ struct MAPNIK_DECL rgba
|
|||
bool operator() (const rgba& x, const rgba& y) const;
|
||||
};
|
||||
|
||||
inline bool operator<(rgba const& y) const
|
||||
{
|
||||
return std::tie(r, g, b, a) < std::tie(y.r, y.g, y.b, y.a);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class MAPNIK_DECL rgba_palette : private util::noncopyable {
|
||||
class MAPNIK_DECL rgba_palette : private util::noncopyable
|
||||
{
|
||||
public:
|
||||
enum palette_type { PALETTE_RGBA = 0, PALETTE_RGB = 1, PALETTE_ACT = 2 };
|
||||
|
||||
explicit rgba_palette(std::string const& pal, palette_type type = PALETTE_RGBA);
|
||||
rgba_palette();
|
||||
|
||||
const std::vector<rgb>& palette() const;
|
||||
const std::vector<unsigned>& alphaTable() const;
|
||||
inline std::vector<rgb> const& palette() const { return rgb_pal_;}
|
||||
inline std::vector<unsigned> const& alpha_table() const { return alpha_pal_;}
|
||||
|
||||
inline std::vector<rgb>& palette() { return rgb_pal_;}
|
||||
inline std::vector<unsigned>& alpha_table() { return alpha_pal_;}
|
||||
|
||||
unsigned char quantize(unsigned c) const;
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ extern "C"
|
|||
{
|
||||
#include <png.h>
|
||||
}
|
||||
|
||||
#include <set>
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
#define MAX_OCTREE_LEVELS 4
|
||||
|
@ -515,19 +515,19 @@ void save_as_png8_oct(T1 & file,
|
|||
}
|
||||
|
||||
//transparency values per palette index
|
||||
std::vector<unsigned> alphaTable;
|
||||
//alphaTable.resize(palette.size());//allow semitransparency also in almost opaque range
|
||||
std::vector<unsigned> alpha_table;
|
||||
//alpha_table.resize(palette.size());//allow semitransparency also in almost opaque range
|
||||
if (opts.trans_mode != 0)
|
||||
{
|
||||
alphaTable.resize(palette.size() - cols[TRANSPARENCY_LEVELS-1]);
|
||||
alpha_table.resize(palette.size() - cols[TRANSPARENCY_LEVELS-1]);
|
||||
}
|
||||
|
||||
if (palette.size() > 16 )
|
||||
{
|
||||
// >16 && <=256 colors -> write 8-bit color depth
|
||||
image_gray8 reduced_image(width,height);
|
||||
reduce_8(image, reduced_image, trees, limits, TRANSPARENCY_LEVELS, alphaTable);
|
||||
save_as_png(file,palette,reduced_image,width,height,8,alphaTable,opts);
|
||||
reduce_8(image, reduced_image, trees, limits, TRANSPARENCY_LEVELS, alpha_table);
|
||||
save_as_png(file,palette,reduced_image,width,height,8,alpha_table,opts);
|
||||
}
|
||||
else if (palette.size() == 1)
|
||||
{
|
||||
|
@ -535,13 +535,13 @@ void save_as_png8_oct(T1 & file,
|
|||
unsigned image_width = ((width + 15) >> 3) & ~1U; // 1-bit image, round up to 16-bit boundary
|
||||
unsigned image_height = height;
|
||||
image_gray8 reduced_image(image_width,image_height);
|
||||
reduce_1(image,reduced_image,trees, limits, alphaTable);
|
||||
reduce_1(image,reduced_image,trees, limits, alpha_table);
|
||||
if (meanAlpha<255 && cols[0]==0)
|
||||
{
|
||||
alphaTable.resize(1);
|
||||
alphaTable[0] = meanAlpha;
|
||||
alpha_table.resize(1);
|
||||
alpha_table[0] = meanAlpha;
|
||||
}
|
||||
save_as_png(file,palette,reduced_image,width,height,1,alphaTable,opts);
|
||||
save_as_png(file,palette,reduced_image,width,height,1,alpha_table,opts);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -549,8 +549,8 @@ void save_as_png8_oct(T1 & file,
|
|||
unsigned image_width = ((width + 7) >> 1) & ~3U; // 4-bit image, round up to 32-bit boundary
|
||||
unsigned image_height = height;
|
||||
image_gray8 reduced_image(image_width,image_height);
|
||||
reduce_4(image, reduced_image, trees, limits, TRANSPARENCY_LEVELS, alphaTable);
|
||||
save_as_png(file,palette,reduced_image,width,height,4,alphaTable,opts);
|
||||
reduce_4(image, reduced_image, trees, limits, TRANSPARENCY_LEVELS, alpha_table);
|
||||
save_as_png(file,palette,reduced_image,width,height,4,alpha_table,opts);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -560,7 +560,7 @@ void save_as_png8(T1 & file,
|
|||
T2 const& image,
|
||||
T3 const & tree,
|
||||
std::vector<mapnik::rgb> const& palette,
|
||||
std::vector<unsigned> const& alphaTable,
|
||||
std::vector<unsigned> const& alpha_table,
|
||||
png_options const& opts)
|
||||
{
|
||||
unsigned width = image.width();
|
||||
|
@ -579,7 +579,7 @@ void save_as_png8(T1 & file,
|
|||
row_out[x] = tree.quantize(row[x]);
|
||||
}
|
||||
}
|
||||
save_as_png(file, palette, reduced_image, width, height, 8, alphaTable, opts);
|
||||
save_as_png(file, palette, reduced_image, width, height, 8, alpha_table, opts);
|
||||
}
|
||||
else if (palette.size() == 1)
|
||||
{
|
||||
|
@ -588,7 +588,7 @@ void save_as_png8(T1 & file,
|
|||
unsigned image_height = height;
|
||||
image_gray8 reduced_image(image_width, image_height);
|
||||
reduced_image.set(0);
|
||||
save_as_png(file, palette, reduced_image, width, height, 1, alphaTable, opts);
|
||||
save_as_png(file, palette, reduced_image, width, height, 1, alpha_table, opts);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -612,7 +612,7 @@ void save_as_png8(T1 & file,
|
|||
row_out[x>>1] |= index;
|
||||
}
|
||||
}
|
||||
save_as_png(file, palette, reduced_image, width, height, 4, alphaTable, opts);
|
||||
save_as_png(file, palette, reduced_image, width, height, 4, alpha_table, opts);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -623,6 +623,7 @@ void save_as_png8_hex(T1 & file,
|
|||
{
|
||||
unsigned width = image.width();
|
||||
unsigned height = image.height();
|
||||
|
||||
if (width + height > 3) // at least 3 pixels (hextree implementation requirement)
|
||||
{
|
||||
// structure for color quantization
|
||||
|
@ -647,20 +648,44 @@ void save_as_png8_hex(T1 & file,
|
|||
}
|
||||
|
||||
//transparency values per palette index
|
||||
std::vector<mapnik::rgba> pal;
|
||||
tree.create_palette(pal);
|
||||
std::vector<mapnik::rgba> rgba_palette;
|
||||
tree.create_palette(rgba_palette);
|
||||
auto size = rgba_palette.size();
|
||||
std::vector<mapnik::rgb> palette;
|
||||
std::vector<unsigned> alphaTable;
|
||||
for (unsigned i=0; i<pal.size(); ++i)
|
||||
std::vector<unsigned> alpha_table;
|
||||
palette.reserve(size);
|
||||
alpha_table.reserve(size);
|
||||
for (auto const& c : rgba_palette)
|
||||
{
|
||||
palette.push_back(rgb(pal[i].r, pal[i].g, pal[i].b));
|
||||
alphaTable.push_back(pal[i].a);
|
||||
palette.emplace_back(c.r, c.g, c.b);
|
||||
alpha_table.push_back(c.a);
|
||||
}
|
||||
save_as_png8<T1, T2, hextree<mapnik::rgba> >(file, image, tree, palette, alphaTable, opts);
|
||||
save_as_png8<T1, T2, hextree<mapnik::rgba> >(file, image, tree, palette, alpha_table, opts);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Can't quantize images with less than 3 pixels");
|
||||
|
||||
std::set<mapnik::rgba> colors;
|
||||
for (unsigned y = 0; y < height; ++y)
|
||||
{
|
||||
typename T2::pixel_type const * row = image.get_row(y);
|
||||
|
||||
for (unsigned x = 0; x < width; ++x)
|
||||
{
|
||||
unsigned val = row[x];
|
||||
colors.emplace(U2RED(val), U2GREEN(val), U2BLUE(val), U2ALPHA(val));
|
||||
}
|
||||
}
|
||||
std::string str;
|
||||
for (auto c : colors)
|
||||
{
|
||||
str.push_back(c.r);
|
||||
str.push_back(c.g);
|
||||
str.push_back(c.b);
|
||||
str.push_back(c.a);
|
||||
}
|
||||
rgba_palette pal(str, rgba_palette::PALETTE_RGBA);
|
||||
save_as_png8<T1, T2, rgba_palette>(file, image, pal, pal.palette(), pal.alpha_table(), opts);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -670,7 +695,7 @@ void save_as_png8_pal(T1 & file,
|
|||
rgba_palette const& pal,
|
||||
png_options const& opts)
|
||||
{
|
||||
save_as_png8<T1, T2, rgba_palette>(file, image, pal, pal.palette(), pal.alphaTable(), opts);
|
||||
save_as_png8<T1, T2, rgba_palette>(file, image, pal, pal.palette(), pal.alpha_table(), opts);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -65,16 +65,6 @@ rgba_palette::rgba_palette()
|
|||
#endif
|
||||
}
|
||||
|
||||
const std::vector<rgb>& rgba_palette::palette() const
|
||||
{
|
||||
return rgb_pal_;
|
||||
}
|
||||
|
||||
const std::vector<unsigned>& rgba_palette::alphaTable() const
|
||||
{
|
||||
return alpha_pal_;
|
||||
}
|
||||
|
||||
bool rgba_palette::valid() const
|
||||
{
|
||||
return colors_ > 0;
|
||||
|
|
Loading…
Reference in a new issue