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