Files
core/OdfFile/Reader/Converter/pptx_slide_context.cpp
Alexander Trofimov 76ee07f61c [copyright] Update copyright header
Co-authored-by: Alexander Trofimov <alexander.trofimov@onlyoffice.com>
Co-committed-by: Alexander Trofimov <alexander.trofimov@onlyoffice.com>
2026-05-14 08:23:56 +00:00

1141 lines
34 KiB
C++

/*
* Copyright (C) Ascensio System SIA, 2009-2026
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation, together with the
* additional terms provided in the LICENSE file.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: https://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA by email at info@onlyoffice.com
* or by postal mail at 20A-6 Ernesta Birznieka-Upisha Street, Riga,
* LV-1050, Latvia, European Union.
*
* The interactive user interfaces in modified versions of the Program
* are required to display Appropriate Legal Notices in accordance with
* Section 5 of the GNU AGPL version 3.
*
* No trademark rights are granted under this License.
*
* All non-code elements of the Product, including illustrations,
* icon sets, and technical writing content, are licensed under the
* Creative Commons Attribution-ShareAlike 4.0 International License:
* https://creativecommons.org/licenses/by-sa/4.0/legalcode
*
* This license applies only to such non-code elements and does not
* modify or replace the licensing terms applicable to the Program's
* source code, which remains licensed under the GNU Affero General
* Public License v3.
*
* SPDX-License-Identifier: AGPL-3.0-only
*/
#include <iostream>
#include <boost/algorithm/string.hpp>
#include <xml/simple_xml_writer.h>
#include <xml/utils.h>
#include "pptx_drawing.h"
#include "pptx_drawings.h"
#include "pptx_slide_context.h"
#include "../Format/odf_document.h"
#include "../Format/draw_common.h"
#include "drawing_object_description.h"
namespace cpdoccore {
namespace oox {
class pptx_drawings;
typedef _CP_PTR(pptx_drawings) pptx_drawings_ptr;
class pptx_slide_context::Impl
{
public:
struct _transition
{
bool Enabled;
std::wstring Type;
_CP_OPT(std::wstring) Speed;
_CP_OPT(int) Time;
_CP_OPT(int) PageTime;
_CP_OPT(std::wstring) Dir;
_CP_OPT(std::wstring) Param;
bool onClick;
};
Impl(const std::wstring & _odfPacket) : odfPacket_(_odfPacket)
{
mediaitems_ = boost::make_shared<mediaitems>(odfPacket_);
clear();
}
drawing_object_description object_description_;
std::vector<drawing_object_description> objects_;
_CP_OPT(_oox_fill) background_fill_;
_transition transition_;
bool use_image_replacement_;
bool processing_notes;
bool header, footer, date_time, slideNum;
// NOTE: Key - ODF draw:id(xml:id), value - OOX ShapeID
// NOTE: draw:id is deprecated. Instead prefer using xml:id.
// draw:id and xml:id MUST be equal to each other
typedef std::unordered_map<std::wstring, size_t> id_map;
id_map id_map_;
void add_drawing(_pptx_drawing const & d, bool isInternal, std::wstring const & rid, std::wstring const & ref, _rels_type type)
{
pptx_drawings_->add(d, isInternal, rid, ref, type);
}
void add_additional_rels (bool isInternal, std::wstring const & rid, std::wstring const & ref, _rels_type type)
{
pptx_drawings_->add(isInternal, rid, ref, type);
}
mediaitems_ptr & get_mediaitems() { return mediaitems_; }
bool empty() const
{
return pptx_drawings_->empty();
}
void clear()
{
objects_.clear();
id_map_.clear();
background_fill_ = boost::none;
header = false;
footer = false;
date_time = false;
slideNum = false;
// NOTE: In PowerPoint p:nvGrpSpPr MUST have id = 1
// Otherwise animation are still working correctly but other element's IDs don't match to its animations in animation editor of PowerPoint
// Reserve "id = 1" for p:nvGrpSpPr
rId_ = 2;
pptx_drawings_ = pptx_drawings::create();
transition_.Enabled = false;
transition_.Speed = boost::none;
transition_.onClick = true;
processing_notes = false;
}
size_t next_rId()
{
return rId_++;;
}
pptx_drawings_ptr get_drawings()
{
return pptx_drawings_;
}
size_t generate_id(const std::wstring& id)
{
size_t result = next_rId();
id_map_.insert(std::make_pair(id, result));
return result;
}
size_t get_id(const std::wstring& id)
{
if (id == L"")
return next_rId();
id_map::iterator it = id_map_.find(id);
if (it == id_map_.end())
return generate_id(id);
return it->second;
}
size_t find_id(const std::wstring& id)
{
id_map::iterator it = id_map_.find(id);
if (it == id_map_.end())
return 0;
return it->second;
}
std::wstring odfPacket_;
void process_drawings();
void process_crop(_oox_fill& fill, const std::wstring& filename);
private:
void process_common_properties(drawing_object_description& obj, _pptx_drawing & drawing);
void process_shape (drawing_object_description& obj, _pptx_drawing & drawing);
void process_image (drawing_object_description& obj, _pptx_drawing & drawing);
void process_chart (drawing_object_description& obj, _pptx_drawing & drawing);
void process_table (drawing_object_description& obj, _pptx_drawing & drawing);
void process_object (drawing_object_description& obj, _pptx_drawing & drawing);
void process_media (drawing_object_description& obj, _pptx_drawing & drawing);
void process_control(drawing_object_description& obj, _pptx_drawing& drawing);
size_t rId_;
mediaitems_ptr mediaitems_;
pptx_drawings_ptr pptx_drawings_;
pptx_drawings_ptr pptx_notes_drawings_;
};
void pptx_slide_context::Impl::process_drawings()
{
for (size_t i = 0; i < objects_.size(); i++)
{
_pptx_drawing drawing = _pptx_drawing();
drawing.type = objects_[i].type_;
drawing.name = objects_[i].name_;
drawing.id = get_id(objects_[i].xml_id_);
drawing.lined = objects_[i].lined_;
drawing.connector = objects_[i].connector_;
process_common_properties(objects_[i], drawing);
switch(objects_[i].type_)
{
case typeImage: process_image(objects_[i], drawing); break;
case typeChart: process_chart(objects_[i], drawing); break;
case typeShape: process_shape(objects_[i], drawing); break;
case typeTable: process_table(objects_[i], drawing); break;
case typeMedia: process_media(objects_[i], drawing); break;
case typeControl: process_control(objects_[i], drawing); break;
case typePDF:
case typeMsObject:
case typeOleObject: process_object(objects_[i], drawing); break;
}
}
for (size_t i = 0; i < pptx_drawings_->get_drawings().size(); i++)
{
_pptx_drawing& drawing = pptx_drawings_->get_drawings()[i];
if(!drawing.connector)
continue;
drawing.start_connection_shape_id = std::to_wstring(find_id(drawing.start_connection_shape_id));
drawing.end_connection_shape_id = std::to_wstring(find_id(drawing.end_connection_shape_id));
}
}
pptx_slide_context::pptx_slide_context(pptx_conversion_context & Context)
: impl_(new pptx_slide_context::Impl(Context.root()->get_folder())),
pptx_animation_context_()
{
hlinks_size_ = 0;
}
void pptx_slide_context::start_slide()
{
impl_->clear(); // objects
hlinks_size_ = 0;
default_set(); //for current object
}
/////////////////////////////////////////////////////////////////////////////////////////////////
void pptx_slide_context::start_slide_animation()
{
impl_->transition_.Enabled = true;
//default
impl_->transition_.Type = L"wipe";
impl_->transition_.Time = boost::none;
impl_->transition_.Dir = boost::none;
impl_->transition_.Param = boost::none;
//speed & onClick are set earlier
}
void pptx_slide_context::set_transitionFilter(std::wstring & type,_CP_OPT(std::wstring) & dir,_CP_OPT(std::wstring) & dop,_CP_OPT(int) & time)
{
impl_->transition_.Type = type;
impl_->transition_.Time = time; // don't confuse transition duration with transition effect duration (OO doesn't have it)
impl_->transition_.Dir = dir;
impl_->transition_.Param = dop;
}
void pptx_slide_context::set_transitionAction(bool val)
{
impl_->transition_.onClick = val;
}
void pptx_slide_context::set_transitionSpeed(std::wstring val)
{
if (val == L"medium") impl_->transition_.Speed = L"med";
else impl_->transition_.Speed = val;//fast / slow
}
/////////////////////////////////////////////////////////////////////////////////////////////////
void pptx_slide_context::default_set()
{
impl_->object_description_.bInner_ = false;
impl_->object_description_.type_ = typeUnknown;
impl_->object_description_.xlink_href_ = L"";
impl_->object_description_.name_ = L"";
impl_->object_description_.descriptor_ = L"";
impl_->object_description_.xml_id_ = L"";
impl_->object_description_.anchor_ = L"";
impl_->object_description_.additional_.clear();
impl_->object_description_.svg_rect_ = boost::none;
impl_->object_description_.connector_ = false;
impl_->object_description_.lined_ = false;
impl_->object_description_.hidden_ = false;
impl_->object_description_.start_shape_id = boost::none;
impl_->object_description_.start_shape_glue_point = boost::none;
impl_->object_description_.end_shape_id = boost::none;
impl_->object_description_.end_shape_glue_point = boost::none;
impl_->object_description_.draw_type_ = boost::none;
impl_->object_description_.hlinks_.clear();
impl_->object_description_.action_.clear();
impl_->object_description_.additional_.clear();
impl_->object_description_.fill_.clear();
impl_->use_image_replacement_ = false;
}
bool pptx_slide_context::is_slide_filepath(const std::wstring& filename)
{
return boost::algorithm::contains(filename, L"slide") && boost::algorithm::ends_with(filename, L".xml");
}
void pptx_slide_context::set_use_image_replacement()
{
impl_->use_image_replacement_ = true;
}
void pptx_slide_context::set_is_placeHolder(bool is_placeholder)
{
impl_->object_description_.additional_.push_back(odf_reader::_property(L"IsPlaceholder", is_placeholder));
}
void pptx_slide_context::set_placeHolder_type(std::wstring typeHolder)
{
if (typeHolder == L"ftr") impl_->footer = true;
if (typeHolder == L"hdr") impl_->header = true;
if (typeHolder == L"dt") impl_->date_time = true;
if (typeHolder == L"sldNum")impl_->slideNum = true;
impl_->object_description_.additional_.push_back(odf_reader::_property(L"PlaceHolderType", typeHolder));
}
void pptx_slide_context::set_placeHolder_idx(int idx)
{
impl_->object_description_.additional_.push_back(odf_reader::_property(L"PlaceHolderIdx", idx));
}
void pptx_slide_context::set_rect(double width_pt, double height_pt, double x_pt, double y_pt)
{
impl_->object_description_.svg_rect_ = _rect(width_pt, height_pt, x_pt, y_pt);
}
void pptx_slide_context::set_rotate(double angle, bool translate)
{
set_property(odf_reader::_property(L"svg:rotate", angle));
if (impl_->object_description_.svg_rect_ && translate)
{
_rect &r = impl_->object_description_.svg_rect_.get();
double new_x = (r.cx / 2 * cos(-angle) - r.cy / 2 * sin(-angle) ) - r.cx / 2;
double new_y = (r.cx / 2 * sin(-angle) + r.cy / 2 * cos(-angle) ) - r.cy / 2;
r.x += new_x;
r.y += new_y;
}
}
void pptx_slide_context::set_translate(double x_pt, double y_pt)
{
if (impl_->object_description_.svg_rect_)
{
_rect & r = impl_->object_description_.svg_rect_.get();
r.x += x_pt;
r.y += y_pt;
}
}
void pptx_slide_context::set_scale(double cx_pt, double cy_pt)
{
if (impl_->object_description_.svg_rect_)
{
_rect & r = impl_->object_description_.svg_rect_.get();
r.x *= cx_pt;
r.y *= cy_pt;
}
}
void pptx_slide_context::set_anchor(std::wstring anchor, double x_pt, double y_pt)
{
impl_->object_description_.anchor_ = anchor;
impl_->object_description_.anchor_x_ = x_pt;
impl_->object_description_.anchor_y_ = y_pt;
}
void pptx_slide_context::set_property(odf_reader::_property p)
{
impl_->object_description_.additional_.push_back(p);
}
std::vector<odf_reader::_property> & pptx_slide_context::get_properties()
{
return impl_->object_description_.additional_;
}
void pptx_slide_context::set_fill(_oox_fill & fill)
{
impl_->object_description_.fill_= fill;
}
void pptx_slide_context::set_is_line_shape(bool val)
{
impl_->object_description_.lined_ = val;
}
void pptx_slide_context::set_is_connector_shape(bool val)
{
impl_->object_description_.connector_ = val;
}
void pptx_slide_context::set_connector_start_shape(const std::wstring& startShape)
{
impl_->object_description_.start_shape_id = startShape;
}
void pptx_slide_context::set_connector_end_shape(const std::wstring& endShape)
{
impl_->object_description_.end_shape_id = endShape;
}
void pptx_slide_context::set_connector_start_glue_point(int gluePoint)
{
impl_->object_description_.start_shape_glue_point = gluePoint;
}
void pptx_slide_context::set_connector_end_glue_point(int gluePoint)
{
impl_->object_description_.end_shape_glue_point = gluePoint;
}
void pptx_slide_context::set_connector_draw_type(const std::wstring& drawType)
{
impl_->object_description_.draw_type_ = drawType;
}
void pptx_slide_context::processing_notes(bool processing_notes)
{
impl_->processing_notes = processing_notes;
}
bool pptx_slide_context::processing_notes()
{
return impl_->processing_notes;
}
std::wstring pptx_slide_context::add_hyperlink(std::wstring const & href)
{
++hlinks_size_;
std::wstring hId = L"hId" + std::to_wstring(hlinks_size_);
std::wstring href_correct = XmlUtils::EncodeXmlString(href);
XmlUtils::replace_all( href_correct, L" .", L".");//1 (130).odt
_hlink_desc desc = {hId, href_correct};
impl_->object_description_.hlinks_.push_back(desc);
return hId;
}
void pptx_slide_context::add_background(_oox_fill & fill)
{
if (fill.bitmap)
{
bool isMediaInternal = false;
std::wstring ref;
fill.bitmap->rId = get_mediaitems()->add_or_find(fill.bitmap->xlink_href_, typeImage, isMediaInternal, ref, oox::document_place);
add_rels(isMediaInternal, fill.bitmap->rId, ref, typeImage);
std::wstring fileName = impl_->odfPacket_ + FILE_SEPARATOR_STR + fill.bitmap->xlink_href_;
impl_->process_crop(fill, fileName);
}
impl_->background_fill_ = fill;
}
void pptx_slide_context::set_name(std::wstring name)
{
boost::replace_all(name, L"&", L"&amp;");
impl_->object_description_.name_ = name;
}
void pptx_slide_context::set_id(std::wstring const& id)
{
impl_->object_description_.xml_id_ = id;
}
void pptx_slide_context::set_hidden(bool val)
{
impl_->object_description_.hidden_ = val;
}
void pptx_slide_context::start_shape(int type)
{
if (impl_->object_description_.bInner_) return;
impl_->object_description_.type_ = typeShape;
impl_->object_description_.shape_type_ = type; //2,3...
}
void pptx_slide_context::start_action(std::wstring action)
{
impl_->object_description_.action_.enabled = true;
if (action == L"sound")
{
//impl_->object_description_.action_.action = L"ppaction://noaction";
impl_->object_description_.action_.typeRels = typeAudio;
impl_->object_description_.action_.highlightClick = true;
}
else if (action == L"next-page")
{
impl_->object_description_.action_.action = L"ppaction://hlinkshowjump?jump=nextslide";
impl_->object_description_.action_.highlightClick = true;
}
else if (action == L"previous-page")
{
impl_->object_description_.action_.action = L"ppaction://hlinkshowjump?jump=previousslide";
impl_->object_description_.action_.highlightClick = true;
}
else if (action == L"first-page")
{
impl_->object_description_.action_.action = L"ppaction://hlinkshowjump?jump=firstslide";
impl_->object_description_.action_.highlightClick = true;
}
else if (action == L"last-page")
{
impl_->object_description_.action_.action = L"ppaction://hlinkshowjump?jump=lastslide";
impl_->object_description_.action_.highlightClick = true;
}
//ppaction://hlinkshowjump?jump=endshow
else if (action == L"execute")
{
impl_->object_description_.action_.action = L"ppaction://program";
impl_->object_description_.action_.typeRels = typeHyperlink;
impl_->object_description_.action_.highlightClick = true;
}
else if (action == L"show")
{
impl_->object_description_.action_.action = L"ppaction://hlinksldjump";
impl_->object_description_.action_.typeRels = typeSlide;
impl_->object_description_.action_.highlightClick = true;
}
}
void pptx_slide_context::set_link(std::wstring link, _rels_type typeRels)
{
++hlinks_size_;
impl_->object_description_.action_.highlightClick = true;
if (typeRels == typeAudio)
{
bool isMediaInternal = true;
impl_->object_description_.action_.hSoundId = get_mediaitems()->add_or_find(link, typeAudio, isMediaInternal, impl_->object_description_.action_.hSoundRef, oox::document_place);
impl_->add_additional_rels(isMediaInternal, impl_->object_description_.action_.hSoundId, impl_->object_description_.action_.hSoundRef, typeAudio);
}
else
{
impl_->object_description_.action_.typeRels = typeRels;
std::wstring hId = L"hId" + std::to_wstring(hlinks_size_);
link = XmlUtils::EncodeXmlString(link);
if (typeRels == typeHyperlink)
XmlUtils::replace_all( link, L" .", L"."); //1 (130).odt
impl_->object_description_.action_.hId = hId;
impl_->object_description_.action_.hRef = link;
if (!is_slide_filepath(link))
impl_->object_description_.action_.action = L"";
}
}
void pptx_slide_context::end_action()
{
}
void pptx_slide_context::start_table()
{
impl_->object_description_.type_ = typeTable;
}
void pptx_slide_context::set_text_box()
{
impl_->object_description_.type_ = typeShape;
impl_->object_description_.shape_type_ = 2; //2,3...
}
void pptx_slide_context::set_ms_object(const std::wstring & path, const std::wstring & progId)
{
impl_->object_description_.type_ = typeMsObject;
impl_->object_description_.xlink_href_ = path;
impl_->object_description_.descriptor_ = progId;
}
void pptx_slide_context::set_ole_object(const std::wstring & path, const std::wstring & progId)
{
impl_->object_description_.type_ = typeOleObject;
impl_->object_description_.xlink_href_ = path;
impl_->object_description_.descriptor_ = progId;
}
void pptx_slide_context::set_media(const std::wstring & path)
{
if (path.empty()) return;
impl_->object_description_.type_ = typeMedia;
impl_->object_description_.xlink_href_ = path;
impl_->object_description_.action_.enabled = true;
impl_->object_description_.action_.action = L"ppaction://media";
}
void pptx_slide_context::set_media_param(std::wstring name, std::wstring value)
{
}
void pptx_slide_context::set_image(const std::wstring & path)
{
size_t pos_replaicement = path.find(L"ObjectReplacements");
if (pos_replaicement != std::wstring::npos)
{
if (path.length() - (pos_replaicement + 18) < 2)
return; //object without image
}
bool bSvg = path.rfind(L".svg") == path.length() - 4;
bool bPdf = path.rfind(L".pdf") == path.length() - 4;
if (bSvg)
{
impl_->object_description_.xlink_href_ = path; // priority image
}
else if (bPdf)
{
if (impl_->object_description_.type_ == typeImage)
{
impl_->object_description_.fill_.type = 2;
impl_->object_description_.fill_.bitmap = oox::oox_bitmap_fill::create();
impl_->object_description_.fill_.bitmap->xlink_href_ = impl_->object_description_.xlink_href_;
impl_->object_description_.fill_.bitmap->bStretch = true;
}
impl_->object_description_.type_ = typePDF;
impl_->object_description_.descriptor_ = L"Acrobat.Document.DC";
impl_->object_description_.xlink_href_ = path;
impl_->use_image_replacement_ = true;
}
if (impl_->object_description_.type_ == typeUnknown)
{
impl_->object_description_.type_ = typeImage;
impl_->object_description_.xlink_href_ = path;
}
else if (impl_->use_image_replacement_)
{
impl_->object_description_.fill_.type = 2;
impl_->object_description_.fill_.bitmap = oox::oox_bitmap_fill::create();
impl_->object_description_.fill_.bitmap->xlink_href_ = path;
impl_->object_description_.fill_.bitmap->bStretch = true;
}
}
bool pptx_slide_context::start_frame()
{
if (impl_->object_description_.type_ != typeUnknown)
impl_->object_description_.bInner_ = true;
return impl_->object_description_.bInner_;
}
void pptx_slide_context::set_chart(const std::wstring & path)
{
impl_->object_description_.type_ = typeChart;
impl_->object_description_.xlink_href_ = path;
}
void pptx_slide_context::end_frame()
{
if (impl_->object_description_.bInner_)
impl_->object_description_.bInner_ = false;
else
{
impl_->objects_.push_back(impl_->object_description_);
default_set();
}
}
void pptx_slide_context::start_control(const std::wstring& ctrlPropId, int type)
{
impl_->object_description_.type_ = typeControl;
impl_->object_description_.shape_type_ = type; // object type for vml
impl_->object_description_.xlink_href_ = ctrlPropId;
}
void pptx_slide_context::end_control()
{
impl_->objects_.push_back(impl_->object_description_);
default_set();
}
void pptx_slide_context::end_shape()
{
impl_->objects_.push_back(impl_->object_description_);
default_set();
}
void pptx_slide_context::end_table()
{
}
bool pptx_slide_context::empty() const
{
return impl_->empty();
}
bool pptx_slide_context::isDefault()
{
return impl_->object_description_.type_ == typeUnknown;
}
void pptx_slide_context::process_drawings()
{
return impl_->process_drawings();
}
void pptx_slide_context::Impl::process_image(drawing_object_description& obj, _pptx_drawing & drawing)
{
int pos_replaicement = 0, pos_preview = 0;
drawing.fill.bitmap = oox_bitmap_fill::create();
drawing.fill.type = 2;
_CP_OPT(std::wstring) sTextContent;
_CP_OPT(double) dLuminance, dContrast;
GetProperty(obj.additional_, L"text-content", sTextContent);
GetProperty(obj.additional_, L"color-mode", drawing.fill.bitmap->color_mode);
GetProperty(obj.additional_, L"luminance", drawing.fill.bitmap->luminance);
GetProperty(obj.additional_, L"contrast", drawing.fill.bitmap->contrast);
if (sTextContent)//in ms office you can't add text to image - changing type to rect with image fill
{
drawing.type = typeShape;
drawing.sub_type = 2;//rect
}
std::wstring fileName = odfPacket_ + FILE_SEPARATOR_STR + obj.xlink_href_;
process_crop(drawing.fill, fileName);
///////////////////////////////////////////////////////////////////////////////////////////////////
std::wstring ref;/// this is a link to output external object
bool isMediaInternal = false;
drawing.fill.bitmap->rId = get_mediaitems()->add_or_find(obj.xlink_href_, typeImage, isMediaInternal, ref, oox::document_place);
drawing.fill.bitmap->isInternal = isMediaInternal;
if (drawing.type == typeShape)
{
add_additional_rels(isMediaInternal, drawing.fill.bitmap->rId, ref, typeImage);//actually this is not an object, but additional rel and object ref
isMediaInternal = true;
std::wstring rId = get_mediaitems()->add_or_find(L"", typeShape, isMediaInternal, ref, oox::document_place);
add_drawing(drawing, isMediaInternal, rId, ref, typeShape);//object
}
else if (!drawing.fill.bitmap->rId.empty())
{
add_drawing(drawing, isMediaInternal, drawing.fill.bitmap->rId, ref, drawing.type);//object
}
}
void pptx_slide_context::Impl::process_chart(drawing_object_description & obj, _pptx_drawing & drawing)
{
std::wstring ref;
bool isMediaInternal = true;
drawing.objectId = get_mediaitems()->add_or_find(obj.xlink_href_, obj.type_, isMediaInternal, ref, oox::document_place);
add_drawing(drawing, isMediaInternal, drawing.objectId, ref, drawing.type);
}
void pptx_slide_context::Impl::process_table(drawing_object_description & obj, _pptx_drawing & drawing)
{
std::wstring ref;
bool isMediaInternal = true;
std::wstring rId = get_mediaitems()->add_or_find(L"", obj.type_, isMediaInternal, ref, oox::document_place);
add_drawing(drawing, isMediaInternal, rId, ref, drawing.type);
}
void pptx_slide_context::Impl::process_control(drawing_object_description& obj, _pptx_drawing& drawing)
{
std::wstring ref;
bool isMediaInternal = true;
if (drawing.fill.bitmap)
{
drawing.fill.bitmap->rId = get_mediaitems()->add_or_find(drawing.fill.bitmap->xlink_href_, typeImage, isMediaInternal, ref, oox::document_place);
add_additional_rels(isMediaInternal, drawing.fill.bitmap->rId, ref, typeImage);
std::wstring fileName = odfPacket_ + FILE_SEPARATOR_STR + drawing.fill.bitmap->xlink_href_;
process_crop(drawing.fill, fileName);
}
std::wstring rId = get_mediaitems()->add_or_find(L"", obj.type_, isMediaInternal, ref, oox::document_place);
add_drawing(drawing, isMediaInternal, rId, ref, drawing.type);
}
void pptx_slide_context::Impl::process_shape(drawing_object_description & obj, _pptx_drawing & drawing)
{
int PlaceHolderIndex = 1;
std::wstring ref;
bool isMediaInternal = true;
if (drawing.fill.bitmap)
{
drawing.fill.bitmap->rId = get_mediaitems()->add_or_find(drawing.fill.bitmap->xlink_href_, typeImage, isMediaInternal, ref, oox::document_place);
add_additional_rels(isMediaInternal, drawing.fill.bitmap->rId, ref, typeImage);
std::wstring fileName = odfPacket_ + FILE_SEPARATOR_STR + drawing.fill.bitmap->xlink_href_;
process_crop(drawing.fill, fileName);
}
std::wstring rId = get_mediaitems()->add_or_find(L"", typeShape, isMediaInternal, ref, oox::document_place);
////////////////////////////////////////////////////////////////
_CP_OPT(std::wstring) sPlaceHolderType;
GetProperty(obj.additional_, L"PlaceHolderType", sPlaceHolderType);
if (sPlaceHolderType)
{
drawing.place_holder_type_ = *sPlaceHolderType;
_CP_OPT(int) iPlaceHolderIdx;
GetProperty(obj.additional_, L"PlaceHolderIdx", iPlaceHolderIdx);
if (iPlaceHolderIdx) drawing.place_holder_idx_ = *iPlaceHolderIdx;
}
_CP_OPT(bool) is_placeholder;
GetProperty(obj.additional_, L"IsPlaceholder", is_placeholder);
drawing.place_holder_ = is_placeholder.get_value_or(false);
drawing.sub_type = obj.shape_type_;
// NOTE: All object identifiers may be unknown at connector processing time.
// Start and end connector object identifiers will be updated after processing all objects on slide.
drawing.start_connection_shape_id = obj.start_shape_id.get_value_or(L"");
drawing.end_connection_shape_id = obj.end_shape_id.get_value_or(L"");
drawing.start_connection_index = obj.start_shape_glue_point.get_value_or(0);
drawing.end_connection_index = obj.end_shape_glue_point.get_value_or(0);
drawing.connector_prst = obj.draw_type_.get_value_or(L"line");
add_drawing(drawing, isMediaInternal, rId, ref, typeShape);
}
void pptx_slide_context::Impl::process_object(drawing_object_description& obj, _pptx_drawing & drawing)
{
std::wstring ref, ref_image;
bool isMediaInternal = true, isMediaInternal_image = true;
drawing.objectId = get_mediaitems()->add_or_find(obj.xlink_href_, obj.type_, isMediaInternal, ref, oox::document_place);
drawing.objectProgId = obj.descriptor_;
if (!drawing.fill.bitmap)
{
drawing.fill.bitmap = oox::oox_bitmap_fill::create();
drawing.fill.bitmap->xlink_href_ = L"zero.png";
_image_file_::GenerateZeroImage(odfPacket_ + FILE_SEPARATOR_STR + L"zero.png");
}
drawing.fill.bitmap->rId = get_mediaitems()->add_or_find(drawing.fill.bitmap->xlink_href_, typeImage, isMediaInternal_image, ref_image, oox::document_place);
add_additional_rels(isMediaInternal_image, drawing.fill.bitmap->rId, ref_image, typeImage);
add_drawing(drawing, isMediaInternal, drawing.objectId, ref, drawing.type);
}
void pptx_slide_context::Impl::process_media(drawing_object_description& obj, _pptx_drawing & drawing)
{
std::wstring ref, ref_image;
bool isMediaInternal = true, isMediaInternal_image = true;
drawing.type = mediaitems::detectMediaType(obj.xlink_href_); //reset from Media to Audio, Video, ... QuickTime? AudioCD? ...
drawing.objectId = get_mediaitems()->add_or_find(obj.xlink_href_, drawing.type, isMediaInternal, ref, oox::document_place);
drawing.extId = L"ext" + drawing.objectId;
drawing.extExternal = !isMediaInternal;
if (!drawing.fill.bitmap)
{
drawing.fill.bitmap = oox::oox_bitmap_fill::create();
drawing.fill.bitmap->xlink_href_ = L"zero.png";
_image_file_::GenerateZeroImage(odfPacket_ + FILE_SEPARATOR_STR + L"zero.png");
}
drawing.fill.bitmap->rId = get_mediaitems()->add_or_find(drawing.fill.bitmap->xlink_href_, typeImage, isMediaInternal_image, ref_image, oox::document_place);
add_additional_rels(isMediaInternal_image, drawing.fill.bitmap->rId, ref_image, typeImage);
add_drawing(drawing, false, drawing.objectId, L"NULL", drawing.type);
add_additional_rels( isMediaInternal, drawing.extId, ref, typeMedia);
}
void pptx_slide_context::Impl::process_common_properties(drawing_object_description & pic, _pptx_drawing & drawing)
{
if (pic.svg_rect_)
{
int val;
//todooo confusion with negative values
drawing.x = (int)(0.5 + odf_types::length(pic.svg_rect_->x, odf_types::length::pt).get_value_unit(odf_types::length::emu));
drawing.y = (int)(0.5 + odf_types::length(pic.svg_rect_->y, odf_types::length::pt).get_value_unit(odf_types::length::emu));
val = (int)(0.5 + odf_types::length(pic.svg_rect_->cx, odf_types::length::pt).get_value_unit(odf_types::length::emu));
if ( val >=0 ) drawing.cx = val;
val = (int)(0.5 + odf_types::length(pic.svg_rect_->cy, odf_types::length::pt).get_value_unit(odf_types::length::emu));
if ( val >=0 ) drawing.cy = val;
}
drawing.hidden = pic.hidden_;
drawing.additional = pic.additional_;
drawing.hlinks = pic.hlinks_;
drawing.action = pic.action_;
drawing.fill = pic.fill_;
}
void pptx_slide_context::Impl::process_crop(_oox_fill & fill, const std::wstring& filename)
{
if (!fill.bitmap) return;
_image_file_::GetResolution(filename.c_str(), fill.bitmap->width, fill.bitmap->height, get_mediaitems()->applicationFonts());
if (fill.bitmap->width && fill.bitmap->height)
{
fill.bitmap->bCrop = odf_reader::parse_clipping(fill.clipping, *fill.bitmap->width, *fill.bitmap->height, fill.bitmap->cropRect);
if (fill.bitmap->sx_pt && fill.bitmap->sy_pt)
{
fill.bitmap->sx = (*fill.bitmap->sx_pt * 100. / *fill.bitmap->width) * 4 / 3;
fill.bitmap->sy = (*fill.bitmap->sy_pt * 100. / *fill.bitmap->height) * 4 / 3;
}
}
if (!fill.bitmap->bTile && fill.bitmap->sx && fill.bitmap->sy)
{
fill.bitmap->bStretch = true;
}
}
void pptx_slide_context::dump_rels(rels & Rels)
{
impl_->get_drawings()->dump_rels(Rels);
}
mediaitems_ptr & pptx_slide_context::get_mediaitems()
{
return impl_->get_mediaitems();
}
void pptx_slide_context::add_rels( bool isInternal, std::wstring const & rid, std::wstring const & ref, _rels_type type)
{
impl_->add_additional_rels(isInternal, rid, ref, type);
}
void pptx_slide_context::set_footer(bool val)
{
impl_->footer = true;
}
void pptx_slide_context::set_header(bool val)
{
impl_->header = val;
}
void pptx_slide_context::set_page_number(bool val)
{
impl_->slideNum = val;
}
void pptx_slide_context::set_date_time(bool val)
{
impl_->date_time = val;
}
bool pptx_slide_context::get_date_time()
{
return impl_->date_time;
}
bool pptx_slide_context::get_page_number()
{
return impl_->slideNum;
}
bool pptx_slide_context::get_header()
{
return impl_->header;
}
bool pptx_slide_context::get_footer()
{
return impl_->footer;
}
void pptx_slide_context::generate_id(const std::wstring& id)
{
impl_->generate_id(id);
}
size_t pptx_slide_context::get_id(const std::wstring& id)
{
Impl::id_map::iterator it = impl_->id_map_.find(id);
if (it == impl_->id_map_.end())
return 0;
return it->second;
}
void pptx_slide_context::serialize_background(std::wostream & strm, bool always)
{
if (!always && ( (!impl_->background_fill_) || (impl_->background_fill_->type == 0))) return;
std::wstring background_fill;
if (impl_->background_fill_)
{
std::wstringstream tmp_strm;
oox_serialize_fill(tmp_strm, impl_->background_fill_.get());
background_fill = tmp_strm.str();
}
CP_XML_WRITER(strm)
{
CP_XML_NODE(L"p:bg")
{
CP_XML_NODE(L"p:bgPr")
{
if (false == background_fill.empty())
{
CP_XML_STREAM() << background_fill;
}
else
{
CP_XML_NODE(L"a:noFill");
}
CP_XML_NODE(L"a:effectLst");
}
}
}
}
void pptx_slide_context::serialize_animations(std::wostream & strm)
{
CP_XML_WRITER(strm)
{
if (impl_->transition_.Enabled)
{
CP_XML_NODE(L"p:transition")
{
if (impl_->transition_.Speed)
{
CP_XML_ATTR(L"spd",impl_->transition_.Speed.get());
}
/* if (impl_->transition_.Time)
{
CP_XML_ATTR(L"p14:dur", impl_->transition_.Time.get());
}*/
if (impl_->transition_.PageTime)
{
CP_XML_ATTR(L"advTm", impl_->transition_.PageTime.get());
}
CP_XML_ATTR(L"advClick", impl_->transition_.onClick);
CP_XML_NODE(std::wstring(L"p:" + impl_->transition_.Type))
{
if (impl_->transition_.Dir)
{
CP_XML_ATTR(L"dir",impl_->transition_.Dir.get());
}
if (impl_->transition_.Param)
{
if (impl_->transition_.Type == L"wheel")
CP_XML_ATTR(L"spokes",impl_->transition_.Param.get());
if (impl_->transition_.Type == L"fade")
CP_XML_ATTR(L"thruBlk",impl_->transition_.Param.get());
if (impl_->transition_.Type == L"split")
CP_XML_ATTR(L"orient",impl_->transition_.Param.get());
}
}
//p:sndAc
}
}
pptx_animation_context_.serialize(strm);
}
}
void pptx_slide_context::serialize_HeaderFooter(std::wostream & strm)
{
if (!impl_->header && !impl_->footer && !impl_->date_time && !impl_->slideNum)return;
CP_XML_WRITER(strm)
{
CP_XML_NODE(L"p:hf")
{
if(impl_->footer) CP_XML_ATTR(L"ftr",1);
if(impl_->header) CP_XML_ATTR(L"hdr",1);
if(impl_->date_time) CP_XML_ATTR(L"dt",1);
if(impl_->slideNum) CP_XML_ATTR(L"sldNum",1);
}
}
}
void pptx_slide_context::serialize_objects(std::wostream & strm)
{
const int nextnvGrpSpPrId = 1;
CP_XML_WRITER(strm)
{
// put default mandatory noGroup here for now
CP_XML_NODE(L"p:nvGrpSpPr")
{
CP_XML_NODE(L"p:cNvPr")
{
CP_XML_ATTR(L"name", L"noGroup");
CP_XML_ATTR(L"id", nextnvGrpSpPrId);
}
CP_XML_NODE(L"p:cNvGrpSpPr");
CP_XML_NODE(L"p:nvPr");
}
CP_XML_NODE(L"p:grpSpPr")
{
CP_XML_NODE(L"a:xfrm")
{
CP_XML_NODE(L"a:off") { CP_XML_ATTR(L"x", 0); CP_XML_ATTR(L"y", 0); }
CP_XML_NODE(L"a:ext") { CP_XML_ATTR(L"cx",0); CP_XML_ATTR(L"cy",0); }
CP_XML_NODE(L"a:chOff") { CP_XML_ATTR(L"x", 0); CP_XML_ATTR(L"y", 0); }
CP_XML_NODE(L"a:chExt") { CP_XML_ATTR(L"cx",0); CP_XML_ATTR(L"cy",0); }
}
}
}
impl_->get_drawings()->serialize(strm);
}
}
}