Blender V4.5
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 "BLI_bounds.hh"
6
8#include "BKE_scene.hh"
9
11
13#include "DNA_scene_types.h"
14
15#include "grease_pencil_io.hh"
17
18#include "hpdf.h"
19
20#include <iostream>
21
25
27
29 public:
31
32 HPDF_Doc pdf_;
33 HPDF_Page page_;
34
35 bool export_scene(Scene &scene, StringRefNull filepath);
36 void export_grease_pencil_objects(int frame_number);
37 void export_grease_pencil_layer(const Object &object,
38 const bke::greasepencil::Layer &layer,
39 const bke::greasepencil::Drawing &drawing);
40
41 bool create_document();
42 bool add_page();
43
45 const Span<float3> positions,
46 const bool cyclic,
48 const float opacity,
49 std::optional<float> width);
50 bool write_to_file(StringRefNull filepath);
51};
52
54{
55 bool result = false;
56 Object &ob_eval = *DEG_get_evaluated(context_.depsgraph, params_.object);
57
58 if (!create_document()) {
59 return false;
60 }
61
62 switch (params_.frame_mode) {
64 const int frame_number = scene.r.cfra;
65
66 this->prepare_render_params(scene, frame_number);
67 this->add_page();
68 this->export_grease_pencil_objects(frame_number);
69 result = this->write_to_file(filepath);
70 break;
71 }
74 const bool only_selected = (params_.frame_mode == ExportParams::FrameMode::Selected);
75 if (only_selected && ob_eval.type != OB_GREASE_PENCIL) {
76 /* For exporting "Selected Frames", the active object is required to be a grease pencil
77 * object, from which we will read selected frames from. */
78 break;
79 }
80 const int orig_frame = scene.r.cfra;
81 for (int frame_number = scene.r.sfra; frame_number <= scene.r.efra; frame_number++) {
82 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob_eval.data);
83 if (only_selected && !this->is_selected_frame(grease_pencil, frame_number)) {
84 continue;
85 }
86
87 scene.r.cfra = frame_number;
89
90 this->prepare_render_params(scene, frame_number);
91 this->add_page();
92 this->export_grease_pencil_objects(frame_number);
93 }
94
95 result = this->write_to_file(filepath);
96
97 /* Back to original frame. */
98 scene.r.cfra = orig_frame;
101 break;
102 }
103 default:
104 break;
105 }
106
107 return result;
108}
109
111{
113
115
116 for (const ObjectInfo &info : objects) {
117 const Object *ob = info.object;
118
119 /* Use evaluated version to get strokes with modifiers. */
120 const Object *ob_eval = DEG_get_evaluated(context_.depsgraph, ob);
121 BLI_assert(ob_eval->type == OB_GREASE_PENCIL);
122 const GreasePencil *grease_pencil_eval = static_cast<const GreasePencil *>(ob_eval->data);
123
124 for (const bke::greasepencil::Layer *layer : grease_pencil_eval->layers()) {
125 if (!layer->is_visible()) {
126 continue;
127 }
128 const Drawing *drawing = grease_pencil_eval->get_drawing_at(*layer, frame_number);
129 if (drawing == nullptr) {
130 continue;
131 }
132
133 export_grease_pencil_layer(*ob_eval, *layer, *drawing);
134 }
135 }
136}
137
139 const bke::greasepencil::Layer &layer,
140 const bke::greasepencil::Drawing &drawing)
141{
143
144 const float4x4 layer_to_world = layer.to_world_space(object);
145
146 auto write_stroke = [&](const Span<float3> positions,
147 const bool cyclic,
148 const ColorGeometry4f &color,
149 const float opacity,
150 const std::optional<float> width,
151 const bool /*round_cap*/,
152 const bool /*is_outline*/) {
153 write_stroke_to_polyline(layer_to_world, positions, cyclic, color, opacity, width);
154 };
155
156 foreach_stroke_in_layer(object, layer, drawing, write_stroke);
157}
158
160{
161 auto hpdf_error_handler = [](HPDF_STATUS error_no, HPDF_STATUS detail_no, void * /*user_data*/) {
162 printf("ERROR: error_no=%04X, detail_no=%u\n", (HPDF_UINT)error_no, (HPDF_UINT)detail_no);
163 };
164
165 pdf_ = HPDF_New(hpdf_error_handler, nullptr);
166 if (!pdf_) {
167 std::cout << "error: cannot create PdfDoc object\n";
168 return false;
169 }
170 return true;
171}
172
174{
175 page_ = HPDF_AddPage(pdf_);
176 if (!pdf_) {
177 std::cout << "error: cannot create PdfPage\n";
178 return false;
179 }
180
181 if (camera_persmat_) {
182 HPDF_Page_SetWidth(page_, camera_rect_.size().x);
183 HPDF_Page_SetHeight(page_, camera_rect_.size().y);
184 }
185 else {
186 HPDF_Page_SetWidth(page_, screen_rect_.size().x);
187 HPDF_Page_SetHeight(page_, screen_rect_.size().y);
188 }
189
190 return true;
191}
192
194 const Span<float3> positions,
195 const bool cyclic,
196 const ColorGeometry4f &color,
197 const float opacity,
198 const std::optional<float> width)
199{
200 if (width) {
201 HPDF_Page_SetLineJoin(page_, HPDF_ROUND_JOIN);
202 HPDF_Page_SetLineWidth(page_, std::max(*width, 1.0f));
203 }
204
205 const float total_opacity = color.a * opacity;
206
207 HPDF_Page_GSave(page_);
208 HPDF_ExtGState gstate = (total_opacity < 1.0f) ? HPDF_CreateExtGState(pdf_) : nullptr;
209
210 ColorGeometry4f srgb;
212 if (width) {
213 HPDF_Page_SetRGBFill(page_, srgb.r, srgb.g, srgb.b);
214 HPDF_Page_SetRGBStroke(page_, srgb.r, srgb.g, srgb.b);
215 if (gstate) {
216 HPDF_ExtGState_SetAlphaFill(gstate, std::clamp(total_opacity, 0.0f, 1.0f));
217 HPDF_ExtGState_SetAlphaStroke(gstate, std::clamp(total_opacity, 0.0f, 1.0f));
218 }
219 }
220 else {
221 HPDF_Page_SetRGBFill(page_, srgb.r, srgb.g, srgb.b);
222 if (gstate) {
223 HPDF_ExtGState_SetAlphaFill(gstate, std::clamp(total_opacity, 0.0f, 1.0f));
224 }
225 }
226 if (gstate) {
227 HPDF_Page_SetExtGState(page_, gstate);
228 }
229
230 for (const int i : positions.index_range()) {
231 const float2 screen_co = this->project_to_screen(transform, positions[i]);
232 if (i == 0) {
233 HPDF_Page_MoveTo(page_, screen_co.x, screen_co.y);
234 }
235 else {
236 HPDF_Page_LineTo(page_, screen_co.x, screen_co.y);
237 }
238 }
239 if (cyclic) {
240 HPDF_Page_ClosePath(page_);
241 }
242
243 if (width) {
244 HPDF_Page_Stroke(page_);
245 }
246 else {
247 HPDF_Page_Fill(page_);
248 }
249
250 HPDF_Page_GRestore(page_);
251}
252
254{
255 /* Support unicode character paths on Windows. */
256 HPDF_STATUS result = 0;
257
258 /* TODO: It looks `libharu` does not support unicode. */
259#if 0 /* `ifdef WIN32` */
260 wchar_t *filepath_16 = alloc_utf16_from_8(filepath.c_str(), 0);
261 std::wstring wstr(filepath_16);
262 result = HPDF_SaveToFile(pdf_, wstr.c_str());
263 free(filepath_16);
264#else
265 result = HPDF_SaveToFile(pdf_, filepath.c_str());
266#endif
267
268 return (result == 0) ? true : false;
269}
270
271bool export_pdf(const IOContext &context,
272 const ExportParams &params,
273 Scene &scene,
274 StringRefNull filepath)
275{
276 PDFExporter exporter(context, params);
277 return exporter.export_scene(scene, filepath);
278}
279
280} // namespace blender::io::grease_pencil
Low-level operations for grease pencil.
bool BKE_scene_camera_switch_update(Scene *scene)
Definition scene.cc:2267
void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph)
Definition scene.cc:2697
#define BLI_assert(a)
Definition BLI_assert.h:46
void BLI_kdtree_nd_ free(KDTree *tree)
void linearrgb_to_srgb_v3_v3(float srgb[3], const float linear[3])
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
@ OB_GREASE_PENCIL
return true
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
ChannelStorageType r
Definition BLI_color.hh:93
ChannelStorageType g
Definition BLI_color.hh:93
ChannelStorageType b
Definition BLI_color.hh:93
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr const char * c_str() const
float4x4 to_world_space(const Object &object) 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)
bool is_selected_frame(const GreasePencil &grease_pencil, int frame_number) const
float2 project_to_screen(const float4x4 &transform, const float3 &position) const
GreasePencilExporter(const IOContext &context, const ExportParams &params)
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]
bool export_pdf(const IOContext &context, const ExportParams &params, Scene &scene, StringRefNull filepath)
MatBase< float, 4, 4 > float4x4
VecBase< float, 2 > float2
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
Definition BLI_color.hh:342
struct RenderData r
i
Definition text_draw.cc:230
wchar_t * alloc_utf16_from_8(const char *in8, size_t add)
Definition utfconv.cc:292