add a new member function of pixel_buffer for rotating image
This commit is contained in:
parent
9947d0c511
commit
6217232a31
@ -111,6 +111,7 @@ namespace nana
|
||||
void bitblt(const ::nana::rectangle& r_dst, const graphics& src); ///< Transfers the color data corresponding to r_dst from the src graphics to this graphics.
|
||||
void bitblt(const ::nana::rectangle& r_dst, const graphics& src, const point& p_src);///< Transfers the color data corresponding to r_dst from the src graphics at point p_src to this graphics.
|
||||
|
||||
void blend(const ::nana::rectangle& r, const ::nana::color&, double fade_rate);
|
||||
void blend(const ::nana::rectangle& s_r, graphics& dst, const point& d_pos, double fade_rate) const;///< blends with the dst object.
|
||||
|
||||
void blur(const ::nana::rectangle& r, std::size_t radius); ///< Blur process.
|
||||
@ -144,8 +145,6 @@ namespace nana
|
||||
unsigned bidi_string(const nana::point&, const wchar_t *, std::size_t len);
|
||||
unsigned bidi_string(const point& pos, const char*, std::size_t len);
|
||||
|
||||
void blend(const ::nana::rectangle& r, const ::nana::color&, double fade_rate);
|
||||
|
||||
void set_pixel(int x, int y, const ::nana::color&);
|
||||
void set_pixel(int x, int y);
|
||||
|
||||
@ -167,6 +166,7 @@ namespace nana
|
||||
void rectangle(const ::nana::rectangle&, bool solid);
|
||||
void rectangle(const ::nana::rectangle&, bool solid, const color&);
|
||||
void frame_rectangle(const ::nana::rectangle&, const color& left, const color& top, const color& right, const color& bottom);
|
||||
void frame_rectangle(const ::nana::rectangle&, const color&, unsigned gap);
|
||||
|
||||
void gradual_rectangle(const ::nana::rectangle&, const color& from, const color& to, bool vertical);
|
||||
void round_rectangle(const ::nana::rectangle&, unsigned radius_x, unsigned radius_y, const color&, bool solid, const color& color_if_solid);
|
||||
|
||||
@ -75,6 +75,7 @@ namespace nana{ namespace paint
|
||||
void blend(const nana::rectangle& s_r, drawable_type dw_dst, const nana::point& d_pos, double fade_rate) const;
|
||||
void blur(const nana::rectangle& r, std::size_t radius);
|
||||
|
||||
pixel_buffer rotate(double angle, const color& extend_color);
|
||||
private:
|
||||
std::shared_ptr<pixel_buffer_storage> storage_;
|
||||
};
|
||||
|
||||
@ -1112,6 +1112,29 @@ namespace paint
|
||||
line_to({ r.x, r.y }, left_clr);
|
||||
}
|
||||
|
||||
void graphics::frame_rectangle(const ::nana::rectangle& r, const color& clr, unsigned gap)
|
||||
{
|
||||
palette(false, clr);
|
||||
|
||||
if (r.width > gap * 2)
|
||||
{
|
||||
point left{ r.x + static_cast<int>(gap), r.y }, right{ r.right() - static_cast<int>(gap) - 1, r.y };
|
||||
line(left, right);
|
||||
|
||||
left.y = right.y = r.bottom() - 1;
|
||||
line(left, right);
|
||||
}
|
||||
|
||||
if (r.height > gap * 2)
|
||||
{
|
||||
point top{ r.x, r.y + static_cast<int>(gap) }, bottom{ r.x, r.bottom() - static_cast<int>(gap) - 1 };
|
||||
line(top, bottom);
|
||||
|
||||
top.x = bottom.x = r.right() - 1;
|
||||
line(top, bottom);
|
||||
}
|
||||
}
|
||||
|
||||
void graphics::gradual_rectangle(const ::nana::rectangle& rct, const ::nana::color& from, const ::nana::color& to, bool vertical)
|
||||
{
|
||||
#if defined(NANA_WINDOWS)
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
|
||||
#include <stdexcept>
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
|
||||
namespace nana{ namespace paint
|
||||
{
|
||||
@ -47,11 +48,36 @@ namespace nana{ namespace paint
|
||||
struct pixel_buffer::pixel_buffer_storage
|
||||
: private nana::noncopyable
|
||||
{
|
||||
pixel_buffer_storage& operator=(const pixel_buffer_storage&) = delete;
|
||||
|
||||
bool _m_alloc()
|
||||
{
|
||||
if (pixel_size.empty())
|
||||
return false;
|
||||
|
||||
std::unique_ptr<pixel_color_t[]> pxbuf{ new pixel_color_t[pixel_size.width * pixel_size.height] };
|
||||
#if defined(NANA_X11)
|
||||
auto & spec = nana::detail::platform_spec::instance();
|
||||
x11.image = ::XCreateImage(spec.open_display(), spec.screen_visual(), 32, ZPixmap, 0, reinterpret_cast<char*>(pxbuf.get()), pixel_size.width, pixel_size.height, 32, 0);
|
||||
x11.attached = false;
|
||||
if (!x11.image)
|
||||
throw std::runtime_error("Nana.pixel_buffer: XCreateImage failed");
|
||||
|
||||
if (static_cast<int>(bytes_per_line) != x11.image->bytes_per_line)
|
||||
{
|
||||
x11.image->data = nullptr;
|
||||
XDestroyImage(x11.image);
|
||||
throw std::runtime_error("Nana.pixel_buffer: Invalid pixel buffer context.");
|
||||
}
|
||||
#endif
|
||||
raw_pixel_buffer = pxbuf.release();
|
||||
return true;
|
||||
}
|
||||
public:
|
||||
const drawable_type drawable; //Attached handle
|
||||
const nana::rectangle valid_r;
|
||||
const nana::size pixel_size;
|
||||
pixel_color_t * raw_pixel_buffer;
|
||||
pixel_color_t * raw_pixel_buffer{ nullptr };
|
||||
const std::size_t bytes_per_line;
|
||||
bool alpha_channel{false};
|
||||
#if defined(NANA_X11)
|
||||
@ -86,37 +112,31 @@ namespace nana{ namespace paint
|
||||
}
|
||||
}img_pro;
|
||||
|
||||
pixel_buffer_storage(const pixel_buffer_storage& other) :
|
||||
drawable{ other.drawable },
|
||||
valid_r{ other.valid_r },
|
||||
pixel_size{ other.pixel_size },
|
||||
bytes_per_line{ other.bytes_per_line },
|
||||
alpha_channel{ other.alpha_channel },
|
||||
img_pro{ other.img_pro }
|
||||
{
|
||||
if (_m_alloc())
|
||||
std::memcpy(raw_pixel_buffer, other.raw_pixel_buffer, pixel_size.width * pixel_size.height);
|
||||
}
|
||||
|
||||
pixel_buffer_storage(std::size_t width, std::size_t height)
|
||||
: drawable(nullptr),
|
||||
valid_r(0, 0, static_cast<unsigned>(width), static_cast<unsigned>(height)),
|
||||
pixel_size(static_cast<unsigned>(width), static_cast<unsigned>(height)),
|
||||
raw_pixel_buffer(new pixel_color_t[width * height]),
|
||||
bytes_per_line(width * sizeof(pixel_color_t))
|
||||
{
|
||||
#if defined(NANA_X11)
|
||||
nana::detail::platform_spec & spec = nana::detail::platform_spec::instance();
|
||||
x11.image = ::XCreateImage(spec.open_display(), spec.screen_visual(), 32, ZPixmap, 0, reinterpret_cast<char*>(raw_pixel_buffer), width, height, 32, 0);
|
||||
x11.attached = false;
|
||||
if(nullptr == x11.image)
|
||||
{
|
||||
delete [] raw_pixel_buffer;
|
||||
throw std::runtime_error("Nana.pixel_buffer: XCreateImage failed");
|
||||
}
|
||||
|
||||
if(static_cast<int>(bytes_per_line) != x11.image->bytes_per_line)
|
||||
{
|
||||
x11.image->data = nullptr;
|
||||
XDestroyImage(x11.image);
|
||||
delete [] raw_pixel_buffer;
|
||||
throw std::runtime_error("Nana.pixel_buffer: Invalid pixel buffer context.");
|
||||
}
|
||||
#endif
|
||||
_m_alloc();
|
||||
}
|
||||
|
||||
pixel_buffer_storage(drawable_type drawable, const nana::rectangle& want_r)
|
||||
: drawable(drawable),
|
||||
valid_r(valid_rectangle(paint::detail::drawable_size(drawable), want_r)),
|
||||
pixel_size(valid_r),
|
||||
pixel_size(valid_r.dimension()),
|
||||
#if defined(NANA_WINDOWS)
|
||||
raw_pixel_buffer(reinterpret_cast<pixel_color_t*>(reinterpret_cast<char*>(drawable->pixbuf_ptr + valid_r.x) + drawable->bytes_per_line * valid_r.y)),
|
||||
bytes_per_line(drawable->bytes_per_line)
|
||||
@ -362,7 +382,7 @@ namespace nana{ namespace paint
|
||||
XDestroyImage(img);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
};//end struct pixel_buffer_storage
|
||||
|
||||
pixel_buffer::pixel_buffer(drawable_type drawable, const nana::rectangle& want_rectangle)
|
||||
{
|
||||
@ -1105,5 +1125,153 @@ namespace nana{ namespace paint
|
||||
if (overlap(r, ::nana::rectangle{ this->size() }, good_r))
|
||||
(*(sp->img_pro.blur))->process(*this, good_r, radius);
|
||||
}
|
||||
|
||||
|
||||
//x' = x*cos(angle) - y*sin(angle)
|
||||
//y' = y*cos(angle) - x*sin(angle)
|
||||
class calc_rotate
|
||||
{
|
||||
enum class angles
|
||||
{
|
||||
none, half_pi, pi, triangle_pi
|
||||
};
|
||||
public:
|
||||
calc_rotate(double angle, const basic_point<double>& origin):
|
||||
specific_{ _m_spec(angle) },
|
||||
sin_a_{ std::sin(angle * degree_) },
|
||||
cos_a_{ std::cos(angle * degree_) },
|
||||
origin_{ origin }
|
||||
{
|
||||
}
|
||||
|
||||
basic_point<double> from(const point& p)
|
||||
{
|
||||
switch (specific_)
|
||||
{
|
||||
case angles::half_pi:
|
||||
return{ p.y - origin_.y, origin_.x - p.x};
|
||||
case angles::pi:
|
||||
return{ origin_.x - p.x, origin_.y - p.y};
|
||||
case angles::triangle_pi:
|
||||
return{ origin_.y - p.y, p.x - origin_.x};
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return{
|
||||
(p.x - origin_.x) * cos_a_ + (p.y - origin_.y) * sin_a_,
|
||||
(p.y - origin_.y) * cos_a_ - (p.x - origin_.x) * sin_a_
|
||||
};
|
||||
}
|
||||
|
||||
basic_point<double> to(const point& p)
|
||||
{
|
||||
switch (specific_)
|
||||
{
|
||||
case angles::half_pi:
|
||||
return{ origin_.y - p.y, p.x - origin_.x };
|
||||
case angles::pi:
|
||||
return{ origin_.x - p.x, origin_.y - p.y };
|
||||
case angles::triangle_pi:
|
||||
return{ p.y - origin_.y, origin_.x - p.x };
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return{
|
||||
(p.x - origin_.x) * cos_a_ - (p.y - origin_.y) * sin_a_,
|
||||
(p.y - origin_.y) * cos_a_ + (p.x - origin_.x) * sin_a_
|
||||
};
|
||||
}
|
||||
private:
|
||||
static angles _m_spec(double angle)
|
||||
{
|
||||
if (90.0 == angle)
|
||||
return angles::half_pi;
|
||||
else if (180.0 == angle)
|
||||
return angles::pi;
|
||||
else if (270.0 == angle)
|
||||
return angles::triangle_pi;
|
||||
|
||||
return angles::none;
|
||||
}
|
||||
private:
|
||||
const angles specific_;
|
||||
const double degree_{ std::acos(-1) / 180 };
|
||||
const double sin_a_;
|
||||
const double cos_a_;
|
||||
const basic_point<double> origin_;
|
||||
};
|
||||
|
||||
pixel_buffer pixel_buffer::rotate(double angle, const color& extend_color)
|
||||
{
|
||||
auto sp = storage_.get();
|
||||
if (!sp)
|
||||
return{};
|
||||
|
||||
if (angle <= 0 || 360 <= angle)
|
||||
{
|
||||
return{*this};
|
||||
}
|
||||
|
||||
const basic_point<double> origin{ (sp->pixel_size.width - 1) / 2.0, (sp->pixel_size.height - 1) / 2.0 };
|
||||
calc_rotate point_rotate{ angle, origin };
|
||||
|
||||
nana::size size_rotated{ sp->pixel_size };
|
||||
|
||||
if (90 == angle || 270 == angle)
|
||||
{
|
||||
size_rotated.shift();
|
||||
}
|
||||
else
|
||||
{
|
||||
point pw, ph;
|
||||
if (angle < 180)
|
||||
{
|
||||
ph.x = static_cast<int>(sp->pixel_size.width);
|
||||
}
|
||||
else if (angle > 180)
|
||||
{
|
||||
pw.x = static_cast<int>(sp->pixel_size.width);
|
||||
}
|
||||
|
||||
size_rotated.width = static_cast<unsigned>(std::abs(point_rotate.from(pw).x) * 2) + 1;
|
||||
size_rotated.height = static_cast<unsigned>(std::abs(point_rotate.from(ph).y) * 2) + 1;
|
||||
}
|
||||
|
||||
pixel_buffer rotated_pxbuf{ size_rotated.width, size_rotated.height };
|
||||
|
||||
const basic_point<double> rotated_origin{ (size_rotated.width - 1) / 2.0, (size_rotated.height - 1) / 2.0 };
|
||||
|
||||
for (int y = 0; y < static_cast<int>(size_rotated.height); ++y)
|
||||
{
|
||||
auto buf = rotated_pxbuf.raw_ptr(y);
|
||||
|
||||
basic_point<double> dest{ -rotated_origin.x, y - rotated_origin.y };
|
||||
dest = dest + origin;
|
||||
|
||||
const int right_point = static_cast<int>(dest.x) + static_cast<int>(size_rotated.width);
|
||||
|
||||
const int source_right = static_cast<int>(sp->pixel_size.width);
|
||||
const int source_bottom = static_cast<int>(sp->pixel_size.height);
|
||||
|
||||
for (point point_dest{ static_cast<int>(dest.x), static_cast<int>(dest.y) }; point_dest.x < right_point; ++point_dest.x)
|
||||
{
|
||||
auto point_source = point_rotate.to(point_dest) + origin;
|
||||
|
||||
if (0 <= point_source.x && point_source.x <= static_cast<double>(sp->pixel_size.width - 1) && 0 <= point_source.y && point_source.y <= static_cast<double>(sp->pixel_size.height - 1))
|
||||
{
|
||||
*buf = this->raw_ptr(static_cast<std::size_t>(point_source.y))[static_cast<int>(point_source.x)];
|
||||
}
|
||||
else
|
||||
*buf = extend_color.px_color();
|
||||
|
||||
++buf;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return rotated_pxbuf;
|
||||
}
|
||||
}//end namespace paint
|
||||
}//end namespace nana
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user