00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <mapnik/octree.hpp>
00026 extern "C"
00027 {
00028 #include <png.h>
00029 }
00030
00031 namespace mapnik {
00032
00033 template <typename T>
00034 void write_data (png_structp png_ptr, png_bytep data, png_size_t length)
00035 {
00036 T * out = static_cast<T*>(png_get_io_ptr(png_ptr));
00037 out->write(reinterpret_cast<char*>(data), length);
00038 }
00039
00040 template <typename T>
00041 void flush_data (png_structp png_ptr)
00042 {
00043 T * out = static_cast<T*>(png_get_io_ptr(png_ptr));
00044 out->flush();
00045 }
00046
00047 template <typename T1, typename T2>
00048 void save_as_png(T1 & file , T2 const& image)
00049 {
00050 png_voidp error_ptr=0;
00051 png_structp png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING,
00052 error_ptr,0, 0);
00053
00054 if (!png_ptr) return;
00055
00056
00057 #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) && defined(PNG_MMX_CODE_SUPPORTED)
00058 png_uint_32 mask, flags;
00059 flags = png_get_asm_flags(png_ptr);
00060 mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE);
00061 png_set_asm_flags(png_ptr, flags | mask);
00062 #endif
00063 png_set_filter (png_ptr, 0, PNG_FILTER_NONE);
00064 png_infop info_ptr = png_create_info_struct(png_ptr);
00065 if (!info_ptr)
00066 {
00067 png_destroy_write_struct(&png_ptr,(png_infopp)0);
00068 return;
00069 }
00070 if (setjmp(png_jmpbuf(png_ptr)))
00071 {
00072 png_destroy_write_struct(&png_ptr, &info_ptr);
00073 return;
00074 }
00075 png_set_write_fn (png_ptr, &file, &write_data<T1>, &flush_data<T1>);
00076
00077
00078
00079 png_set_IHDR(png_ptr, info_ptr,image.width(),image.height(),8,
00080 PNG_COLOR_TYPE_RGB_ALPHA,PNG_INTERLACE_NONE,
00081 PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT);
00082 png_write_info(png_ptr, info_ptr);
00083 for (unsigned i=0;i<image.height();i++)
00084 {
00085 png_write_row(png_ptr,(png_bytep)image.getRow(i));
00086 }
00087
00088 png_write_end(png_ptr, info_ptr);
00089 png_destroy_write_struct(&png_ptr, &info_ptr);
00090 }
00091
00092 template <typename T>
00093 void reduce_8 (T const& in, ImageData8 & out, octree<rgb> & tree)
00094 {
00095 unsigned width = in.width();
00096 unsigned height = in.height();
00097 for (unsigned y = 0; y < height; ++y)
00098 {
00099 mapnik::ImageData32::pixel_type const * row = in.getRow(y);
00100 mapnik::ImageData8::pixel_type * row_out = out.getRow(y);
00101 for (unsigned x = 0; x < width; ++x)
00102 {
00103 unsigned val = row[x];
00104 mapnik::rgb c((val)&0xff, (val>>8)&0xff, (val>>16) & 0xff);
00105 uint8_t index = tree.quantize(c);
00106 row_out[x] = index;
00107 }
00108 }
00109 }
00110
00111 template <typename T>
00112 void reduce_4 (T const& in, ImageData8 & out, octree<rgb> & tree)
00113 {
00114 unsigned width = in.width();
00115 unsigned height = in.height();
00116
00117 for (unsigned y = 0; y < height; ++y)
00118 {
00119 mapnik::ImageData32::pixel_type const * row = in.getRow(y);
00120 mapnik::ImageData8::pixel_type * row_out = out.getRow(y);
00121
00122 for (unsigned x = 0; x < width; ++x)
00123 {
00124 unsigned val = row[x];
00125 mapnik::rgb c((val)&0xff, (val>>8)&0xff, (val>>16) & 0xff);
00126 uint8_t index = tree.quantize(c);
00127 if (x%2 > 0) index = index<<4;
00128 row_out[x>>1] |= index;
00129 }
00130 }
00131 }
00132
00133
00134 template <typename T>
00135 void reduce_1(T const&, ImageData8 & out, octree<rgb> &)
00136 {
00137 out.set(0);
00138 }
00139
00140 template <typename T>
00141 void save_as_png(T & file, std::vector<mapnik::rgb> & palette,
00142 mapnik::ImageData8 const& image,
00143 unsigned width,
00144 unsigned height,
00145 unsigned color_depth)
00146 {
00147 png_voidp error_ptr=0;
00148 png_structp png_ptr=png_create_write_struct(PNG_LIBPNG_VER_STRING,
00149 error_ptr,0, 0);
00150
00151 if (!png_ptr) return;
00152
00153
00154 #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) && defined(PNG_MMX_CODE_SUPPORTED)
00155 png_uint_32 mask, flags;
00156 flags = png_get_asm_flags(png_ptr);
00157 mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE);
00158 png_set_asm_flags(png_ptr, flags | mask);
00159 #endif
00160 png_set_filter (png_ptr, 0, PNG_FILTER_NONE);
00161 png_infop info_ptr = png_create_info_struct(png_ptr);
00162 if (!info_ptr)
00163 {
00164 png_destroy_write_struct(&png_ptr,(png_infopp)0);
00165 return;
00166 }
00167 if (setjmp(png_jmpbuf(png_ptr)))
00168 {
00169 png_destroy_write_struct(&png_ptr, &info_ptr);
00170 return;
00171 }
00172 png_set_write_fn (png_ptr, &file, &write_data<T>, &flush_data<T>);
00173
00174 png_set_IHDR(png_ptr, info_ptr,width,height,color_depth,
00175 PNG_COLOR_TYPE_PALETTE,PNG_INTERLACE_NONE,
00176 PNG_COMPRESSION_TYPE_DEFAULT,PNG_FILTER_TYPE_DEFAULT);
00177
00178 png_set_PLTE(png_ptr,info_ptr,reinterpret_cast<png_color*>(&palette[0]),palette.size());
00179
00180 png_write_info(png_ptr, info_ptr);
00181 for (unsigned i=0;i<height;i++)
00182 {
00183 png_write_row(png_ptr,(png_bytep)image.getRow(i));
00184 }
00185
00186 png_write_end(png_ptr, info_ptr);
00187 png_destroy_write_struct(&png_ptr, &info_ptr);
00188 }
00189
00190 template <typename T1,typename T2>
00191 void save_as_png256(T1 & file, T2 const& image)
00192 {
00193 octree<rgb> tree(256);
00194 unsigned width = image.width();
00195 unsigned height = image.height();
00196 for (unsigned y = 0; y < height; ++y)
00197 {
00198 typename T2::pixel_type const * row = image.getRow(y);
00199 for (unsigned x = 0; x < width; ++x)
00200 {
00201 unsigned val = row[x];
00202 tree.insert(mapnik::rgb((val)&0xff, (val>>8)&0xff, (val>>16) & 0xff));
00203 }
00204 }
00205
00206 std::vector<rgb> palette;
00207 tree.create_palette(palette);
00208 assert(palette.size() <= 256);
00209
00210 if (palette.size() > 16 )
00211 {
00212
00213 ImageData8 reduced_image(width,height);
00214 reduce_8(image,reduced_image,tree);
00215 save_as_png(file,palette,reduced_image,width,height,8);
00216 }
00217 else if (palette.size() == 1)
00218 {
00219
00220 unsigned image_width = (int(0.125*width) + 7)&~7;
00221 unsigned image_height = height;
00222 ImageData8 reduced_image(image_width,image_height);
00223 reduce_1(image,reduced_image,tree);
00224 save_as_png(file,palette,reduced_image,width,height,1);
00225 }
00226 else
00227 {
00228
00229 unsigned image_width = (int(0.5*width) + 3)&~3;
00230 unsigned image_height = height;
00231 ImageData8 reduced_image(image_width,image_height);
00232 reduce_4(image,reduced_image,tree);
00233 save_as_png(file,palette,reduced_image,width,height,4);
00234 }
00235 }
00236 }