Skip to content

Commit 7fa35f4

Browse files
committed
Support creating paletted images for any number of pixels e.g < 3 (ref mapnik#3466)
1 parent d17f1f0 commit 7fa35f4

File tree

3 files changed

+66
-40
lines changed

3 files changed

+66
-40
lines changed

include/mapnik/palette.hpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ using rgba_hash_table = std::unordered_map<unsigned int, unsigned char>;
4343

4444
// stl
4545
#include <vector>
46+
#include <tuple>
4647

4748
#define U2RED(x) ((x)&0xff)
4849
#define U2GREEN(x) (((x)>>8)&0xff)
@@ -53,7 +54,8 @@ namespace mapnik {
5354

5455
struct rgba;
5556

56-
struct MAPNIK_DECL rgb {
57+
struct MAPNIK_DECL rgb
58+
{
5759
std::uint8_t r;
5860
std::uint8_t g;
5961
std::uint8_t b;
@@ -92,7 +94,7 @@ struct MAPNIK_DECL rgba
9294
b(U2BLUE(c)),
9395
a(U2ALPHA(c)) {}
9496

95-
inline bool operator==(const rgba& y) const
97+
inline bool operator==(rgba const& y) const
9698
{
9799
return r == y.r && g == y.g && b == y.b && a == y.a;
98100
}
@@ -103,18 +105,27 @@ struct MAPNIK_DECL rgba
103105
bool operator() (const rgba& x, const rgba& y) const;
104106
};
105107

108+
inline bool operator<(rgba const& y) const
109+
{
110+
return std::tie(r, g, b, a) < std::tie(y.r, y.g, y.b, y.a);
111+
}
112+
106113
};
107114

108115

109-
class MAPNIK_DECL rgba_palette : private util::noncopyable {
116+
class MAPNIK_DECL rgba_palette : private util::noncopyable
117+
{
110118
public:
111119
enum palette_type { PALETTE_RGBA = 0, PALETTE_RGB = 1, PALETTE_ACT = 2 };
112120

113121
explicit rgba_palette(std::string const& pal, palette_type type = PALETTE_RGBA);
114122
rgba_palette();
115123

116-
const std::vector<rgb>& palette() const;
117-
const std::vector<unsigned>& alphaTable() const;
124+
inline std::vector<rgb> const& palette() const { return rgb_pal_;}
125+
inline std::vector<unsigned> const& alpha_table() const { return alpha_pal_;}
126+
127+
inline std::vector<rgb>& palette() { return rgb_pal_;}
128+
inline std::vector<unsigned>& alpha_table() { return alpha_pal_;}
118129

119130
unsigned char quantize(unsigned c) const;
120131

include/mapnik/png_io.hpp

Lines changed: 50 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ extern "C"
3939
{
4040
#include <png.h>
4141
}
42-
42+
#include <set>
4343
#pragma GCC diagnostic pop
4444

4545
#define MAX_OCTREE_LEVELS 4
@@ -515,42 +515,42 @@ void save_as_png8_oct(T1 & file,
515515
}
516516

517517
//transparency values per palette index
518-
std::vector<unsigned> alphaTable;
519-
//alphaTable.resize(palette.size());//allow semitransparency also in almost opaque range
518+
std::vector<unsigned> alpha_table;
519+
//alpha_table.resize(palette.size());//allow semitransparency also in almost opaque range
520520
if (opts.trans_mode != 0)
521521
{
522-
alphaTable.resize(palette.size() - cols[TRANSPARENCY_LEVELS-1]);
522+
alpha_table.resize(palette.size() - cols[TRANSPARENCY_LEVELS-1]);
523523
}
524524

525525
if (palette.size() > 16 )
526526
{
527527
// >16 && <=256 colors -> write 8-bit color depth
528528
image_gray8 reduced_image(width,height);
529-
reduce_8(image, reduced_image, trees, limits, TRANSPARENCY_LEVELS, alphaTable);
530-
save_as_png(file,palette,reduced_image,width,height,8,alphaTable,opts);
529+
reduce_8(image, reduced_image, trees, limits, TRANSPARENCY_LEVELS, alpha_table);
530+
save_as_png(file,palette,reduced_image,width,height,8,alpha_table,opts);
531531
}
532532
else if (palette.size() == 1)
533533
{
534534
// 1 color image -> write 1-bit color depth PNG
535535
unsigned image_width = ((width + 15) >> 3) & ~1U; // 1-bit image, round up to 16-bit boundary
536536
unsigned image_height = height;
537537
image_gray8 reduced_image(image_width,image_height);
538-
reduce_1(image,reduced_image,trees, limits, alphaTable);
538+
reduce_1(image,reduced_image,trees, limits, alpha_table);
539539
if (meanAlpha<255 && cols[0]==0)
540540
{
541-
alphaTable.resize(1);
542-
alphaTable[0] = meanAlpha;
541+
alpha_table.resize(1);
542+
alpha_table[0] = meanAlpha;
543543
}
544-
save_as_png(file,palette,reduced_image,width,height,1,alphaTable,opts);
544+
save_as_png(file,palette,reduced_image,width,height,1,alpha_table,opts);
545545
}
546546
else
547547
{
548548
// <=16 colors -> write 4-bit color depth PNG
549549
unsigned image_width = ((width + 7) >> 1) & ~3U; // 4-bit image, round up to 32-bit boundary
550550
unsigned image_height = height;
551551
image_gray8 reduced_image(image_width,image_height);
552-
reduce_4(image, reduced_image, trees, limits, TRANSPARENCY_LEVELS, alphaTable);
553-
save_as_png(file,palette,reduced_image,width,height,4,alphaTable,opts);
552+
reduce_4(image, reduced_image, trees, limits, TRANSPARENCY_LEVELS, alpha_table);
553+
save_as_png(file,palette,reduced_image,width,height,4,alpha_table,opts);
554554
}
555555
}
556556

@@ -560,7 +560,7 @@ void save_as_png8(T1 & file,
560560
T2 const& image,
561561
T3 const & tree,
562562
std::vector<mapnik::rgb> const& palette,
563-
std::vector<unsigned> const& alphaTable,
563+
std::vector<unsigned> const& alpha_table,
564564
png_options const& opts)
565565
{
566566
unsigned width = image.width();
@@ -579,7 +579,7 @@ void save_as_png8(T1 & file,
579579
row_out[x] = tree.quantize(row[x]);
580580
}
581581
}
582-
save_as_png(file, palette, reduced_image, width, height, 8, alphaTable, opts);
582+
save_as_png(file, palette, reduced_image, width, height, 8, alpha_table, opts);
583583
}
584584
else if (palette.size() == 1)
585585
{
@@ -588,7 +588,7 @@ void save_as_png8(T1 & file,
588588
unsigned image_height = height;
589589
image_gray8 reduced_image(image_width, image_height);
590590
reduced_image.set(0);
591-
save_as_png(file, palette, reduced_image, width, height, 1, alphaTable, opts);
591+
save_as_png(file, palette, reduced_image, width, height, 1, alpha_table, opts);
592592
}
593593
else
594594
{
@@ -612,7 +612,7 @@ void save_as_png8(T1 & file,
612612
row_out[x>>1] |= index;
613613
}
614614
}
615-
save_as_png(file, palette, reduced_image, width, height, 4, alphaTable, opts);
615+
save_as_png(file, palette, reduced_image, width, height, 4, alpha_table, opts);
616616
}
617617
}
618618

@@ -623,6 +623,7 @@ void save_as_png8_hex(T1 & file,
623623
{
624624
unsigned width = image.width();
625625
unsigned height = image.height();
626+
626627
if (width + height > 3) // at least 3 pixels (hextree implementation requirement)
627628
{
628629
// structure for color quantization
@@ -647,20 +648,44 @@ void save_as_png8_hex(T1 & file,
647648
}
648649

649650
//transparency values per palette index
650-
std::vector<mapnik::rgba> pal;
651-
tree.create_palette(pal);
651+
std::vector<mapnik::rgba> rgba_palette;
652+
tree.create_palette(rgba_palette);
653+
auto size = rgba_palette.size();
652654
std::vector<mapnik::rgb> palette;
653-
std::vector<unsigned> alphaTable;
654-
for (unsigned i=0; i<pal.size(); ++i)
655+
std::vector<unsigned> alpha_table;
656+
palette.reserve(size);
657+
alpha_table.reserve(size);
658+
for (auto const& c : rgba_palette)
655659
{
656-
palette.push_back(rgb(pal[i].r, pal[i].g, pal[i].b));
657-
alphaTable.push_back(pal[i].a);
660+
palette.emplace_back(c.r, c.g, c.b);
661+
alpha_table.push_back(c.a);
658662
}
659-
save_as_png8<T1, T2, hextree<mapnik::rgba> >(file, image, tree, palette, alphaTable, opts);
663+
save_as_png8<T1, T2, hextree<mapnik::rgba> >(file, image, tree, palette, alpha_table, opts);
660664
}
661665
else
662666
{
663-
throw std::runtime_error("Can't quantize images with less than 3 pixels");
667+
668+
std::set<mapnik::rgba> colors;
669+
for (unsigned y = 0; y < height; ++y)
670+
{
671+
typename T2::pixel_type const * row = image.get_row(y);
672+
673+
for (unsigned x = 0; x < width; ++x)
674+
{
675+
unsigned val = row[x];
676+
colors.emplace(U2RED(val), U2GREEN(val), U2BLUE(val), U2ALPHA(val));
677+
}
678+
}
679+
std::string str;
680+
for (auto c : colors)
681+
{
682+
str.push_back(c.r);
683+
str.push_back(c.g);
684+
str.push_back(c.b);
685+
str.push_back(c.a);
686+
}
687+
rgba_palette pal(str, rgba_palette::PALETTE_RGBA);
688+
save_as_png8<T1, T2, rgba_palette>(file, image, pal, pal.palette(), pal.alpha_table(), opts);
664689
}
665690
}
666691

@@ -670,7 +695,7 @@ void save_as_png8_pal(T1 & file,
670695
rgba_palette const& pal,
671696
png_options const& opts)
672697
{
673-
save_as_png8<T1, T2, rgba_palette>(file, image, pal, pal.palette(), pal.alphaTable(), opts);
698+
save_as_png8<T1, T2, rgba_palette>(file, image, pal, pal.palette(), pal.alpha_table(), opts);
674699
}
675700

676701
}

src/palette.cpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -65,16 +65,6 @@ rgba_palette::rgba_palette()
6565
#endif
6666
}
6767

68-
const std::vector<rgb>& rgba_palette::palette() const
69-
{
70-
return rgb_pal_;
71-
}
72-
73-
const std::vector<unsigned>& rgba_palette::alphaTable() const
74-
{
75-
return alpha_pal_;
76-
}
77-
7868
bool rgba_palette::valid() const
7969
{
8070
return colors_ > 0;

0 commit comments

Comments
 (0)