#include "Rasterizer.hpp" #include #include // For rasterizing #include #include #include #include #include #include #include #include #include // For png compression #include namespace Slic3r { class Raster::Impl { public: using TPixelRenderer = agg::pixfmt_gray8; // agg::pixfmt_rgb24; using TRawRenderer = agg::renderer_base; using TPixel = TPixelRenderer::color_type; using TRawBuffer = agg::rendering_buffer; using TBuffer = std::vector; using TRendererAA = agg::renderer_scanline_aa_solid; static const TPixel ColorWhite; static const TPixel ColorBlack; using Origin = Raster::Origin; private: Raster::Resolution resolution_; Raster::PixelDim pxdim_; TBuffer buf_; TRawBuffer rbuf_; TPixelRenderer pixfmt_; TRawRenderer raw_renderer_; TRendererAA renderer_; Origin o_; std::function flipy_ = [](agg::path_storage&) {}; public: inline Impl(const Raster::Resolution& res, const Raster::PixelDim &pd, Origin o): resolution_(res), pxdim_(pd), buf_(res.pixels()), rbuf_(reinterpret_cast(buf_.data()), res.width_px, res.height_px, res.width_px*TPixelRenderer::num_components), pixfmt_(rbuf_), raw_renderer_(pixfmt_), renderer_(raw_renderer_), o_(o) { renderer_.color(ColorWhite); // If we would like to play around with gamma // ras.gamma(agg::gamma_power(1.0)); clear(); if(o_ == Origin::TOP_LEFT) flipy_ = [this](agg::path_storage& path) { path.flip_y(0, resolution_.height_px); }; } void draw(const ExPolygon &poly) { agg::rasterizer_scanline_aa<> ras; agg::scanline_p8 scanlines; auto&& path = to_path(poly.contour); flipy_(path); ras.add_path(path); for(auto h : poly.holes) { auto&& holepath = to_path(h); flipy_(holepath); ras.add_path(holepath); } agg::render_scanlines(ras, scanlines, renderer_); } inline void clear() { raw_renderer_.clear(ColorBlack); } inline TBuffer& buffer() { return buf_; } inline const Raster::Resolution resolution() { return resolution_; } inline Origin origin() const /*noexcept*/ { return o_; } private: double getPx(const Point& p) { return p(0) * SCALING_FACTOR/pxdim_.w_mm; } double getPy(const Point& p) { return p(1) * SCALING_FACTOR/pxdim_.h_mm; } agg::path_storage to_path(const Polygon& poly) { agg::path_storage path; auto it = poly.points.begin(); path.move_to(getPx(*it), getPy(*it)); while(++it != poly.points.end()) path.line_to(getPx(*it), getPy(*it)); path.line_to(getPx(poly.points.front()), getPy(poly.points.front())); return path; } }; const Raster::Impl::TPixel Raster::Impl::ColorWhite = Raster::Impl::TPixel(255); const Raster::Impl::TPixel Raster::Impl::ColorBlack = Raster::Impl::TPixel(0); Raster::Raster(const Resolution &r, const PixelDim &pd, Origin o): impl_(new Impl(r, pd, o)) {} Raster::Raster() {} Raster::~Raster() {} Raster::Raster(Raster &&m): impl_(std::move(m.impl_)) {} void Raster::reset(const Raster::Resolution &r, const Raster::PixelDim &pd) { // Free up the unnecessary memory and make sure it stays clear after // an exception auto o = impl_? impl_->origin() : Origin::TOP_LEFT; reset(r, pd, o); } void Raster::reset(const Raster::Resolution &r, const Raster::PixelDim &pd, Raster::Origin o) { impl_.reset(); impl_.reset(new Impl(r, pd, o)); } void Raster::reset() { impl_.reset(); } Raster::Resolution Raster::resolution() const { if(impl_) return impl_->resolution(); return Resolution(0, 0); } void Raster::clear() { assert(impl_); impl_->clear(); } void Raster::draw(const ExPolygon &poly) { assert(impl_); impl_->draw(poly); } void Raster::save(std::ostream& stream, Compression comp) { assert(impl_); switch(comp) { case Compression::PNG: { png::writer wr(stream); wr.set_bit_depth(8); wr.set_color_type(png::color_type_gray); wr.set_width(resolution().width_px); wr.set_height(resolution().height_px); wr.set_compression_type(png::compression_type_default); wr.write_info(); auto& b = impl_->buffer(); auto ptr = reinterpret_cast( b.data() ); unsigned stride = sizeof(Impl::TBuffer::value_type) * resolution().width_px; for(unsigned r = 0; r < resolution().height_px; r++, ptr+=stride) { wr.write_row(ptr); } break; } case Compression::RAW: { stream << "P5 " << impl_->resolution().width_px << " " << impl_->resolution().height_px << " " << "255 "; stream.write(reinterpret_cast(impl_->buffer().data()), impl_->buffer().size()*sizeof(Impl::TBuffer::value_type)); } } } }