From: Niklas P Andersson Date: Thu, 3 Dec 2015 12:54:46 +0000 (+0100) Subject: support for rectangular vectors masks in PSD-files with binding to crop transform X-Git-Tag: 2.1.0_Beta1~148 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=39a35183b7f266e0f79abd10f28ff996e5f194d4;p=casparcg support for rectangular vectors masks in PSD-files with binding to crop transform --- diff --git a/modules/psd/layer.cpp b/modules/psd/layer.cpp index acc595e33..d35c8583c 100644 --- a/modules/psd/layer.cpp +++ b/modules/psd/layer.cpp @@ -596,6 +596,8 @@ int layer::sheet_color() const { return impl_->sheet_color_; } bool layer::is_visible() { return (impl_->flags_ & 2) == 0; } //the (PSD file-format) documentation is is saying the opposite but what the heck bool layer::is_position_protected() { return (impl_->protection_flags_& 4) == 4; } +const layer::mask_info& layer::mask() const { return impl_->mask_; } + double layer::text_scale() const { return impl_->text_scale_; } bool layer::is_text() const { return !impl_->text_layer_info_.empty(); } const boost::property_tree::wptree& layer::text_data() const { return impl_->text_layer_info_; } diff --git a/modules/psd/layer.h b/modules/psd/layer.h index 95baf8aaf..7f2ca628c 100644 --- a/modules/psd/layer.h +++ b/modules/psd/layer.h @@ -111,7 +111,7 @@ public: bool has_vector() const { return (vector_mask_ && !vector_mask_->empty() && vector_mask_->enabled()); } bool has_bitmap() const { return (!vector_mask_ && !empty()) || (vector_mask_ && total_mask_); } - const std::unique_ptr& vector() { return vector_mask_; } + const std::unique_ptr& vector() const { return vector_mask_; } const psd::rect& rect() const { return rect_; } const image8bit_ptr& bitmap() const { return bitmap_; } @@ -128,6 +128,8 @@ public: bool is_visible(); bool is_position_protected(); + const mask_info& mask() const; + double text_scale() const; bool is_text() const; const boost::property_tree::wptree& text_data() const; diff --git a/modules/psd/misc.cpp b/modules/psd/misc.cpp index 17df31ca6..829a9ee52 100644 --- a/modules/psd/misc.cpp +++ b/modules/psd/misc.cpp @@ -165,6 +165,11 @@ layer_tag string_to_layer_tags(const std::wstring& str) { result = result & (~layer_tag::moveable); result = result & (~layer_tag::explicit_dynamic); } + else if (boost::algorithm::iequals(flag, "cornerpin")) { + result = result | layer_tag::cornerpin; + result = result & (~layer_tag::resizable); + result = result & (~layer_tag::explicit_dynamic); + } } return result; diff --git a/modules/psd/misc.h b/modules/psd/misc.h index 955903cbb..1f5680875 100644 --- a/modules/psd/misc.h +++ b/modules/psd/misc.h @@ -146,7 +146,8 @@ enum class layer_tag : int { moveable = 4, resizable = 8, rasterized = 16, - all = 31 + cornerpin = 32, + all = 63 }; ENUM_ENABLE_BITWISE(layer_tag); diff --git a/modules/psd/psd_scene_producer.cpp b/modules/psd/psd_scene_producer.cpp index 09aa82af1..727ca17f9 100644 --- a/modules/psd/psd_scene_producer.cpp +++ b/modules/psd/psd_scene_producer.cpp @@ -102,13 +102,17 @@ class dependency_resolver { struct layer_record { - layer_record() : layer(nullptr), tags(layer_tag::none), adjustment_x(0), adjustment_y(0) + layer_record() : layer(nullptr), tags(layer_tag::none), adjustment_x(0), adjustment_y(0), vector_mask(false) + {} + layer_record(caspar::core::scene::layer* l, caspar::psd::layer_tag t, double x, double y, bool v) : + layer(l), tags(t), adjustment_x(x), adjustment_y(y), vector_mask(v) {} caspar::core::scene::layer* layer; layer_tag tags; double adjustment_x; double adjustment_y; + bool vector_mask; }; std::list layers; @@ -127,13 +131,9 @@ public: spl::shared_ptr scene() { return scene_; } - void add(caspar::core::scene::layer* layer, layer_tag tags, double adjustment_x, double adjustment_y) + void add(caspar::core::scene::layer* layer, layer_tag tags, double adjustment_x, double adjustment_y, bool vector_mask) { - layer_record rec; - rec.layer = layer; - rec.tags = tags; - rec.adjustment_x = adjustment_x; - rec.adjustment_y = adjustment_y; + layer_record rec{ layer, tags, adjustment_x, adjustment_y, vector_mask }; layers.push_back(rec); //if the layer is either explicitly tagged as dynamic or at least not tagged as static/rasterized we should try to set it as master @@ -187,7 +187,11 @@ public: r.layer->position.x.bind(master.layer->position.x + master.layer->producer.get()->pixel_constraints().width + offset_end_x + r.adjustment_x); else if ((r.tags & layer_tag::resizable) == layer_tag::resizable) { r.layer->position.x.bind(master.layer->position.x + offset_start_x + r.adjustment_x); - r.layer->producer.get()->pixel_constraints().width.bind(master.layer->producer.get()->pixel_constraints().width + (slave_width - master_width)); + + if(r.vector_mask) //adjust crop-rect if we have a vector-mask + r.layer->crop.lower_right.x.bind(master.layer->producer.get()->pixel_constraints().width + ((r.layer->crop.lower_right.x.get() - r.layer->crop.upper_left.x.get()) - master_width)); + else //just stretch the content + r.layer->producer.get()->pixel_constraints().width.bind(master.layer->producer.get()->pixel_constraints().width + (slave_width - master_width)); } //no support for changes in the y-direction yet @@ -349,6 +353,10 @@ void create_timelines( scene->add_keyframe(opacity, opct, frame); } } + else + { + //ignore other kinds of tracks for now + } } } @@ -400,9 +408,9 @@ spl::shared_ptr create_psd_scene_producer(const core::fram create_timelines(root, dependencies.format_desc, scene_layer, psd_layer, 0, 0); if (psd_layer->is_movable()) - current.add(&scene_layer, psd_layer->tags(), 0, 0); + current.add(&scene_layer, psd_layer->tags(), 0, 0, false); - if (psd_layer->is_resizable()) + if (psd_layer->is_resizable()) //TODO: we could add support for resizable groups with vector masks CASPAR_LOG(warning) << "Groups doesn't support the \"resizable\"-tag."; if (psd_layer->is_explicit_dynamic()) @@ -419,6 +427,10 @@ spl::shared_ptr create_psd_scene_producer(const core::fram continue; } + std::shared_ptr layer_producer; + int adjustment_x = 0, + adjustment_y = 0; + if(psd_layer->is_visible()) { auto layer_name = psd_layer->name(); @@ -435,21 +447,14 @@ spl::shared_ptr create_psd_scene_producer(const core::fram text_producer->pixel_constraints().height.set(psd_layer->size().height); core::text::string_metrics metrics = text_producer->measure_string(str); - auto adjustment_x = -2; //the 2 offset is just a hack for now. don't know why our text is rendered 2 px to the right of that in photoshop - auto adjustment_y = metrics.bearingY; - auto& scene_layer = current.scene()->create_layer(text_producer, psd_layer->location().x + adjustment_x, psd_layer->location().y + adjustment_y, layer_name); - scene_layer.adjustments.opacity.set(psd_layer->opacity() / 255.0); - scene_layer.hidden.set(!psd_layer->is_visible()); + adjustment_x = -2; //the 2 offset is just a hack for now. don't know why our text is rendered 2 px to the right of that in photoshop + adjustment_y = metrics.bearingY; + layer_producer = text_producer; - if (psd_layer->has_timeline()) - create_timelines(root, dependencies.format_desc, scene_layer, psd_layer, adjustment_x, adjustment_y); - - current.add(&scene_layer, psd_layer->tags(), -adjustment_x, -adjustment_y); text_producers_by_layer_name.push_back(std::make_pair(layer_name, text_producer)); } else { - std::shared_ptr layer_producer; if(psd_layer->is_solid()) { layer_producer = core::create_const_producer(core::create_color_frame(it->get(), dependencies.frame_factory, psd_layer->solid_color().to_uint32()), psd_layer->bitmap()->width(), psd_layer->bitmap()->height()); @@ -475,19 +480,42 @@ spl::shared_ptr create_psd_scene_producer(const core::fram layer_producer = core::create_const_producer(core::draw_frame(std::move(frame)), psd_layer->bitmap()->width(), psd_layer->bitmap()->height()); } } + } - if(layer_producer) - { - auto& scene_layer = current.scene()->create_layer(spl::make_shared_ptr(layer_producer), psd_layer->location().x, psd_layer->location().y, psd_layer->name()); - scene_layer.adjustments.opacity.set(psd_layer->opacity() / 255.0); - scene_layer.hidden.set(!psd_layer->is_visible()); + if (layer_producer) + { + auto& scene_layer = current.scene()->create_layer(spl::make_shared_ptr(layer_producer), psd_layer->location().x + adjustment_x, psd_layer->location().y + adjustment_y, layer_name); + scene_layer.adjustments.opacity.set(psd_layer->opacity() / 255.0); + scene_layer.hidden.set(!psd_layer->is_visible()); //this will always evaluate to true + + if (psd_layer->mask().has_vector()) { + + //this rectangle is in document-coordinates + auto mask = psd_layer->mask().vector()->rect(); + + //remap to layer-coordinates + auto left = static_cast(mask.location.x) - scene_layer.position.x.get(); + auto right = left + static_cast(mask.size.width); + auto top = static_cast(mask.location.y) - scene_layer.position.y.get(); + auto bottom = top + static_cast(mask.size.height); + + scene_layer.crop.upper_left.x.unbind(); + scene_layer.crop.upper_left.x.set(left); + scene_layer.crop.upper_left.y.unbind(); + scene_layer.crop.upper_left.y.set(top); + + scene_layer.crop.lower_right.x.unbind(); + scene_layer.crop.lower_right.x.set(right); + + scene_layer.crop.lower_right.y.unbind(); + scene_layer.crop.lower_right.y.set(bottom); + } - if (psd_layer->has_timeline()) - create_timelines(root, dependencies.format_desc, scene_layer, psd_layer, 0, 0); + if (psd_layer->has_timeline()) + create_timelines(root, dependencies.format_desc, scene_layer, psd_layer, adjustment_x, adjustment_y); - if(psd_layer->is_movable() || psd_layer->is_resizable()) - current.add(&scene_layer, psd_layer->tags(), 0, 0); - } + if (psd_layer->is_movable() || psd_layer->is_resizable() || (psd_layer->is_text() && !psd_layer->is_static())) + current.add(&scene_layer, psd_layer->tags(), -adjustment_x, -adjustment_y, psd_layer->mask().has_vector()); } } } @@ -497,13 +525,14 @@ spl::shared_ptr create_psd_scene_producer(const core::fram root->reverse_layers(); scene_stack.top().calculate(); + if (doc.has_timeline()) + create_marks(root, dependencies.format_desc, doc.timeline()); // Reset all dynamic text fields to empty strings and expose them as a scene parameter. - for (auto& text_layer : text_producers_by_layer_name) + for (auto& text_layer : text_producers_by_layer_name) { + text_layer.second->text().set(L""); text_layer.second->text().bind(root->create_variable(boost::to_lower_copy(text_layer.first), true, L"")); - - if (doc.has_timeline()) - create_marks(root, dependencies.format_desc, doc.timeline()); + } auto params2 = params; params2.erase(params2.begin());