mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-07-11 05:24:10 +08:00
Co-authored-by: Alexander Trofimov <alexander.trofimov@onlyoffice.com> Co-committed-by: Alexander Trofimov <alexander.trofimov@onlyoffice.com>
1141 lines
34 KiB
C++
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"&");
|
|
|
|
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);
|
|
}
|
|
|
|
}
|
|
}
|