forked from mia/Aegisub
Make AR-changing resampling more user-friendly
Add modes where the borders to add or remove are automatically calculated rather than forcing the user to do it manually, and hopefully make it a bit clearer what exactly will happen.
This commit is contained in:
parent
7e2780f57a
commit
0f030c45f3
5 changed files with 65 additions and 15 deletions
|
@ -24,9 +24,10 @@
|
|||
#include "help_button.h"
|
||||
#include "libresrc/libresrc.h"
|
||||
#include "resolution_resampler.h"
|
||||
#include "validators.h"
|
||||
#include "video_context.h"
|
||||
|
||||
#include <boost/rational.hpp>
|
||||
#include <boost/range/size.hpp>
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/spinctrl.h>
|
||||
|
@ -88,9 +89,9 @@ DialogResample::DialogResample(agi::Context *c, ResampleSettings &settings)
|
|||
from_script = new wxButton(this, -1, _("From s&cript"));
|
||||
from_script->Enable(false);
|
||||
|
||||
change_ar = new wxCheckBox(this, -1, _("&Change aspect ratio"));
|
||||
change_ar->SetValidator(wxGenericValidator(&settings.change_ar));
|
||||
change_ar->Enable(false);
|
||||
wxString ar_modes[] = {_("Stretch"), _("Add borders"), _("Remove borders"), _("Manual")};
|
||||
ar_mode = new wxRadioBox(this, -1, _("Aspect Ratio Handling"), wxDefaultPosition,
|
||||
wxDefaultSize, boost::size(ar_modes), ar_modes, 1, 4, MakeEnumBinder(&settings.ar_mode));
|
||||
|
||||
// Position the controls
|
||||
auto margin_sizer = new wxGridSizer(3, 3, 5, 5);
|
||||
|
@ -121,20 +122,24 @@ DialogResample::DialogResample(agi::Context *c, ResampleSettings &settings)
|
|||
|
||||
auto dest_res_box = new wxStaticBoxSizer(wxVERTICAL, this, _("Destination Resolution"));
|
||||
dest_res_box->Add(dest_res_sizer, wxSizerFlags(1).Expand().Border(wxBOTTOM));
|
||||
dest_res_box->Add(change_ar);
|
||||
|
||||
auto main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
main_sizer->Add(margin_box, wxSizerFlags(1).Expand().Border());
|
||||
main_sizer->Add(source_res_sizer, wxSizerFlags(0).Expand().Border());
|
||||
main_sizer->Add(dest_res_box, wxSizerFlags(0).Expand().Border());
|
||||
main_sizer->Add(ar_mode, wxSizerFlags(0).Expand().Border());
|
||||
main_sizer->Add(margin_box, wxSizerFlags(1).Expand().Border());
|
||||
main_sizer->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL | wxHELP), wxSizerFlags().Expand().Border(wxALL & ~wxTOP));
|
||||
SetSizerAndFit(main_sizer);
|
||||
CenterOnParent();
|
||||
|
||||
TransferDataToWindow();
|
||||
UpdateButtons();
|
||||
|
||||
// Bind events
|
||||
using std::bind;
|
||||
Bind(wxEVT_BUTTON, bind(&HelpButton::OpenPage, "Resample resolution"), wxID_HELP);
|
||||
Bind(wxEVT_SPINCTRL, [=](wxCommandEvent&) { UpdateButtons(); });
|
||||
Bind(wxEVT_RADIOBOX, [=](wxCommandEvent&) { UpdateButtons(); });
|
||||
from_video->Bind(wxEVT_BUTTON, &DialogResample::SetDestFromVideo, this);
|
||||
from_script->Bind(wxEVT_BUTTON, &DialogResample::SetSourceFromScript, this);
|
||||
symmetrical->Bind(wxEVT_CHECKBOX, &DialogResample::OnSymmetrical, this);
|
||||
|
@ -157,9 +162,18 @@ void DialogResample::UpdateButtons() {
|
|||
(dest_x->GetValue() != video_w || dest_y->GetValue() != video_h));
|
||||
from_script->Enable(source_x->GetValue() != script_w || source_y->GetValue() != script_h);
|
||||
|
||||
boost::rational<int> source_ar(source_x->GetValue(), source_y->GetValue());
|
||||
boost::rational<int> dest_ar(dest_x->GetValue(), dest_y->GetValue());
|
||||
change_ar->Enable(source_ar != dest_ar);
|
||||
auto source_ar = double(source_x->GetValue()) / source_y->GetValue();
|
||||
auto dest_ar = double(dest_x->GetValue()) / dest_y->GetValue();
|
||||
bool ar_changed = abs(source_ar - dest_ar) / dest_ar > .01;
|
||||
|
||||
ar_mode->Enable(ar_changed);
|
||||
|
||||
bool margins = ar_changed && ar_mode->GetSelection() == (int)ResampleARMode::Manual;
|
||||
symmetrical->Enable(margins);
|
||||
margin_ctrl[LEFT]->Enable(margins);
|
||||
margin_ctrl[TOP]->Enable(margins);
|
||||
margin_ctrl[RIGHT]->Enable(margins && !symmetrical->GetValue());
|
||||
margin_ctrl[BOTTOM]->Enable(margins && !symmetrical->GetValue());
|
||||
}
|
||||
|
||||
void DialogResample::OnSymmetrical(wxCommandEvent &) {
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
namespace agi { struct Context; }
|
||||
class AssFile;
|
||||
class wxCheckBox;
|
||||
class wxRadioBox;
|
||||
class wxSpinCtrl;
|
||||
struct ResampleSettings;
|
||||
|
||||
|
@ -42,7 +43,7 @@ class DialogResample final : public wxDialog {
|
|||
wxSpinCtrl *dest_x;
|
||||
wxSpinCtrl *dest_y;
|
||||
wxCheckBox *symmetrical;
|
||||
wxCheckBox *change_ar;
|
||||
wxRadioBox *ar_mode;
|
||||
wxSpinCtrl *margin_ctrl[4];
|
||||
|
||||
wxButton *from_script;
|
||||
|
|
|
@ -154,6 +154,36 @@ namespace {
|
|||
}
|
||||
|
||||
void ResampleResolution(AssFile *ass, ResampleSettings settings) {
|
||||
auto horizontal_stretch = 1.0;
|
||||
auto old_ar = double(settings.source_x) / settings.source_y;
|
||||
auto new_ar = double(settings.dest_x) / settings.dest_y;
|
||||
bool border_horizontally = new_ar > old_ar;
|
||||
// Don't convert aspect ratio if it's very close to correct
|
||||
// (for reference, 848x480 <-> 1280x720 is .006)
|
||||
if (abs(old_ar - new_ar) / new_ar > .01) {
|
||||
switch (settings.ar_mode) {
|
||||
case ResampleARMode::RemoveBorder:
|
||||
border_horizontally = !border_horizontally;
|
||||
case ResampleARMode::AddBorder:
|
||||
if (border_horizontally) // Wider/Shorter
|
||||
settings.margin[LEFT] = settings.margin[RIGHT] = (settings.source_y * new_ar - settings.source_x) / 2;
|
||||
else // Taller/Narrower
|
||||
settings.margin[TOP] = settings.margin[BOTTOM] = (settings.source_x / new_ar - settings.source_y) / 2;
|
||||
break;
|
||||
case ResampleARMode::Stretch:
|
||||
horizontal_stretch = new_ar / old_ar;
|
||||
break;
|
||||
case ResampleARMode::Manual:
|
||||
old_ar =
|
||||
double(settings.source_x + settings.margin[LEFT] + settings.margin[RIGHT]) /
|
||||
double(settings.source_y + settings.margin[TOP] + settings.margin[BOTTOM]);
|
||||
|
||||
if (abs(old_ar - new_ar) / new_ar > .01)
|
||||
horizontal_stretch = new_ar / old_ar;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Add margins to original resolution
|
||||
settings.source_x += settings.margin[LEFT] + settings.margin[RIGHT];
|
||||
settings.source_y += settings.margin[TOP] + settings.margin[BOTTOM];
|
||||
|
@ -162,12 +192,9 @@ void ResampleResolution(AssFile *ass, ResampleSettings settings) {
|
|||
settings.margin,
|
||||
double(settings.dest_x) / double(settings.source_x),
|
||||
double(settings.dest_y) / double(settings.source_y),
|
||||
1.0
|
||||
horizontal_stretch
|
||||
};
|
||||
|
||||
if (settings.change_ar)
|
||||
state.ar = state.rx / state.ry;
|
||||
|
||||
for (auto& line : ass->Styles)
|
||||
resample_style(&state, line);
|
||||
for (auto& line : ass->Events)
|
||||
|
|
|
@ -16,6 +16,13 @@
|
|||
|
||||
class AssFile;
|
||||
|
||||
enum class ResampleARMode {
|
||||
Stretch,
|
||||
AddBorder,
|
||||
RemoveBorder,
|
||||
Manual
|
||||
};
|
||||
|
||||
/// Configuration parameters for a resample
|
||||
struct ResampleSettings {
|
||||
int margin[4]; ///< Amount to add to each margin
|
||||
|
@ -23,7 +30,7 @@ struct ResampleSettings {
|
|||
int source_y; ///< Original Y resolution
|
||||
int dest_x; ///< New X resolution
|
||||
int dest_y; ///< New Y resolution
|
||||
bool change_ar; ///< Should the aspect ratio of the subs be changed?
|
||||
ResampleARMode ar_mode; ///< What to do if the old AR and new AR don't match
|
||||
};
|
||||
|
||||
/// Resample the subtitles in the project
|
||||
|
|
|
@ -76,6 +76,7 @@ class EnumBinder final : public wxValidator {
|
|||
T *value;
|
||||
|
||||
wxObject *Clone() const override { return new EnumBinder<T>(value); }
|
||||
bool Validate(wxWindow *) override { return true; }
|
||||
|
||||
bool TransferFromWindow() override {
|
||||
if (wxRadioBox *rb = dynamic_cast<wxRadioBox*>(GetWindow()))
|
||||
|
|
Loading…
Reference in a new issue