+2017-05-09 Carl Hetherington <cth@carlh.net>
+
+ * Write a simple cover sheet when making a DCP (#1039).
+
2017-05-08 Carl Hetherington <cth@carlh.net>
* Show multiple tracks in the timeline if there are overlapping subtitles (#941).
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ id="svg5816"
+ viewBox="0 0 48 48"
+ sodipodi:version="0.32"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:version="0.91 r13725"
+ sodipodi:docname="cover_sheet.svg"
+ version="1.1">
+ <defs
+ id="defs3">
+ <radialGradient
+ id="radialGradient6719"
+ xlink:href="#linearGradient5060"
+ gradientUnits="userSpaceOnUse"
+ cy="486.65"
+ cx="605.71"
+ gradientTransform="matrix(-2.7744,0,0,1.9697,112.76,-872.89)"
+ r="117.14"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient5060"
+ inkscape:collect="always">
+ <stop
+ id="stop5062"
+ style="stop-color:black"
+ offset="0" />
+ <stop
+ id="stop5064"
+ style="stop-color:black;stop-opacity:0"
+ offset="1" />
+ </linearGradient>
+ <radialGradient
+ id="radialGradient6717"
+ xlink:href="#linearGradient5060"
+ gradientUnits="userSpaceOnUse"
+ cy="486.65"
+ cx="605.71"
+ gradientTransform="matrix(2.7744,0,0,1.9697,-1891.6,-872.89)"
+ r="117.14"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient6715"
+ y2="609.51"
+ gradientUnits="userSpaceOnUse"
+ x2="302.86"
+ gradientTransform="matrix(2.7744,0,0,1.9697,-1892.2,-872.89)"
+ y1="366.65"
+ x1="302.86"
+ inkscape:collect="always">
+ <stop
+ id="stop5050"
+ style="stop-color:black;stop-opacity:0"
+ offset="0" />
+ <stop
+ id="stop5056"
+ style="stop-color:black"
+ offset=".5" />
+ <stop
+ id="stop5052"
+ style="stop-color:black;stop-opacity:0"
+ offset="1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient2152">
+ <stop
+ id="stop2154"
+ style="stop-color:#9aa29a"
+ offset="0" />
+ <stop
+ id="stop2156"
+ style="stop-color:#b5beb5"
+ offset="1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient27488"
+ y2="15.257"
+ gradientUnits="userSpaceOnUse"
+ y1="15.257"
+ gradientTransform="matrix(1.3435 0 0 1.4179 2.8795 .31460)"
+ x2="30.6"
+ x1="2.0619"
+ inkscape:collect="always">
+ <stop
+ id="stop2138"
+ style="stop-color:#989690"
+ offset="0" />
+ <stop
+ id="stop2140"
+ style="stop-color:#656460"
+ offset="1" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient27488"
+ id="linearGradient8193"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.8693657,0,0,0.80274289,29.209849,80.26044)"
+ x1="2.0619"
+ y1="15.257"
+ x2="30.6"
+ y2="15.257" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ bordercolor="#666666"
+ inkscape:window-x="0"
+ inkscape:window-y="27"
+ pagecolor="#ffffff"
+ inkscape:grid-bbox="true"
+ inkscape:zoom="4"
+ inkscape:pageshadow="2"
+ showgrid="false"
+ borderopacity="1.0"
+ inkscape:current-layer="layer1"
+ inkscape:cx="4.3829084"
+ inkscape:cy="-18.515601"
+ inkscape:window-width="1280"
+ inkscape:pageopacity="0.0"
+ inkscape:window-height="968"
+ inkscape:document-units="px"
+ inkscape:window-maximized="1" />
+ <g
+ id="layer1"
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer">
+ <g
+ id="g6707"
+ transform="matrix(0.0227,0,0,0.022979,44.190742,39.034)">
+ <rect
+ id="rect6709"
+ style="color:#000000;opacity:0.40206;fill:url(#linearGradient6715)"
+ height="478.35999"
+ width="1339.6"
+ y="-150.7"
+ x="-1559.3" />
+ <path
+ id="path6711"
+ sodipodi:nodetypes="cccc"
+ style="color:#000000;opacity:0.40206;fill:url(#radialGradient6717)"
+ d="m -219.62,-150.68 0,478.33 c 142.88,0.9 345.4,-107.17 345.4,-239.2 0,-132.02 -159.44,-239.13 -345.4,-239.13 z"
+ inkscape:connector-curvature="0" />
+ <path
+ id="path6713"
+ sodipodi:nodetypes="cccc"
+ style="color:#000000;opacity:0.40206;fill:url(#radialGradient6719)"
+ d="m -1559.3,-150.68 0,478.33 c -142.8,0.9 -345.4,-107.17 -345.4,-239.2 0,-132.02 159.5,-239.13 345.4,-239.13 z"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g8222"
+ transform="translate(-0.1111002,-106.75)">
+ <rect
+ y="108.95594"
+ x="8.5809364"
+ height="40.338127"
+ width="31.060328"
+ id="rect8133"
+ style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#e6e6e6;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient8193);stroke-width:0.51847273;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path8167"
+ d="m 11.232107,112.40472 13.7113,0"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.64635694px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path8169"
+ d="m 11.232107,115.77542 17.367647,0"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.64635694px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path8171"
+ d="m 11.232107,119.14611 5.598781,0"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.64635694px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path8173"
+ d="m 11.232107,122.51681 11.083301,0"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.64635694px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path8175"
+ d="m 11.232107,125.8875 21.82382,0"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.64635694px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path8177"
+ d="m 11.232107,129.2582 9.940693,0"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.64635694px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path8179"
+ d="m 11.232107,132.62889 16.453561,0"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.64635694px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ </g>
+ </g>
+ <metadata
+ id="metadata54">
+ <rdf:RDF>
+ <cc:Work>
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/publicdomain/" />
+ <dc:publisher>
+ <cc:Agent
+ rdf:about="http://openclipart.org/">
+ <dc:title>Openclipart</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:title>tango internet mail</dc:title>
+ <dc:date>2010-03-29T08:04:16</dc:date>
+ <dc:description>"E-mail" icon from <a href="http://tango.freedesktop.org/Tango_Desktop_Project"> Tango Project </a> \r\n<br><br>\r\nSince version 0.8.90 Tango Project icons are Public Domain: <a href="http://tango.freedesktop.org/Frequently_Asked_Questions#Terms_of_Use.3F"> Tango Project FAQ </a></dc:description>
+ <dc:source>https://openclipart.org/detail/35215/tango-internet-mail-by-warszawianka</dc:source>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>warszawianka</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>email</rdf:li>
+ <rdf:li>envelope</rdf:li>
+ <rdf:li>externalsource</rdf:li>
+ <rdf:li>icon</rdf:li>
+ <rdf:li>letter</rdf:li>
+ <rdf:li>tango</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/publicdomain/">
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#Reproduction" />
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#Distribution" />
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+</svg>
# OS X preferences icons
# servers.png does not have an SVG version
mkdir -p osx/preferences
- for i in colour_conversions defaults kdm_email keys tms; do
+ for i in colour_conversions defaults kdm_email cover_sheet keys tms; do
$INKSCAPE osx/preferences/$i.png src/$i.svg -w 32 -h 32
done
_allowed_dcp_frame_rates.push_back (60);
set_kdm_email_to_default ();
+ set_cover_sheet_to_default ();
}
void
}
_preview_sound = f.optional_bool_child("PreviewSound").get_value_or (false);
_preview_sound_output = f.optional_string_child("PreviewSoundOutput");
+ if (f.optional_string_child("CoverSheet")) {
+ _cover_sheet = f.optional_string_child("CoverSheet").get();
+ }
/* Replace any cinemas from config.xml with those from the configured file */
if (boost::filesystem::exists (_cinemas_file)) {
if (_preview_sound_output) {
root->add_child("PreviewSoundOutput")->add_child_text (_preview_sound_output.get());
}
+ root->add_child("CoverSheet")->add_child_text (_cover_sheet);
try {
doc.write_to_file_formatted (path("config.xml").string ());
changed ();
}
+void
+Config::set_cover_sheet_to_default ()
+{
+ _cover_sheet = _(
+ "$CPL_NAME\n\n"
+ "Type: $TYPE\n"
+ "Format: $CONTAINER\n"
+ "Audio: $AUDIO\n"
+ "Length: $LENGTH\n"
+ );
+}
+
void
Config::add_to_history (boost::filesystem::path p)
{
{
return path("config.xml", false);
}
+
+void
+Config::reset_cover_sheet ()
+{
+ set_cover_sheet_to_default ();
+ changed ();
+}
return _preview_sound;
}
+ std::string cover_sheet () const {
+ return _cover_sheet;
+ }
+
boost::optional<std::string> preview_sound_output () const {
return _preview_sound_output;
}
maybe_set (_nagged[nag], nagged);
}
+ void set_cover_sheet (std::string s) {
+ maybe_set (_cover_sheet, s);
+ }
+
+ void reset_cover_sheet ();
+
void changed (Property p = OTHER);
boost::signals2::signal<void (Property)> Changed;
/** Emitted if read() failed on an existing Config file. There is nothing
void read ();
void set_defaults ();
void set_kdm_email_to_default ();
+ void set_cover_sheet_to_default ();
void read_cinemas (cxml::Document const & f);
boost::shared_ptr<dcp::CertificateChain> create_certificate_chain ();
boost::filesystem::path directory_or (boost::optional<boost::filesystem::path> dir, boost::filesystem::path a) const;
bool _preview_sound;
/** name of a specific sound output stream to use for preview, or empty to use the default */
boost::optional<std::string> _preview_sound_output;
+ std::string _cover_sheet;
/** Singleton instance, or 0 */
static Config* _instance;
/* Count mapped audio channels */
- int non_lfe = 0;
- int lfe = 0;
-
- BOOST_FOREACH (int i, mapped_audio_channels ()) {
- if (i >= audio_channels()) {
- /* This channel is mapped but is not included in the DCP */
- continue;
- }
-
- if (static_cast<dcp::Channel> (i) == dcp::LFE) {
- ++lfe;
- } else {
- ++non_lfe;
- }
- }
-
- if (non_lfe) {
- d += String::compose("_%1%2", non_lfe, lfe);
+ pair<int, int> ch = audio_channel_types (mapped_audio_channels(), audio_channels());
+ if (ch.first) {
+ d += String::compose("_%1%2", ch.first, ch.second);
}
/* XXX: HI/VI */
using std::cout;
using std::bad_alloc;
using std::set_terminate;
+using std::make_pair;
using boost::shared_ptr;
using boost::thread;
using boost::optional;
return out;
}
+
+/** @param mapped List of mapped audio channels from a Film.
+ * @param channels Total number of channels in the Film.
+ * @return First: number of non-LFE channels, second: number of LFE channels.
+ */
+pair<int, int>
+audio_channel_types (list<int> mapped, int channels)
+{
+ int non_lfe = 0;
+ int lfe = 0;
+
+ BOOST_FOREACH (int i, mapped) {
+ if (i >= channels) {
+ /* This channel is mapped but is not included in the DCP */
+ continue;
+ }
+
+ if (static_cast<dcp::Channel> (i) == dcp::LFE) {
+ ++lfe;
+ } else {
+ ++non_lfe;
+ }
+ }
+
+ return make_pair (non_lfe, lfe);
+}
extern std::string audio_asset_filename (boost::shared_ptr<dcp::SoundAsset> asset, int reel_index, int reel_count, boost::optional<std::string> content_summary);
extern float relaxed_string_to_float (std::string);
extern std::string careful_string_filter (std::string);
+extern std::pair<int, int> audio_channel_types (std::list<int> mapped, int channels);
#endif
/*
- Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2017 Carl Hetherington <cth@carlh.net>
This file is part of DCP-o-matic.
LOG_GENERAL (
N_("Wrote %1 FULL, %2 FAKE, %3 REPEAT, %4 pushed to disk"), _full_written, _fake_written, _repeat_written, _pushed_to_disk
);
+
+ write_cover_sheet ();
+}
+
+void
+Writer::write_cover_sheet ()
+{
+ boost::filesystem::path const cover = _film->file ("COVER_SHEET.txt");
+ FILE* f = fopen_boost (cover, "w");
+ if (!f) {
+ throw OpenFileError (cover, errno, false);
+ }
+
+ string text = Config::instance()->cover_sheet ();
+ boost::algorithm::replace_all (text, "$CPL_NAME", _film->name());
+ boost::algorithm::replace_all (text, "$TYPE", _film->dcp_content_type()->pretty_name());
+ boost::algorithm::replace_all (text, "$CONTAINER", _film->container()->nickname());
+
+ pair<int, int> ch = audio_channel_types (_film->mapped_audio_channels(), _film->audio_channels());
+ string description = String::compose("%1.%2", ch.first, ch.second);
+
+ if (description == "0.0") {
+ description = _("None");
+ } else if (description == "1.0") {
+ description = _("Mono");
+ } else if (description == "2.0") {
+ description = _("Stereo");
+ }
+ boost::algorithm::replace_all (text, "$AUDIO", description);
+
+ int h, m, s, fr;
+ _film->length().split (_film->video_frame_rate(), h, m, s, fr);
+ string length;
+ if (h == 0 && m == 0) {
+ length = String::compose("%1s", s);
+ } else if (h == 0 && m > 0) {
+ length = String::compose("%1m%2s", m, s);
+ } else if (h > 0 && m > 0) {
+ length = String::compose("%1h%2m%3s", h, m, s);
+ }
+
+ boost::algorithm::replace_all (text, "$LENGTH", length);
+
+ fwrite (text.c_str(), 1, text.length(), f);
+ fclose (f);
}
/** @param frame Frame index within the whole DCP.
bool have_sequenced_image_at_queue_head ();
size_t video_reel (int frame) const;
void set_digest_progress (Job* job, float progress);
+ void write_cover_sheet ();
/** our Film */
boost::shared_ptr<const Film> _film;
wxButton* _reset_kdm_email;
};
+class CoverSheetPage : public StandardPage
+{
+public:
+
+ CoverSheetPage (wxSize panel_size, int border)
+#ifdef DCPOMATIC_OSX
+ /* We have to force both width and height of this one */
+ : StandardPage (wxSize (480, 128), border)
+#else
+ : StandardPage (panel_size, border)
+#endif
+ {}
+
+ wxString GetName () const
+ {
+ return _("Cover Sheet");
+ }
+
+#ifdef DCPOMATIC_OSX
+ wxBitmap GetLargeIcon () const
+ {
+ return wxBitmap ("cover_sheet", wxBITMAP_TYPE_PNG_RESOURCE);
+ }
+#endif
+
+private:
+ void setup ()
+ {
+ _cover_sheet = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
+ _panel->GetSizer()->Add (_cover_sheet, 0, wxEXPAND | wxALL, _border);
+
+ _reset_cover_sheet = new wxButton (_panel, wxID_ANY, _("Reset to default text"));
+ _panel->GetSizer()->Add (_reset_cover_sheet, 0, wxEXPAND | wxALL, _border);
+
+ _cover_sheet->Bind (wxEVT_TEXT, boost::bind (&CoverSheetPage::cover_sheet_changed, this));
+ _reset_cover_sheet->Bind (wxEVT_BUTTON, boost::bind (&CoverSheetPage::reset_cover_sheet, this));
+ }
+
+ void config_changed ()
+ {
+ checked_set (_cover_sheet, Config::instance()->cover_sheet ());
+ }
+
+ void cover_sheet_changed ()
+ {
+ if (_cover_sheet->GetValue().IsEmpty ()) {
+ /* Sometimes we get sent an erroneous notification that the cover sheet
+ is empty; I don't know why.
+ */
+ return;
+ }
+ Config::instance()->set_cover_sheet (wx_to_std (_cover_sheet->GetValue ()));
+ }
+
+ void reset_cover_sheet ()
+ {
+ Config::instance()->reset_cover_sheet ();
+ checked_set (_cover_sheet, Config::instance()->cover_sheet ());
+ }
+
+ wxTextCtrl* _cover_sheet;
+ wxButton* _reset_cover_sheet;
+};
+
+
/** @class AdvancedPage
* @brief Advanced page of the preferences dialog.
*/
e->AddPage (new KeysPage (ps, border));
e->AddPage (new TMSPage (ps, border));
e->AddPage (new KDMEmailPage (ps, border));
+ e->AddPage (new CoverSheetPage (ps, border));
e->AddPage (new AdvancedPage (ps, border));
return e;
}