1 /*****************************************************************************
2 * drawing - A library for creating Excel XLSX drawing files.
3 *
4 * Used in conjunction with the libxlsxwriter library.
5 *
6 * Copyright 2014-2021, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
7 *
8 */
9
10 #include "xlsxwriter/xmlwriter.h"
11 #include "xlsxwriter/common.h"
12 #include "xlsxwriter/drawing.h"
13 #include "xlsxwriter/worksheet.h"
14 #include "xlsxwriter/utility.h"
15
16 #define LXW_OBJ_NAME_LENGTH 14 /* "Picture 65536", or "Chart 65536" */
17 /*
18 * Forward declarations.
19 */
20
21 /*****************************************************************************
22 *
23 * Private functions.
24 *
25 ****************************************************************************/
26
27 /*
28 * Create a new drawing collection.
29 */
30 lxw_drawing *
lxw_drawing_new(void)31 lxw_drawing_new(void)
32 {
33 lxw_drawing *drawing = calloc(1, sizeof(lxw_drawing));
34 GOTO_LABEL_ON_MEM_ERROR(drawing, mem_error);
35
36 drawing->drawing_objects = calloc(1, sizeof(struct lxw_drawing_objects));
37 GOTO_LABEL_ON_MEM_ERROR(drawing->drawing_objects, mem_error);
38
39 STAILQ_INIT(drawing->drawing_objects);
40
41 return drawing;
42
43 mem_error:
44 lxw_drawing_free(drawing);
45 return NULL;
46 }
47
48 /*
49 * Free a drawing object.
50 */
51 void
lxw_free_drawing_object(lxw_drawing_object * drawing_object)52 lxw_free_drawing_object(lxw_drawing_object *drawing_object)
53 {
54 if (!drawing_object)
55 return;
56
57 free(drawing_object->description);
58 free(drawing_object->tip);
59
60 free(drawing_object);
61 }
62
63 /*
64 * Free a drawing collection.
65 */
66 void
lxw_drawing_free(lxw_drawing * drawing)67 lxw_drawing_free(lxw_drawing *drawing)
68 {
69 lxw_drawing_object *drawing_object;
70
71 if (!drawing)
72 return;
73
74 if (drawing->drawing_objects) {
75 while (!STAILQ_EMPTY(drawing->drawing_objects)) {
76 drawing_object = STAILQ_FIRST(drawing->drawing_objects);
77 STAILQ_REMOVE_HEAD(drawing->drawing_objects, list_pointers);
78 lxw_free_drawing_object(drawing_object);
79 }
80
81 free(drawing->drawing_objects);
82 }
83
84 free(drawing);
85 }
86
87 /*
88 * Add a drawing object to the drawing collection.
89 */
90 void
lxw_add_drawing_object(lxw_drawing * drawing,lxw_drawing_object * drawing_object)91 lxw_add_drawing_object(lxw_drawing *drawing,
92 lxw_drawing_object *drawing_object)
93 {
94 STAILQ_INSERT_TAIL(drawing->drawing_objects, drawing_object,
95 list_pointers);
96 }
97
98 /*****************************************************************************
99 *
100 * XML functions.
101 *
102 ****************************************************************************/
103
104 /*
105 * Write the XML declaration.
106 */
107 STATIC void
_drawing_xml_declaration(lxw_drawing * self)108 _drawing_xml_declaration(lxw_drawing *self)
109 {
110 lxw_xml_declaration(self->file);
111 }
112
113 /*
114 * Write the <xdr:wsDr> element.
115 */
116 STATIC void
_write_drawing_workspace(lxw_drawing * self)117 _write_drawing_workspace(lxw_drawing *self)
118 {
119 struct xml_attribute_list attributes;
120 struct xml_attribute *attribute;
121 char xmlns_xdr[] = LXW_SCHEMA_DRAWING "/spreadsheetDrawing";
122 char xmlns_a[] = LXW_SCHEMA_DRAWING "/main";
123
124 LXW_INIT_ATTRIBUTES();
125
126 LXW_PUSH_ATTRIBUTES_STR("xmlns:xdr", xmlns_xdr);
127 LXW_PUSH_ATTRIBUTES_STR("xmlns:a", xmlns_a);
128
129 lxw_xml_start_tag(self->file, "xdr:wsDr", &attributes);
130
131 LXW_FREE_ATTRIBUTES();
132 }
133
134 /*
135 * Write the <xdr:col> element.
136 */
137 STATIC void
_drawing_write_col(lxw_drawing * self,char * data)138 _drawing_write_col(lxw_drawing *self, char *data)
139 {
140 lxw_xml_data_element(self->file, "xdr:col", data, NULL);
141 }
142
143 /*
144 * Write the <xdr:colOff> element.
145 */
146 STATIC void
_drawing_write_col_off(lxw_drawing * self,char * data)147 _drawing_write_col_off(lxw_drawing *self, char *data)
148 {
149 lxw_xml_data_element(self->file, "xdr:colOff", data, NULL);
150 }
151
152 /*
153 * Write the <xdr:row> element.
154 */
155 STATIC void
_drawing_write_row(lxw_drawing * self,char * data)156 _drawing_write_row(lxw_drawing *self, char *data)
157 {
158 lxw_xml_data_element(self->file, "xdr:row", data, NULL);
159 }
160
161 /*
162 * Write the <xdr:rowOff> element.
163 */
164 STATIC void
_drawing_write_row_off(lxw_drawing * self,char * data)165 _drawing_write_row_off(lxw_drawing *self, char *data)
166 {
167 lxw_xml_data_element(self->file, "xdr:rowOff", data, NULL);
168 }
169
170 /*
171 * Write the main part of the <xdr:from> and <xdr:to> elements.
172 */
173 STATIC void
_drawing_write_coords(lxw_drawing * self,lxw_drawing_coords * coords)174 _drawing_write_coords(lxw_drawing *self, lxw_drawing_coords *coords)
175 {
176 char data[LXW_UINT32_T_LENGTH];
177
178 lxw_snprintf(data, LXW_UINT32_T_LENGTH, "%u", coords->col);
179 _drawing_write_col(self, data);
180
181 lxw_snprintf(data, LXW_UINT32_T_LENGTH, "%u",
182 (uint32_t) coords->col_offset);
183 _drawing_write_col_off(self, data);
184
185 lxw_snprintf(data, LXW_UINT32_T_LENGTH, "%u", coords->row);
186 _drawing_write_row(self, data);
187
188 lxw_snprintf(data, LXW_UINT32_T_LENGTH, "%u",
189 (uint32_t) coords->row_offset);
190 _drawing_write_row_off(self, data);
191 }
192
193 /*
194 * Write the <xdr:from> element.
195 */
196 STATIC void
_drawing_write_from(lxw_drawing * self,lxw_drawing_coords * coords)197 _drawing_write_from(lxw_drawing *self, lxw_drawing_coords *coords)
198 {
199 lxw_xml_start_tag(self->file, "xdr:from", NULL);
200
201 _drawing_write_coords(self, coords);
202
203 lxw_xml_end_tag(self->file, "xdr:from");
204 }
205
206 /*
207 * Write the <xdr:to> element.
208 */
209 STATIC void
_drawing_write_to(lxw_drawing * self,lxw_drawing_coords * coords)210 _drawing_write_to(lxw_drawing *self, lxw_drawing_coords *coords)
211 {
212 lxw_xml_start_tag(self->file, "xdr:to", NULL);
213
214 _drawing_write_coords(self, coords);
215
216 lxw_xml_end_tag(self->file, "xdr:to");
217 }
218
219 /*
220 * Write the <a:hlinkClick> element.
221 */
222 STATIC void
_drawing_write_a_hlink_click(lxw_drawing * self,uint32_t rel_index,char * tip)223 _drawing_write_a_hlink_click(lxw_drawing *self, uint32_t rel_index, char *tip)
224 {
225 struct xml_attribute_list attributes;
226 struct xml_attribute *attribute;
227 char xmlns_r[] = "http://schemas.openxmlformats.org/"
228 "officeDocument/2006/relationships";
229 char r_id[LXW_MAX_ATTRIBUTE_LENGTH];
230
231 lxw_snprintf(r_id, LXW_ATTR_32, "rId%d", rel_index);
232
233 LXW_INIT_ATTRIBUTES();
234 LXW_PUSH_ATTRIBUTES_STR("xmlns:r", xmlns_r);
235 LXW_PUSH_ATTRIBUTES_STR("r:id", r_id);
236
237 if (tip)
238 LXW_PUSH_ATTRIBUTES_STR("tooltip", tip);
239
240 lxw_xml_empty_tag(self->file, "a:hlinkClick", &attributes);
241
242 LXW_FREE_ATTRIBUTES();
243 }
244
245 /*
246 * Write the <a16:creationId> element.
247 */
248 STATIC void
_drawing_write_a16_creation_id(lxw_drawing * self)249 _drawing_write_a16_creation_id(lxw_drawing *self)
250 {
251 struct xml_attribute_list attributes;
252 struct xml_attribute *attribute;
253 char xmlns[] = "http://schemas.microsoft.com/office/drawing/2014/main";
254
255 LXW_INIT_ATTRIBUTES();
256 LXW_PUSH_ATTRIBUTES_STR("xmlns:a16", xmlns);
257 LXW_PUSH_ATTRIBUTES_STR("id", "{00000000-0008-0000-0000-000002000000}");
258
259 lxw_xml_empty_tag(self->file, "a16:creationId", &attributes);
260
261 LXW_FREE_ATTRIBUTES();
262 }
263
264 /*
265 * Write the <adec:decorative> element.
266 */
267 STATIC void
_workbook_write_adec_decorative(lxw_drawing * self)268 _workbook_write_adec_decorative(lxw_drawing *self)
269 {
270 struct xml_attribute_list attributes;
271 struct xml_attribute *attribute;
272 char xmlns[] =
273 "http://schemas.microsoft.com/office/drawing/2017/decorative";
274
275 LXW_INIT_ATTRIBUTES();
276 LXW_PUSH_ATTRIBUTES_STR("xmlns:adec", xmlns);
277 LXW_PUSH_ATTRIBUTES_STR("val", "1");
278
279 lxw_xml_empty_tag(self->file, "adec:decorative", &attributes);
280
281 LXW_FREE_ATTRIBUTES();
282 }
283
284 /*
285 * Write the <a:ext> element.
286 */
287 STATIC void
_drawing_write_uri_ext(lxw_drawing * self,char * uri)288 _drawing_write_uri_ext(lxw_drawing *self, char *uri)
289 {
290 struct xml_attribute_list attributes;
291 struct xml_attribute *attribute;
292
293 LXW_INIT_ATTRIBUTES();
294 LXW_PUSH_ATTRIBUTES_STR("uri", uri);
295
296 lxw_xml_start_tag(self->file, "a:ext", &attributes);
297
298 LXW_FREE_ATTRIBUTES();
299 }
300
301 /*
302 * Write the decorative elements.
303 */
304 STATIC void
_workbook_write_decorative(lxw_drawing * self)305 _workbook_write_decorative(lxw_drawing *self)
306 {
307 lxw_xml_start_tag(self->file, "a:extLst", NULL);
308
309 _drawing_write_uri_ext(self, "{FF2B5EF4-FFF2-40B4-BE49-F238E27FC236}");
310 _drawing_write_a16_creation_id(self);
311 lxw_xml_end_tag(self->file, "a:ext");
312
313 _drawing_write_uri_ext(self, "{C183D7F6-B498-43B3-948B-1728B52AA6E4}");
314 _workbook_write_adec_decorative(self);
315 lxw_xml_end_tag(self->file, "a:ext");
316
317 lxw_xml_end_tag(self->file, "a:extLst");
318 }
319
320 /*
321 * Write the <xdr:cNvPr> element.
322 */
323 STATIC void
_drawing_write_c_nv_pr(lxw_drawing * self,char * object_name,uint32_t index,lxw_drawing_object * drawing_object)324 _drawing_write_c_nv_pr(lxw_drawing *self, char *object_name, uint32_t index,
325 lxw_drawing_object *drawing_object)
326 {
327 struct xml_attribute_list attributes;
328 struct xml_attribute *attribute;
329
330 char name[LXW_OBJ_NAME_LENGTH];
331 lxw_snprintf(name, LXW_OBJ_NAME_LENGTH, "%s %d", object_name, index);
332
333 LXW_INIT_ATTRIBUTES();
334
335 LXW_PUSH_ATTRIBUTES_INT("id", index + 1);
336 LXW_PUSH_ATTRIBUTES_STR("name", name);
337
338 if (drawing_object && drawing_object->description
339 && strlen(drawing_object->description)
340 && !drawing_object->decorative) {
341
342 LXW_PUSH_ATTRIBUTES_STR("descr", drawing_object->description);
343 }
344
345 if (drawing_object
346 && (drawing_object->url_rel_index || drawing_object->decorative)) {
347 lxw_xml_start_tag(self->file, "xdr:cNvPr", &attributes);
348
349 if (drawing_object->url_rel_index) {
350 /* Write the a:hlinkClick element. */
351 _drawing_write_a_hlink_click(self,
352 drawing_object->url_rel_index,
353 drawing_object->tip);
354 }
355
356 if (drawing_object->decorative) {
357 _workbook_write_decorative(self);
358 }
359
360 lxw_xml_end_tag(self->file, "xdr:cNvPr");
361 }
362 else {
363 lxw_xml_empty_tag(self->file, "xdr:cNvPr", &attributes);
364 }
365
366 LXW_FREE_ATTRIBUTES();
367 }
368
369 /*
370 * Write the <a:picLocks> element.
371 */
372 STATIC void
_drawing_write_a_pic_locks(lxw_drawing * self)373 _drawing_write_a_pic_locks(lxw_drawing *self)
374 {
375 struct xml_attribute_list attributes;
376 struct xml_attribute *attribute;
377
378 LXW_INIT_ATTRIBUTES();
379 LXW_PUSH_ATTRIBUTES_STR("noChangeAspect", "1");
380
381 lxw_xml_empty_tag(self->file, "a:picLocks", &attributes);
382
383 LXW_FREE_ATTRIBUTES();
384 }
385
386 /*
387 * Write the <xdr:cNvPicPr> element.
388 */
389 STATIC void
_drawing_write_c_nv_pic_pr(lxw_drawing * self)390 _drawing_write_c_nv_pic_pr(lxw_drawing *self)
391 {
392 lxw_xml_start_tag(self->file, "xdr:cNvPicPr", NULL);
393
394 /* Write the a:picLocks element. */
395 _drawing_write_a_pic_locks(self);
396
397 lxw_xml_end_tag(self->file, "xdr:cNvPicPr");
398 }
399
400 /*
401 * Write the <xdr:nvPicPr> element.
402 */
403 STATIC void
_drawing_write_nv_pic_pr(lxw_drawing * self,uint32_t index,lxw_drawing_object * drawing_object)404 _drawing_write_nv_pic_pr(lxw_drawing *self, uint32_t index,
405 lxw_drawing_object *drawing_object)
406 {
407 lxw_xml_start_tag(self->file, "xdr:nvPicPr", NULL);
408
409 /* Write the xdr:cNvPr element. */
410 _drawing_write_c_nv_pr(self, "Picture", index, drawing_object);
411
412 /* Write the xdr:cNvPicPr element. */
413 _drawing_write_c_nv_pic_pr(self);
414
415 lxw_xml_end_tag(self->file, "xdr:nvPicPr");
416 }
417
418 /*
419 * Write the <a:blip> element.
420 */
421 STATIC void
_drawing_write_a_blip(lxw_drawing * self,uint32_t index)422 _drawing_write_a_blip(lxw_drawing *self, uint32_t index)
423 {
424 struct xml_attribute_list attributes;
425 struct xml_attribute *attribute;
426 char xmlns_r[] = LXW_SCHEMA_OFFICEDOC "/relationships";
427 char r_id[LXW_MAX_ATTRIBUTE_LENGTH];
428
429 lxw_snprintf(r_id, LXW_ATTR_32, "rId%d", index);
430
431 LXW_INIT_ATTRIBUTES();
432 LXW_PUSH_ATTRIBUTES_STR("xmlns:r", xmlns_r);
433 LXW_PUSH_ATTRIBUTES_STR("r:embed", r_id);
434
435 lxw_xml_empty_tag(self->file, "a:blip", &attributes);
436
437 LXW_FREE_ATTRIBUTES();
438 }
439
440 /*
441 * Write the <a:fillRect> element.
442 */
443 STATIC void
_drawing_write_a_fill_rect(lxw_drawing * self)444 _drawing_write_a_fill_rect(lxw_drawing *self)
445 {
446 lxw_xml_empty_tag(self->file, "a:fillRect", NULL);
447 }
448
449 /*
450 * Write the <a:stretch> element.
451 */
452 STATIC void
_drawing_write_a_stretch(lxw_drawing * self)453 _drawing_write_a_stretch(lxw_drawing *self)
454 {
455 lxw_xml_start_tag(self->file, "a:stretch", NULL);
456
457 /* Write the a:fillRect element. */
458 _drawing_write_a_fill_rect(self);
459
460 lxw_xml_end_tag(self->file, "a:stretch");
461 }
462
463 /*
464 * Write the <xdr:blipFill> element.
465 */
466 STATIC void
_drawing_write_blip_fill(lxw_drawing * self,uint32_t index)467 _drawing_write_blip_fill(lxw_drawing *self, uint32_t index)
468 {
469 lxw_xml_start_tag(self->file, "xdr:blipFill", NULL);
470
471 /* Write the a:blip element. */
472 _drawing_write_a_blip(self, index);
473
474 /* Write the a:stretch element. */
475 _drawing_write_a_stretch(self);
476
477 lxw_xml_end_tag(self->file, "xdr:blipFill");
478 }
479
480 /*
481 * Write the <a:ext> element.
482 */
483 STATIC void
_drawing_write_a_ext(lxw_drawing * self,lxw_drawing_object * drawing_object)484 _drawing_write_a_ext(lxw_drawing *self, lxw_drawing_object *drawing_object)
485 {
486 struct xml_attribute_list attributes;
487 struct xml_attribute *attribute;
488
489 LXW_INIT_ATTRIBUTES();
490 LXW_PUSH_ATTRIBUTES_INT("cx", drawing_object->width);
491 LXW_PUSH_ATTRIBUTES_INT("cy", drawing_object->height);
492
493 lxw_xml_empty_tag(self->file, "a:ext", &attributes);
494
495 LXW_FREE_ATTRIBUTES();
496 }
497
498 /*
499 * Write the <a:off> element.
500 */
501 STATIC void
_drawing_write_a_off(lxw_drawing * self,lxw_drawing_object * drawing_object)502 _drawing_write_a_off(lxw_drawing *self, lxw_drawing_object *drawing_object)
503 {
504 struct xml_attribute_list attributes;
505 struct xml_attribute *attribute;
506
507 LXW_INIT_ATTRIBUTES();
508 LXW_PUSH_ATTRIBUTES_INT("x", drawing_object->col_absolute);
509 LXW_PUSH_ATTRIBUTES_INT("y", drawing_object->row_absolute);
510
511 lxw_xml_empty_tag(self->file, "a:off", &attributes);
512
513 LXW_FREE_ATTRIBUTES();
514 }
515
516 /*
517 * Write the <a:xfrm> element.
518 */
519 STATIC void
_drawing_write_a_xfrm(lxw_drawing * self,lxw_drawing_object * drawing_object)520 _drawing_write_a_xfrm(lxw_drawing *self, lxw_drawing_object *drawing_object)
521 {
522 lxw_xml_start_tag(self->file, "a:xfrm", NULL);
523
524 /* Write the a:off element. */
525 _drawing_write_a_off(self, drawing_object);
526
527 /* Write the a:ext element. */
528 _drawing_write_a_ext(self, drawing_object);
529
530 lxw_xml_end_tag(self->file, "a:xfrm");
531 }
532
533 /*
534 * Write the <a:avLst> element.
535 */
536 STATIC void
_drawing_write_a_av_lst(lxw_drawing * self)537 _drawing_write_a_av_lst(lxw_drawing *self)
538 {
539 lxw_xml_empty_tag(self->file, "a:avLst", NULL);
540 }
541
542 /*
543 * Write the <a:prstGeom> element.
544 */
545 STATIC void
_drawing_write_a_prst_geom(lxw_drawing * self)546 _drawing_write_a_prst_geom(lxw_drawing *self)
547 {
548 struct xml_attribute_list attributes;
549 struct xml_attribute *attribute;
550
551 LXW_INIT_ATTRIBUTES();
552 LXW_PUSH_ATTRIBUTES_STR("prst", "rect");
553
554 lxw_xml_start_tag(self->file, "a:prstGeom", &attributes);
555
556 /* Write the a:avLst element. */
557 _drawing_write_a_av_lst(self);
558
559 lxw_xml_end_tag(self->file, "a:prstGeom");
560
561 LXW_FREE_ATTRIBUTES();
562 }
563
564 /*
565 * Write the <xdr:spPr> element.
566 */
567 STATIC void
_drawing_write_sp_pr(lxw_drawing * self,lxw_drawing_object * drawing_object)568 _drawing_write_sp_pr(lxw_drawing *self, lxw_drawing_object *drawing_object)
569 {
570 lxw_xml_start_tag(self->file, "xdr:spPr", NULL);
571
572 /* Write the a:xfrm element. */
573 _drawing_write_a_xfrm(self, drawing_object);
574
575 /* Write the a:prstGeom element. */
576 _drawing_write_a_prst_geom(self);
577
578 lxw_xml_end_tag(self->file, "xdr:spPr");
579 }
580
581 /*
582 * Write the <xdr:pic> element.
583 */
584 STATIC void
_drawing_write_pic(lxw_drawing * self,uint32_t index,lxw_drawing_object * drawing_object)585 _drawing_write_pic(lxw_drawing *self, uint32_t index,
586 lxw_drawing_object *drawing_object)
587 {
588 lxw_xml_start_tag(self->file, "xdr:pic", NULL);
589
590 /* Write the xdr:nvPicPr element. */
591 _drawing_write_nv_pic_pr(self, index, drawing_object);
592
593 /* Write the xdr:blipFill element. */
594 _drawing_write_blip_fill(self, drawing_object->rel_index);
595
596 /* Write the xdr:spPr element. */
597 _drawing_write_sp_pr(self, drawing_object);
598
599 lxw_xml_end_tag(self->file, "xdr:pic");
600 }
601
602 /*
603 * Write the <xdr:clientData> element.
604 */
605 STATIC void
_drawing_write_client_data(lxw_drawing * self)606 _drawing_write_client_data(lxw_drawing *self)
607 {
608 lxw_xml_empty_tag(self->file, "xdr:clientData", NULL);
609 }
610
611 /*
612 * Write the <a:graphicFrameLocks> element.
613 */
614 STATIC void
_drawing_write_a_graphic_frame_locks(lxw_drawing * self)615 _drawing_write_a_graphic_frame_locks(lxw_drawing *self)
616 {
617 struct xml_attribute_list attributes;
618 struct xml_attribute *attribute;
619
620 LXW_INIT_ATTRIBUTES();
621 LXW_PUSH_ATTRIBUTES_INT("noGrp", 1);
622
623 lxw_xml_empty_tag(self->file, "a:graphicFrameLocks", &attributes);
624
625 LXW_FREE_ATTRIBUTES();
626 }
627
628 /*
629 * Write the <xdr:cNvGraphicFramePr> element.
630 */
631 STATIC void
_drawing_write_c_nv_graphic_frame_pr(lxw_drawing * self)632 _drawing_write_c_nv_graphic_frame_pr(lxw_drawing *self)
633 {
634 if (self->embedded) {
635 lxw_xml_empty_tag(self->file, "xdr:cNvGraphicFramePr", NULL);
636 }
637 else {
638 lxw_xml_start_tag(self->file, "xdr:cNvGraphicFramePr", NULL);
639
640 /* Write the a:graphicFrameLocks element. */
641 _drawing_write_a_graphic_frame_locks(self);
642
643 lxw_xml_end_tag(self->file, "xdr:cNvGraphicFramePr");
644 }
645 }
646
647 /*
648 * Write the <xdr:nvGraphicFramePr> element.
649 */
650 STATIC void
_drawing_write_nv_graphic_frame_pr(lxw_drawing * self,uint32_t index,lxw_drawing_object * drawing_object)651 _drawing_write_nv_graphic_frame_pr(lxw_drawing *self, uint32_t index,
652 lxw_drawing_object *drawing_object)
653 {
654 lxw_xml_start_tag(self->file, "xdr:nvGraphicFramePr", NULL);
655
656 /* Write the xdr:cNvPr element. */
657 _drawing_write_c_nv_pr(self, "Chart", index, drawing_object);
658
659 /* Write the xdr:cNvGraphicFramePr element. */
660 _drawing_write_c_nv_graphic_frame_pr(self);
661
662 lxw_xml_end_tag(self->file, "xdr:nvGraphicFramePr");
663 }
664
665 /*
666 * Write the <a:off> element.
667 */
668 STATIC void
_drawing_write_xfrm_offset(lxw_drawing * self)669 _drawing_write_xfrm_offset(lxw_drawing *self)
670 {
671 struct xml_attribute_list attributes;
672 struct xml_attribute *attribute;
673
674 LXW_INIT_ATTRIBUTES();
675 LXW_PUSH_ATTRIBUTES_STR("x", "0");
676 LXW_PUSH_ATTRIBUTES_STR("y", "0");
677
678 lxw_xml_empty_tag(self->file, "a:off", &attributes);
679
680 LXW_FREE_ATTRIBUTES();
681 }
682
683 /*
684 * Write the <a:ext> element.
685 */
686 STATIC void
_drawing_write_xfrm_extension(lxw_drawing * self)687 _drawing_write_xfrm_extension(lxw_drawing *self)
688 {
689 struct xml_attribute_list attributes;
690 struct xml_attribute *attribute;
691
692 LXW_INIT_ATTRIBUTES();
693 LXW_PUSH_ATTRIBUTES_STR("cx", "0");
694 LXW_PUSH_ATTRIBUTES_STR("cy", "0");
695
696 lxw_xml_empty_tag(self->file, "a:ext", &attributes);
697
698 LXW_FREE_ATTRIBUTES();
699 }
700
701 /*
702 * Write the <xdr:xfrm> element.
703 */
704 STATIC void
_drawing_write_xfrm(lxw_drawing * self)705 _drawing_write_xfrm(lxw_drawing *self)
706 {
707 lxw_xml_start_tag(self->file, "xdr:xfrm", NULL);
708
709 /* Write the a:off element. */
710 _drawing_write_xfrm_offset(self);
711
712 /* Write the a:ext element. */
713 _drawing_write_xfrm_extension(self);
714
715 lxw_xml_end_tag(self->file, "xdr:xfrm");
716 }
717
718 /*
719 * Write the <c:chart> element.
720 */
721 STATIC void
_drawing_write_chart(lxw_drawing * self,uint32_t index)722 _drawing_write_chart(lxw_drawing *self, uint32_t index)
723 {
724 struct xml_attribute_list attributes;
725 struct xml_attribute *attribute;
726 char xmlns_c[] = LXW_SCHEMA_DRAWING "/chart";
727 char xmlns_r[] = LXW_SCHEMA_OFFICEDOC "/relationships";
728 char r_id[LXW_MAX_ATTRIBUTE_LENGTH];
729
730 lxw_snprintf(r_id, LXW_ATTR_32, "rId%d", index);
731
732 LXW_INIT_ATTRIBUTES();
733 LXW_PUSH_ATTRIBUTES_STR("xmlns:c", xmlns_c);
734 LXW_PUSH_ATTRIBUTES_STR("xmlns:r", xmlns_r);
735 LXW_PUSH_ATTRIBUTES_STR("r:id", r_id);
736
737 lxw_xml_empty_tag(self->file, "c:chart", &attributes);
738
739 LXW_FREE_ATTRIBUTES();
740 }
741
742 /*
743 * Write the <a:graphicData> element.
744 */
745 STATIC void
_drawing_write_a_graphic_data(lxw_drawing * self,uint32_t index)746 _drawing_write_a_graphic_data(lxw_drawing *self, uint32_t index)
747 {
748 struct xml_attribute_list attributes;
749 struct xml_attribute *attribute;
750 char uri[] = LXW_SCHEMA_DRAWING "/chart";
751
752 LXW_INIT_ATTRIBUTES();
753 LXW_PUSH_ATTRIBUTES_STR("uri", uri);
754
755 lxw_xml_start_tag(self->file, "a:graphicData", &attributes);
756
757 /* Write the c:chart element. */
758 _drawing_write_chart(self, index);
759
760 lxw_xml_end_tag(self->file, "a:graphicData");
761
762 LXW_FREE_ATTRIBUTES();
763 }
764
765 /*
766 * Write the <a:graphic> element.
767 */
768 STATIC void
_drawing_write_a_graphic(lxw_drawing * self,uint32_t index)769 _drawing_write_a_graphic(lxw_drawing *self, uint32_t index)
770 {
771
772 lxw_xml_start_tag(self->file, "a:graphic", NULL);
773
774 /* Write the a:graphicData element. */
775 _drawing_write_a_graphic_data(self, index);
776
777 lxw_xml_end_tag(self->file, "a:graphic");
778 }
779
780 /*
781 * Write the <xdr:graphicFrame> element.
782 */
783 STATIC void
_drawing_write_graphic_frame(lxw_drawing * self,uint32_t index,uint32_t rel_index,lxw_drawing_object * drawing_object)784 _drawing_write_graphic_frame(lxw_drawing *self, uint32_t index,
785 uint32_t rel_index,
786 lxw_drawing_object *drawing_object)
787 {
788 struct xml_attribute_list attributes;
789 struct xml_attribute *attribute;
790
791 LXW_INIT_ATTRIBUTES();
792 LXW_PUSH_ATTRIBUTES_STR("macro", "");
793
794 lxw_xml_start_tag(self->file, "xdr:graphicFrame", &attributes);
795
796 /* Write the xdr:nvGraphicFramePr element. */
797 _drawing_write_nv_graphic_frame_pr(self, index, drawing_object);
798
799 /* Write the xdr:xfrm element. */
800 _drawing_write_xfrm(self);
801
802 /* Write the a:graphic element. */
803 _drawing_write_a_graphic(self, rel_index);
804
805 lxw_xml_end_tag(self->file, "xdr:graphicFrame");
806
807 LXW_FREE_ATTRIBUTES();
808 }
809
810 /*
811 * Write the <xdr:twoCellAnchor> element.
812 */
813 STATIC void
_drawing_write_two_cell_anchor(lxw_drawing * self,uint32_t index,lxw_drawing_object * drawing_object)814 _drawing_write_two_cell_anchor(lxw_drawing *self, uint32_t index,
815 lxw_drawing_object *drawing_object)
816 {
817 struct xml_attribute_list attributes;
818 struct xml_attribute *attribute;
819
820 LXW_INIT_ATTRIBUTES();
821
822 if (drawing_object->anchor == LXW_OBJECT_MOVE_DONT_SIZE)
823 LXW_PUSH_ATTRIBUTES_STR("editAs", "oneCell");
824 else if (drawing_object->anchor == LXW_OBJECT_DONT_MOVE_DONT_SIZE)
825 LXW_PUSH_ATTRIBUTES_STR("editAs", "absolute");
826
827 lxw_xml_start_tag(self->file, "xdr:twoCellAnchor", &attributes);
828
829 _drawing_write_from(self, &drawing_object->from);
830 _drawing_write_to(self, &drawing_object->to);
831
832 if (drawing_object->type == LXW_DRAWING_CHART) {
833 /* Write the xdr:graphicFrame element for charts. */
834 _drawing_write_graphic_frame(self, index, drawing_object->rel_index,
835 drawing_object);
836 }
837 else if (drawing_object->type == LXW_DRAWING_IMAGE) {
838 /* Write the xdr:pic element. */
839 _drawing_write_pic(self, index, drawing_object);
840 }
841 else {
842 /* Write the xdr:sp element for shapes. */
843 /* _drawing_write_sp(self, index, col_absolute, row_absolute, width,
844 height, shape); */
845 }
846
847 /* Write the xdr:clientData element. */
848 _drawing_write_client_data(self);
849
850 lxw_xml_end_tag(self->file, "xdr:twoCellAnchor");
851
852 LXW_FREE_ATTRIBUTES();
853 }
854
855 /*
856 * Write the <xdr:ext> element.
857 */
858 STATIC void
_drawing_write_ext(lxw_drawing * self,uint32_t cx,uint32_t cy)859 _drawing_write_ext(lxw_drawing *self, uint32_t cx, uint32_t cy)
860 {
861 struct xml_attribute_list attributes;
862 struct xml_attribute *attribute;
863
864 LXW_INIT_ATTRIBUTES();
865 LXW_PUSH_ATTRIBUTES_INT("cx", cx);
866 LXW_PUSH_ATTRIBUTES_INT("cy", cy);
867
868 lxw_xml_empty_tag(self->file, "xdr:ext", &attributes);
869
870 LXW_FREE_ATTRIBUTES();
871 }
872
873 /*
874 * Write the <xdr:pos> element.
875 */
876 STATIC void
_drawing_write_pos(lxw_drawing * self,int32_t x,int32_t y)877 _drawing_write_pos(lxw_drawing *self, int32_t x, int32_t y)
878 {
879 struct xml_attribute_list attributes;
880 struct xml_attribute *attribute;
881
882 LXW_INIT_ATTRIBUTES();
883 LXW_PUSH_ATTRIBUTES_INT("x", x);
884 LXW_PUSH_ATTRIBUTES_INT("y", y);
885
886 lxw_xml_empty_tag(self->file, "xdr:pos", &attributes);
887
888 LXW_FREE_ATTRIBUTES();
889 }
890
891 /*
892 * Write the <xdr:absoluteAnchor> element.
893 */
894 STATIC void
_drawing_write_absolute_anchor(lxw_drawing * self,uint32_t frame_index)895 _drawing_write_absolute_anchor(lxw_drawing *self, uint32_t frame_index)
896 {
897 lxw_xml_start_tag(self->file, "xdr:absoluteAnchor", NULL);
898
899 if (self->orientation == LXW_LANDSCAPE) {
900 /* Write the xdr:pos element. */
901 _drawing_write_pos(self, 0, 0);
902
903 /* Write the xdr:ext element. */
904 _drawing_write_ext(self, 9308969, 6078325);
905 }
906 else {
907 /* Write the xdr:pos element. */
908 _drawing_write_pos(self, 0, -47625);
909
910 /* Write the xdr:ext element. */
911 _drawing_write_ext(self, 6162675, 6124575);
912 }
913
914 _drawing_write_graphic_frame(self, frame_index, frame_index, NULL);
915
916 /* Write the xdr:clientData element. */
917 _drawing_write_client_data(self);
918
919 lxw_xml_end_tag(self->file, "xdr:absoluteAnchor");
920 }
921
922 /*****************************************************************************
923 *
924 * XML file assembly functions.
925 *
926 ****************************************************************************/
927
928 /*
929 * Assemble and write the XML file.
930 */
931 void
lxw_drawing_assemble_xml_file(lxw_drawing * self)932 lxw_drawing_assemble_xml_file(lxw_drawing *self)
933 {
934 uint32_t index;
935 lxw_drawing_object *drawing_object;
936
937 /* Write the XML declaration. */
938 _drawing_xml_declaration(self);
939
940 /* Write the xdr:wsDr element. */
941 _write_drawing_workspace(self);
942
943 if (self->embedded) {
944 index = 1;
945
946 STAILQ_FOREACH(drawing_object, self->drawing_objects, list_pointers) {
947 _drawing_write_two_cell_anchor(self, index, drawing_object);
948 index++;
949 }
950 }
951 else {
952 /* Write the xdr:absoluteAnchor element. Mainly for chartsheets. */
953 _drawing_write_absolute_anchor(self, 1);
954 }
955
956 lxw_xml_end_tag(self->file, "xdr:wsDr");
957 }
958
959 /*****************************************************************************
960 *
961 * Public functions.
962 *
963 ****************************************************************************/
964