Skip to content

Commit 6252e36

Browse files
committed
Resolving issue #6. Image_surface now properly preserves the data when creating from a data buffer. Also removed commented out code from entrypoint-win32.cpp and updated it to test image_surface usage.
1 parent 69c9578 commit 6252e36

File tree

3 files changed

+72
-54
lines changed

3 files changed

+72
-54
lines changed

win32/N3888_RefImpl/drawing.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,7 @@ namespace std {
542542
protected:
543543
::std::shared_ptr<::std::function<void(void* closure, ::std::vector<unsigned char>& data)>> _Create_from_png_fn;
544544
void* _Create_from_png_closure;
545+
::std::shared_ptr<::std::vector<unsigned char>> _Data;
545546
public:
546547
image_surface(const image_surface&) = default;
547548
image_surface& operator=(const image_surface&) = default;

win32/N3888_RefImpl/entrypoint-win32.cpp

Lines changed: 48 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,45 @@ void Draw(surface& surface) {
5454
context.set_source(pattern);
5555
context.paint();
5656

57+
context.save();
58+
const int width = 100;
59+
const int height = 100;
60+
const format fmt = format::rgb24;
61+
const int stride = format_stride_for_width(fmt, width);
62+
vector<unsigned char> data;
63+
for (int y = 0; y < height; y++) {
64+
for (int x = 0; x < stride; x++) {
65+
auto byte = x % 4;
66+
switch (byte)
67+
{
68+
case 0:
69+
data.push_back(0x7Fui8);
70+
break;
71+
case 1:
72+
data.push_back(0xFFui8);
73+
break;
74+
case 2:
75+
data.push_back(0ui8);
76+
break;
77+
case 3:
78+
data.push_back(0ui8);
79+
break;
80+
default:
81+
throw logic_error("We're MODing by 4, how do we have a value outside of [0,3]?");
82+
}
83+
}
84+
}
85+
auto imageSurfaceFromData = image_surface(data, fmt, width, height, stride);
86+
context.set_source_surface(imageSurfaceFromData, 400.0, 400.0);
87+
context.move_to(400.0, 400.0);
88+
context.rel_line_to(100.0, 0.0);
89+
context.rel_line_to(0.0, 100.0);
90+
context.rel_line_to(-100.0, 0.0);
91+
context.close_path();
92+
context.fill();
93+
imageSurfaceFromData.finish();
94+
context.restore();
95+
5796
context.save();
5897
matrix m;
5998
m.init_translate(300.0, 400.0);
@@ -79,7 +118,7 @@ void Draw(surface& surface) {
79118
context.set_source_rgb(0.0, 0.0, 0.0);
80119
context.stroke();
81120
context.restore();
82-
121+
83122
context.set_source_rgb(1.0, 1.0, 1.0);
84123
context.move_to(100.0, 100.0);
85124
context.select_font_face("Segoe UI", font_slant::normal, font_weight::normal);
@@ -99,53 +138,19 @@ void OnPaint(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
99138

100139
hdc = BeginPaint(hWnd, &ps);
101140

102-
//// GDI double-buffering. Adapted from the Python example here: http://cairographics.org/cookbook/win32quickstart/ .
103-
//RECT clientRect;
104-
//if (!GetClientRect(hWnd, &clientRect)) {
105-
// throw_get_last_error<logic_error>("Failed GetClientRect call.");
106-
//}
107-
//auto width = clientRect.right - clientRect.left;
108-
//auto height = clientRect.bottom - clientRect.top;
109-
110-
//// Create the off-screen buffer.
111-
112-
//// First create a compatible GDI drawing context.
113-
//auto bufferDC = CreateCompatibleDC(hdc);
114-
//throw_if_null<logic_error>(bufferDC, "Failed CreateCompatibleDC call.");
115-
116-
//// Then create a compatible bitmap. This is the off-screen buffer.
117-
//auto hBitmap = CreateCompatibleBitmap(hdc, width, height);
118-
//throw_if_null<logic_error>(hBitmap, "Failed CreateCompatibleBitmap call.");
119-
120-
//// Set the compatible bitmap as the object to draw to.
121-
//auto hOldBitmap = SelectObject(bufferDC, hBitmap);
122-
//throw_if_null<logic_error>(hOldBitmap, "Failed SelectObject call.");
123-
124-
// We always start by creating a surface. Typically the surface would be a member of a class and would not be repeatedly created.
125-
// Note that per the proposal, make_surface's parameters are implementation-defined.
141+
// To enable screenshot saving, we are using a global unique_ptr surface. I did not rewrite the boilerplate
142+
// Win32 code so that it'd be a class, hence the globals. Note that this would not work without using CS_OWNDC
143+
// when registering the window class since we could get a different HDC each time without that flag.
126144
if (g_psurface == nullptr) {
127-
g_psurface = unique_ptr<surface>(new surface(move(make_surface(cairo_win32_surface_create(/*bufferDC*/hdc)))));
145+
g_psurface = unique_ptr<surface>(new surface(move(make_surface(cairo_win32_surface_create(hdc)))));
128146
}
129147

130148
// Draw to the off-screen buffer.
131149
Draw(*g_psurface);
150+
151+
// Flush to ensure that it is drawn to the window.
132152
g_psurface->flush();
133-
//if (!BitBlt(hdc, 0, 0, width, height, bufferDC, clientRect.left, clientRect.top, SRCCOPY)) {
134-
// throw_get_last_error<logic_error>("Failed BitBlt call.");
135-
//}
136-
//// Blit the off-screen buffer to the screen.
137-
//if (!BitBlt(hdc, 0, 0, width, height, bufferDC, clientRect.left, clientRect.top, SRCCOPY)) {
138-
// throw_get_last_error<logic_error>("Failed BitBlt call.");
139-
//}
140-
141-
//// Restore the original bitmap.
142-
//throw_if_null<logic_error>(SelectObject(bufferDC, hOldBitmap), "Failed SelectObject call.");
143-
//if (!DeleteObject(hBitmap)) {
144-
// throw logic_error("Failed DeleteObject call.");
145-
//}
146-
//if (!DeleteDC(bufferDC)) {
147-
// throw logic_error("Failed DeleteDC call.");
148-
//}
153+
149154
EndPaint(hWnd, &ps);
150155
}
151156

@@ -270,7 +275,7 @@ void ShowSaveAsPNGDialog() {
270275
fsd->SetFileTypeIndex(1U), "Failed call to IFileDialog::SetFileTypeIndex.");
271276
throw_if_failed_hresult<logic_error>(
272277
fsd->SetDefaultExtension(L"png"), "Failed call to IFileDialog::SetDefaultExtension.");
273-
278+
274279
ComPtr<IKnownFolderManager> kfm;
275280
throw_if_failed_hresult<logic_error>(
276281
CoCreateInstance(CLSID_KnownFolderManager, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&kfm)), "Failed call to CoCreateInstance for IKnownFolderManager.");

win32/N3888_RefImpl/image_surface.cpp

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,74 +8,87 @@ using namespace std::experimental::drawing;
88
image_surface::image_surface(image_surface&& other) : surface(move(other)) {
99
_Create_from_png_fn = move(other._Create_from_png_fn);
1010
_Create_from_png_closure = move(other._Create_from_png_closure);
11+
_Data = move(other._Data);
1112
other._Create_from_png_fn = nullptr;
1213
other._Create_from_png_closure = nullptr;
14+
other._Data = nullptr;
1315
}
1416

1517
image_surface& image_surface::operator=(image_surface&& other) {
1618
if (this != &other) {
1719
surface::operator=(move(other));
1820
_Create_from_png_fn = move(other._Create_from_png_fn);
1921
_Create_from_png_closure = move(other._Create_from_png_closure);
22+
_Data = move(other._Data);
2023
other._Create_from_png_fn = nullptr;
2124
other._Create_from_png_closure = nullptr;
25+
other._Data = nullptr;
2226
}
2327
return *this;
2428
}
2529

2630
image_surface::image_surface(surface::native_handle_type nh, surface::native_handle_type map_of)
2731
: surface(nullptr)
2832
, _Create_from_png_fn(new ::std::function<void(void* closure, ::std::vector<unsigned char>& data)>)
29-
, _Create_from_png_closure() {
33+
, _Create_from_png_closure()
34+
, _Data(nullptr) {
3035
_Surface = shared_ptr<cairo_surface_t>(nh, [map_of](cairo_surface_t *mapped_surface) {
31-
cairo_surface_unmap_image(map_of, mapped_surface); });
36+
cairo_surface_unmap_image(map_of, mapped_surface); }
37+
);
3238
}
3339

3440
image_surface::image_surface(format format, int width, int height)
3541
: surface(nullptr)
3642
, _Create_from_png_fn(new ::std::function<void(void* closure, ::std::vector<unsigned char>& data)>)
37-
, _Create_from_png_closure() {
43+
, _Create_from_png_closure()
44+
, _Data(nullptr) {
3845
_Surface = shared_ptr<cairo_surface_t>(cairo_image_surface_create(_Format_to_cairo_format_t(format), width, height), &cairo_surface_destroy);
3946
_Throw_if_failed_status(_Cairo_status_t_to_status(cairo_surface_status(_Surface.get())));
4047
}
4148

4249
image_surface::image_surface(vector<unsigned char>& data, format format, int width, int height, int stride)
4350
: surface(nullptr)
4451
, _Create_from_png_fn(new ::std::function<void(void* closure, ::std::vector<unsigned char>& data)>)
45-
, _Create_from_png_closure() {
52+
, _Create_from_png_closure()
53+
, _Data(new vector<unsigned char>) {
4654
assert(stride == format_stride_for_width(format, width));
47-
_Surface = shared_ptr<cairo_surface_t>(cairo_image_surface_create_for_data(data.data(), _Format_to_cairo_format_t(format), width, height, stride), &cairo_surface_destroy);
55+
_Data->resize(height * stride);
56+
_Data->assign(begin(data), end(data));
57+
_Surface = shared_ptr<cairo_surface_t>(cairo_image_surface_create_for_data(_Data->data(), _Format_to_cairo_format_t(format), width, height, stride), &cairo_surface_destroy);
4858
_Throw_if_failed_status(_Cairo_status_t_to_status(cairo_surface_status(_Surface.get())));
4959
}
5060

5161
image_surface::image_surface(surface& other, format format, int width, int height)
5262
: surface(nullptr)
5363
, _Create_from_png_fn(new ::std::function<void(void* closure, ::std::vector<unsigned char>& data)>)
54-
, _Create_from_png_closure() {
64+
, _Create_from_png_closure()
65+
, _Data(nullptr) {
5566
_Surface = shared_ptr<cairo_surface_t>(cairo_surface_create_similar_image(other.native_handle(), _Format_to_cairo_format_t(format), width, height), &cairo_surface_destroy);
5667
_Throw_if_failed_status(_Cairo_status_t_to_status(cairo_surface_status(_Surface.get())));
5768
}
5869

5970
image_surface::image_surface(const string& filename)
6071
: surface(nullptr)
6172
, _Create_from_png_fn(new ::std::function<void(void* closure, ::std::vector<unsigned char>& data)>)
62-
, _Create_from_png_closure() {
73+
, _Create_from_png_closure()
74+
, _Data(nullptr) {
6375
_Surface = shared_ptr<cairo_surface_t>(cairo_image_surface_create_from_png(filename.c_str()), &cairo_surface_destroy);
6476
_Throw_if_failed_status(_Cairo_status_t_to_status(cairo_surface_status(_Surface.get())));
6577
}
6678

6779
image_surface::image_surface(::std::function<void(void* closure, vector<unsigned char>& data)> read_fn, void* closure)
6880
: surface(nullptr)
6981
, _Create_from_png_fn(new function<void(void*, vector<unsigned char>&)>(read_fn))
70-
, _Create_from_png_closure(closure) {
82+
, _Create_from_png_closure(closure)
83+
, _Data(nullptr) {
7184
_Surface = shared_ptr<cairo_surface_t>(cairo_image_surface_create_from_png_stream(&image_surface::_Cairo_create_from_png_stream, this), &cairo_surface_destroy);
7285
_Throw_if_failed_status(_Cairo_status_t_to_status(cairo_surface_status(_Surface.get())));
7386
_Create_from_png_closure = nullptr;
7487
*_Create_from_png_fn = nullptr;
7588
}
7689

7790
void image_surface::set_data(vector<unsigned char>& data) {
78-
auto expected_size = get_stride() * get_height();
91+
auto expected_size = static_cast<size_t>(get_stride() * get_height());
7992
if (data.size() != static_cast<uint64_t>(expected_size)) {
8093
throw drawing_exception(status::invalid_stride);
8194
}
@@ -86,15 +99,14 @@ void image_surface::set_data(vector<unsigned char>& data) {
8699
if (imageData == nullptr) {
87100
throw drawing_exception(status::null_pointer);
88101
}
89-
memmove(imageData, data.data(), expected_size);
102+
memcpy(imageData, data.data(), expected_size);
90103
}
91104

92105
vector<unsigned char> image_surface::get_data() {
93106
auto required_size = get_stride() * get_height();
94107
vector<unsigned char> data;
95108
auto imageData = cairo_image_surface_get_data(_Surface.get());
96109
if (imageData == nullptr) {
97-
//throw drawing_exception(status::null_pointer);
98110
data.clear();
99111
}
100112
else {

0 commit comments

Comments
 (0)