Blender V4.3
grease_pencil_io_export_pdf.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BKE_attribute.hh"
6#include "BKE_curves.hh"
8#include "BKE_material.h"
9#include "BKE_scene.hh"
10
12
14#include "DNA_material_types.h"
15#include "DNA_scene_types.h"
16
17#include "ED_view3d.hh"
18
19#include "grease_pencil_io.hh"
21
22#include "hpdf.h"
23
24#include <iostream>
25
31
33 public:
35
36 HPDF_Doc pdf_;
37 HPDF_Page page_;
38
39 bool export_scene(Scene &scene, StringRefNull filepath);
40 void export_grease_pencil_objects(int frame_number);
41 void export_grease_pencil_layer(const Object &object,
42 const bke::greasepencil::Layer &layer,
43 const bke::greasepencil::Drawing &drawing);
44
45 bool create_document();
46 bool add_page();
47
48 void write_stroke_to_polyline(const float4x4 &transform,
49 const Span<float3> positions,
50 const bool cyclic,
51 const ColorGeometry4f &color,
52 const float opacity,
53 std::optional<float> width);
54 bool write_to_file(StringRefNull filepath);
55};
56
57static bool is_selected_frame(const GreasePencil &grease_pencil, const int frame_number)
58{
59 for (const bke::greasepencil::Layer *layer : grease_pencil.layers()) {
60 if (layer->is_visible()) {
61 const GreasePencilFrame *frame = layer->frames().lookup_ptr(frame_number);
62 if ((frame != nullptr) && frame->is_selected()) {
63 return true;
64 }
65 }
66 }
67 return false;
68}
69
71{
72 bool result = false;
74
75 if (!create_document()) {
76 return false;
77 }
78
79 switch (params_.frame_mode) {
81 const int frame_number = scene.r.cfra;
82
83 this->prepare_render_params(scene, frame_number);
84 this->add_page();
85 this->export_grease_pencil_objects(frame_number);
86 result = this->write_to_file(filepath);
87 break;
88 }
91 const bool only_selected = (params_.frame_mode == ExportParams::FrameMode::Selected);
92 const int orig_frame = scene.r.cfra;
93 for (int frame_number = scene.r.sfra; frame_number <= scene.r.efra; frame_number++) {
94 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob_eval.data);
95 if (only_selected && !is_selected_frame(grease_pencil, frame_number)) {
96 continue;
97 }
98
99 scene.r.cfra = frame_number;
101
102 this->prepare_render_params(scene, frame_number);
103 this->add_page();
104 this->export_grease_pencil_objects(frame_number);
105 }
106
107 result = this->write_to_file(filepath);
108
109 /* Back to original frame. */
110 scene.r.cfra = orig_frame;
113 break;
114 }
115 default:
116 break;
117 }
118
119 return result;
120}
121
123{
125
127
128 for (const ObjectInfo &info : objects) {
129 const Object *ob = info.object;
130
131 /* Use evaluated version to get strokes with modifiers. */
132 Object *ob_eval = DEG_get_evaluated_object(context_.depsgraph, const_cast<Object *>(ob));
133 BLI_assert(ob_eval->type == OB_GREASE_PENCIL);
134 const GreasePencil *grease_pencil_eval = static_cast<const GreasePencil *>(ob_eval->data);
135
136 for (const bke::greasepencil::Layer *layer : grease_pencil_eval->layers()) {
137 if (!layer->is_visible()) {
138 continue;
139 }
140 const Drawing *drawing = grease_pencil_eval->get_drawing_at(*layer, frame_number);
141 if (drawing == nullptr) {
142 continue;
143 }
144
145 export_grease_pencil_layer(*ob_eval, *layer, *drawing);
146 }
147 }
148}
149
151 const bke::greasepencil::Layer &layer,
152 const bke::greasepencil::Drawing &drawing)
153{
155
156 const float4x4 layer_to_world = layer.to_world_space(object);
157
158 auto write_stroke = [&](const Span<float3> positions,
159 const bool cyclic,
160 const ColorGeometry4f &color,
161 const float opacity,
162 const std::optional<float> width,
163 const bool /*round_cap*/,
164 const bool /*is_outline*/) {
165 write_stroke_to_polyline(layer_to_world, positions, cyclic, color, opacity, width);
166 };
167
168 foreach_stroke_in_layer(object, layer, drawing, write_stroke);
169}
170
172{
173 auto hpdf_error_handler = [](HPDF_STATUS error_no, HPDF_STATUS detail_no, void * /*user_data*/) {
174 printf("ERROR: error_no=%04X, detail_no=%u\n", (HPDF_UINT)error_no, (HPDF_UINT)detail_no);
175 };
176
177 pdf_ = HPDF_New(hpdf_error_handler, nullptr);
178 if (!pdf_) {
179 std::cout << "error: cannot create PdfDoc object\n";
180 return false;
181 }
182 return true;
183}
184
186{
187 page_ = HPDF_AddPage(pdf_);
188 if (!pdf_) {
189 std::cout << "error: cannot create PdfPage\n";
190 return false;
191 }
192
193 HPDF_Page_SetWidth(page_, render_rect_.size().x);
194 HPDF_Page_SetHeight(page_, render_rect_.size().y);
195
196 return true;
197}
198
200 const Span<float3> positions,
201 const bool cyclic,
202 const ColorGeometry4f &color,
203 const float opacity,
204 const std::optional<float> width)
205{
206 if (width) {
207 HPDF_Page_SetLineJoin(page_, HPDF_ROUND_JOIN);
208 HPDF_Page_SetLineWidth(page_, std::max(*width, 1.0f));
209 }
210
211 const float total_opacity = color.a * opacity;
212
213 HPDF_Page_GSave(page_);
214 HPDF_ExtGState gstate = (total_opacity < 1.0f) ? HPDF_CreateExtGState(pdf_) : nullptr;
215
216 ColorGeometry4f srgb;
217 linearrgb_to_srgb_v3_v3(srgb, color);
218 if (width) {
219 HPDF_Page_SetRGBFill(page_, srgb.r, srgb.g, srgb.b);
220 HPDF_Page_SetRGBStroke(page_, srgb.r, srgb.g, srgb.b);
221 if (gstate) {
222 HPDF_ExtGState_SetAlphaFill(gstate, std::clamp(total_opacity, 0.0f, 1.0f));
223 HPDF_ExtGState_SetAlphaStroke(gstate, std::clamp(total_opacity, 0.0f, 1.0f));
224 }
225 }
226 else {
227 HPDF_Page_SetRGBFill(page_, srgb.r, srgb.g, srgb.b);
228 if (gstate) {
229 HPDF_ExtGState_SetAlphaFill(gstate, std::clamp(total_opacity, 0.0f, 1.0f));
230 }
231 }
232 if (gstate) {
233 HPDF_Page_SetExtGState(page_, gstate);
234 }
235
236 for (const int i : positions.index_range()) {
237 const float2 screen_co = this->project_to_screen(transform, positions[i]);
238 if (i == 0) {
239 HPDF_Page_MoveTo(page_, screen_co.x, screen_co.y);
240 }
241 else {
242 HPDF_Page_LineTo(page_, screen_co.x, screen_co.y);
243 }
244 }
245 if (cyclic) {
246 HPDF_Page_ClosePath(page_);
247 }
248
249 if (width) {
250 HPDF_Page_Stroke(page_);
251 }
252 else {
253 HPDF_Page_Fill(page_);
254 }
255
256 HPDF_Page_GRestore(page_);
257}
258
260{
261 /* Support unicode character paths on Windows. */
262 HPDF_STATUS result = 0;
263
264 /* TODO: It looks `libharu` does not support unicode. */
265#if 0 /* `ifdef WIN32` */
266 wchar_t *filepath_16 = alloc_utf16_from_8(filepath.c_str(), 0);
267 std::wstring wstr(filepath_16);
268 result = HPDF_SaveToFile(pdf_, wstr.c_str());
269 free(filepath_16);
270#else
271 result = HPDF_SaveToFile(pdf_, filepath.c_str());
272#endif
273
274 return (result == 0) ? true : false;
275}
276
277bool export_pdf(const IOContext &context,
278 const ExportParams &params,
279 Scene &scene,
280 StringRefNull filepath)
281{
282 PDFExporter exporter(context, params);
283 return exporter.export_scene(scene, filepath);
284}
285
286} // namespace blender::io::grease_pencil
Low-level operations for curves.
Low-level operations for grease pencil.
General operations, lookup, etc. for materials.
bool BKE_scene_camera_switch_update(Scene *scene)
Definition scene.cc:2213
void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph)
Definition scene.cc:2647
#define BLI_assert(a)
Definition BLI_assert.h:50
void BLI_kdtree_nd_ free(KDTree *tree)
void linearrgb_to_srgb_v3_v3(float srgb[3], const float linear[3])
Object * DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
@ OB_GREASE_PENCIL
ChannelStorageType r
Definition BLI_color.hh:88
ChannelStorageType g
Definition BLI_color.hh:88
ChannelStorageType b
Definition BLI_color.hh:88
constexpr const char * c_str() const
GreasePencilExporter(const IOContext &context, const ExportParams &params)
void prepare_render_params(Scene &scene, int frame_number)
void foreach_stroke_in_layer(const Object &object, const bke::greasepencil::Layer &layer, const bke::greasepencil::Drawing &drawing, WriteStrokeFn stroke_fn)
float2 project_to_screen(const float4x4 &transform, const float3 &position) const
void write_stroke_to_polyline(const float4x4 &transform, const Span< float3 > positions, const bool cyclic, const ColorGeometry4f &color, const float opacity, std::optional< float > width)
void export_grease_pencil_layer(const Object &object, const bke::greasepencil::Layer &layer, const bke::greasepencil::Drawing &drawing)
bool export_scene(Scene &scene, StringRefNull filepath)
#define printf
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
static bool is_selected_frame(const GreasePencil &grease_pencil, const int frame_number)
bool export_pdf(const IOContext &context, const ExportParams &params, Scene &scene, StringRefNull filepath)
wchar_t * alloc_utf16_from_8(const char *in8, size_t add)
Definition utfconv.cc:292