//////////////////////////////////////
// Only set script info if it changed
int DialogProperties::SetInfoIfDifferent(wxString key,wxString value) {
	// Get script
	AssFile *subs = AssFile::top;

	// Compare
	if (subs->GetScriptInfo(key) != value) {
		subs->SetScriptInfo(key,value);
		return 1;
	}
	else return 0;
}
///////////////////
// split current line
void FrameMain::OnVideoTrackSplitLine(wxCommandEvent &event) {
	videoBox->videoDisplay->Stop();

	// Get line
	AssDialogue *curline = SubsBox->GetDialogue(EditBox->linen);
	if (!curline) return;
	if( !curline->Movement ) return;

	// Create split lines
	int StartFrame = VFR_Output.GetFrameAtTime(curline->Start.GetMS(),true);
	int EndFrame = VFR_Output.GetFrameAtTime(curline->End.GetMS(),false);

	AssFile *subs = AssFile::top;
	int ResXValue,ResYValue;
	swscanf( subs->GetScriptInfo(_T("PlayResX")), _T("%d"), &ResXValue );
	swscanf( subs->GetScriptInfo(_T("PlayResY")), _T("%d"), &ResYValue );
	int SrcXValue = videoBox->videoDisplay->provider->GetSourceWidth();
	int SrcYValue = videoBox->videoDisplay->provider->GetSourceHeight();

	float sx = float(ResXValue)/float(SrcXValue);
	float sy = float(ResYValue)/float(SrcYValue);

	for( int Frame = StartFrame; Frame < EndFrame; Frame ++ )
	{
		int localframe = Frame - StartFrame;

		while( curline->Movement->Frames.size() <= localframe ) localframe--;
		FexMovementFrame f = curline->Movement->Frames[localframe];
//		f.Pos.x /= videoBox->videoDisplay->GetW

		AssDialogue *cur = new AssDialogue( curline->GetEntryData() );
		cur->Start.SetMS(VFR_Output.GetTimeAtFrame(Frame,true));
		cur->End.SetMS(VFR_Output.GetTimeAtFrame(Frame,false));
		cur->Text = wxString::Format( _T("{\\pos(%.0f,%.0f)\\fscx%.2f\\fscy%.2f}"), f.Pos.x*sx, f.Pos.y*sy, f.Scale.x*100, f.Scale.y*100 ) + cur->Text;
		cur->UpdateData();

		SubsBox->InsertLine(cur,EditBox->linen + Frame - StartFrame,true,false);
	}

	// Remove Movement
	DeleteMovement( curline->Movement );
	curline->Movement = 0;

	// Remove Tracker
	delete curline->Tracker;
	curline->Tracker = 0;

	// Remove this line
	SubsBox->DeleteLines(SubsBox->GetRangeArray(EditBox->linen, EditBox->linen));

	videoBox->videoDisplay->RefreshVideo();
}
///////////////
// Constructor
DialogResample::DialogResample(wxWindow *parent, SubtitlesGrid *_grid)
: wxDialog (parent,-1,_("Resample resolution"),wxDefaultPosition)
{
	// Variables
	AssFile *subs = AssFile::top;
	grid = _grid;
	vid = grid->video;
	
	// Resolution line
	wxSizer *ResBoxSizer = new wxStaticBoxSizer(wxVERTICAL,this,_("Resolution"));
	wxSizer *ResSizer = new wxBoxSizer(wxHORIZONTAL);
	int sw,sh;
	subs->GetResolution(sw,sh);
	ResXValue = wxString::Format(_T("%i"),sw);
	ResYValue = wxString::Format(_T("%i"),sh);
	ResX = new wxTextCtrl(this,-1,_T(""),wxDefaultPosition,wxSize(50,20),0,NumValidator(&ResXValue));
	ResY = new wxTextCtrl(this,-1,_T(""),wxDefaultPosition,wxSize(50,20),0,NumValidator(&ResYValue));
	wxStaticText *ResText = new wxStaticText(this,-1,_("x"));
	wxButton *FromVideo = new wxButton(this,BUTTON_DEST_FROM_VIDEO,_("From video"));
	if (!vid->loaded) FromVideo->Enable(false);
	ResSizer->Add(ResX,1,wxRIGHT,5);
	ResSizer->Add(ResText,0,wxALIGN_CENTER | wxRIGHT,5);
	ResSizer->Add(ResY,1,wxRIGHT,5);
	ResSizer->Add(FromVideo,1,0,0);

	// Resolution box
	Anamorphic = new wxCheckBox(this,CHECK_ANAMORPHIC,_("Change aspect ratio"));
	ResBoxSizer->Add(ResSizer,1,wxEXPAND|wxBOTTOM,5);
	ResBoxSizer->Add(Anamorphic,0,0,0);

	// Button sizer
	wxSizer *ButtonSizer = new wxBoxSizer(wxHORIZONTAL);
	ButtonSizer->AddStretchSpacer(1);
#ifndef __WXMAC__
	ButtonSizer->Add(new wxButton(this,BUTTON_RESAMPLE,_("Resample")),0,wxRIGHT,5);
	ButtonSizer->Add(new wxButton(this,wxID_CANCEL),0,wxRIGHT,0);
#else
	ButtonSizer->Add(new wxButton(this,wxID_CANCEL),0,wxRIGHT,5);
	wxButton *resampleButton = new wxButton(this,BUTTON_RESAMPLE,_("Resample"));
	ButtonSizer->Add(resampleButton,0,wxRight,0);
	resampleButton->SetDefault();
#endif

	// Main sizer
	wxSizer *MainSizer = new wxBoxSizer(wxVERTICAL);
	MainSizer->Add(ResBoxSizer,1,wxEXPAND|wxALL,5);
	MainSizer->Add(ButtonSizer,0,wxEXPAND|wxRIGHT|wxLEFT|wxBOTTOM,5);
	MainSizer->SetSizeHints(this);
	SetSizer(MainSizer);
	CenterOnParent();
}
Пример #4
0
/// @brief Load generic subs
void AssFile::Load(const wxString &_filename, wxString const& charset) {
	const SubtitleFormat *reader = SubtitleFormat::GetReader(_filename);

	try {
		AssFile temp;
		reader->ReadFile(&temp, _filename, charset);

		bool found_style = false;
		bool found_dialogue = false;

		// Check if the file has at least one style and at least one dialogue line
		for (auto const& line : temp.Line) {
			AssEntryGroup type = line.Group();
			if (type == ENTRY_STYLE) found_style = true;
			if (type == ENTRY_DIALOGUE) found_dialogue = true;
			if (found_style && found_dialogue) break;
		}

		// And if it doesn't add defaults for each
		if (!found_style)
			temp.InsertLine(new AssStyle);
		if (!found_dialogue)
			temp.InsertLine(new AssDialogue);

		swap(temp);
	}
	catch (agi::UserCancelException const&) {
		return;
	}

	// Set general data
	loaded = true;
	filename = _filename;

	// Add comments and set vars
	SetScriptInfo("ScriptType", "v4.00+");

	// Push the initial state of the file onto the undo stack
	UndoStack.clear();
	RedoStack.clear();
	undoDescription.clear();
	autosavedCommitId = savedCommitId = commitId + 1;
	Commit("", COMMIT_NEW);

	FileOpen(filename);
}
Пример #5
0
void TTXTSubtitleFormat::ConvertToTTXT(AssFile &file) const {
	file.Sort();
	StripComments(file);
	RecombineOverlaps(file);
	MergeIdentical(file);
	StripTags(file);
	ConvertNewlines(file, "\r\n");

	// Find last line
	agi::Time lastTime;
	if (!file.Events.empty())
		lastTime = file.Events.back().End;

	// Insert blank line at the end
	auto diag = new AssDialogue;
	diag->Start = lastTime;
	diag->End = lastTime+OPT_GET("Timing/Default Duration")->GetInt();
	file.Events.push_back(*diag);
}
Пример #6
0
void TTXTSubtitleFormat::ConvertToTTXT(AssFile &file) const {
	file.Sort();
	StripComments(file);
	RecombineOverlaps(file);
	MergeIdentical(file);
	StripTags(file);
	ConvertNewlines(file, "\r\n");

	// Find last line
	AssTime lastTime;
	for (auto line : file.Line | boost::adaptors::reversed | agi::of_type<AssDialogue>()) {
		lastTime = line->End;
		break;
	}

	// Insert blank line at the end
	auto diag = new AssDialogue;
	diag->Start = lastTime;
	diag->End = lastTime+OPT_GET("Timing/Default Duration")->GetInt();
	file.Line.push_back(*diag);
}
Пример #7
0
void TTXTSubtitleFormat::ConvertToTTXT(AssFile &file) const {
	file.Sort();
	StripComments(file.Line);
	RecombineOverlaps(file.Line);
	MergeIdentical(file.Line);
	StripTags(file.Line);
	ConvertNewlines(file.Line, "\r\n");

	// Find last line
	AssTime lastTime;
	for (LineList::reverse_iterator cur = file.Line.rbegin(); cur != file.Line.rend(); ++cur) {
		if (AssDialogue *prev = dynamic_cast<AssDialogue*>(*cur)) {
			lastTime = prev->End;
			break;
		}
	}

	// Insert blank line at the end
	AssDialogue *diag = new AssDialogue;
	diag->Start = lastTime;
	diag->End = lastTime+OPT_GET("Timing/Default Duration")->GetInt();
	file.Line.push_back(diag);
}
Пример #8
0
void DialogStyleManager::OnCurrentImport() {
	auto filename = OpenFileSelector(_("Open subtitles file"), "Path/Last/Subtitles", "", "", SubtitleFormat::GetWildcards(0), this);
	if (filename.empty()) return;

	std::string charset;
	try {
		charset = CharSetDetect::GetEncoding(filename);
	}
	catch (agi::UserCancelException const&) {
		return;
	}

	AssFile temp;
	try {
		auto reader = SubtitleFormat::GetReader(filename, charset);
		if (!reader)
			wxMessageBox("Unsupported subtitle format", "Error", wxOK | wxICON_ERROR | wxCENTER, this);
		else
			reader->ReadFile(&temp, filename, charset);
	}
	catch (agi::Exception const& err) {
		wxMessageBox(to_wx(err.GetChainedMessage()), "Error", wxOK | wxICON_ERROR | wxCENTER, this);
	}
	catch (...) {
		wxMessageBox("Unknown error", "Error", wxOK | wxICON_ERROR | wxCENTER, this);
		return;
	}

	// Get styles
	auto styles = temp.GetStyles();
	if (styles.empty()) {
		wxMessageBox(_("The selected file has no available styles."), _("Error Importing Styles"));
		return;
	}

	// Get selection
	wxArrayInt selections;
	int res = GetSelectedChoices(this, selections, _("Choose styles to import:"), _("Import Styles"), to_wx(styles));
	if (res == -1 || selections.empty()) return;
	bool modified = false;

	// Loop through selection
	for (auto const& sel : selections) {
		// Check if there is already a style with that name
		if (AssStyle *existing = c->ass->GetStyle(styles[sel])) {
			int answer = wxMessageBox(
				wxString::Format(_("There is already a style with the name \"%s\" in the current script. Overwrite?"), styles[sel]),
				_("Style name collision"),
				wxYES_NO);
			if (answer == wxYES) {
				modified = true;
				*existing = *temp.GetStyle(styles[sel]);
			}
			continue;
		}

		// Copy
		modified = true;
		c->ass->InsertLine(temp.GetStyle(styles[sel])->Clone());
	}

	// Update
	if (modified)
		c->ass->Commit(_("style import"), AssFile::COMMIT_STYLES);
}
Пример #9
0
	void swap(AssFile &lft, AssFile &rgt) {
		lft.swap(rgt);
	}
Пример #10
0
void AssStyleStorage::ReplaceIntoFile(AssFile &file) {
	for (auto const& s : style) {
		delete file.GetStyle(s->name);
		file.Styles.push_back(*new AssStyle(*s));
	}
}
////////////
// Resample
void DialogResample::OnResample (wxCommandEvent &event) {
	// Resolutions
	AssFile *subs = AssFile::top;
	int x1,y1;
	subs->GetResolution(x1,y1);
	long x2 = 0;
	long y2 = 0;
	ResX->GetValue().ToLong(&x2);
	ResY->GetValue().ToLong(&y2);

	// Check for validity
	if (x1 == 0 || x2 == 0 || y1 == 0 || y2 == 0) {
		EndModal(0);
		return;
	}

	// Calculate resamples
	rx = double(x2)/double(x1);
	ry = double(y2)/double(y1);
	r = ry;
	if (Anamorphic->IsChecked()) ar = rx/ry;
	else ar = 1.0;

	// Iterate through subs
	AssStyle *curStyle;
	AssDialogue *curDiag;
	for (entryIter cur=subs->Line.begin();cur!=subs->Line.end();cur++) {
		// Apply to dialogues
		curDiag = AssEntry::GetAsDialogue(*cur);
		if (curDiag) {
			try {
				// Override tags
				curDiag->ParseASSTags();
				curDiag->ProcessParameters(ResampleTags,curDiag);

				// Drawing tags
				size_t nblocks = curDiag->Blocks.size();
				AssDialogueBlockDrawing *curBlock;
				for (size_t i=0;i<nblocks;i++) {
					curBlock = AssDialogueBlock::GetAsDrawing(curDiag->Blocks.at(i));
					if (curBlock) {
						curBlock->MultiplyCoords(rx,ry);
					}
				}

				// Margins
				curDiag->MarginL = int(curDiag->MarginL * rx + 0.5);
				curDiag->MarginR = int(curDiag->MarginR * rx + 0.5);
				curDiag->MarginV = int(curDiag->MarginV * ry + 0.5);

				// Update
				curDiag->UpdateText();
				curDiag->UpdateData();
				curDiag->ClearBlocks();
				continue;
			}
			catch (const wchar_t *err) {
				wxLogMessage(err);
			}
			catch (wxString err) {
				wxLogMessage(err);
			}
		}

		// Apply to styles
		curStyle = AssEntry::GetAsStyle(*cur);
		if (curStyle) {
			curStyle->fontsize = int(curStyle->fontsize * r + 0.5);
			//curStyle->outline_w *= r;
			//curStyle->shadow_w *= r;
			curStyle->spacing *= rx;
			curStyle->scalex *= ar;
			curStyle->MarginL = int(curStyle->MarginL * rx + 0.5);
			curStyle->MarginR = int(curStyle->MarginR * rx + 0.5);
			curStyle->MarginV = int(curStyle->MarginV * ry + 0.5);
			curStyle->UpdateData();
		}
	}

	// Change script resolution
	subs->SetScriptInfo(_T("PlayResX"),wxString::Format(_T("%i"),x2));
	subs->SetScriptInfo(_T("PlayResY"),wxString::Format(_T("%i"),y2));

	// Flag as modified
	subs->FlagAsModified();
	grid->CommitChanges();;
	EndModal(0);
}
///////////////
// Constructor
DialogProperties::DialogProperties (wxWindow *parent, VideoDisplay *_vid)
: wxDialog(parent, -1, _("Script Properties"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE)
{
	// Setup
	vid = _vid;
	AssFile *subs = AssFile::top;

	// Script details crap
	wxStaticText *TitleLabel = new wxStaticText(this,-1,_("Title:"));
	TitleEdit = new wxTextCtrl(this,-1,subs->GetScriptInfo(_T("Title")),wxDefaultPosition,wxSize(200,20));
	wxStaticText *OrigScriptLabel = new wxStaticText(this,-1,_("Original script:"));
	OrigScriptEdit = new wxTextCtrl(this,-1,subs->GetScriptInfo(_T("Original Script")),wxDefaultPosition,wxSize(200,20));
	wxStaticText *TranslationLabel = new wxStaticText(this,-1,_("Translation:"));
	TranslationEdit = new wxTextCtrl(this,-1,subs->GetScriptInfo(_T("Original Translation")),wxDefaultPosition,wxSize(200,20));
	wxStaticText *EditingLabel = new wxStaticText(this,-1,_("Editing:"));
	EditingEdit = new wxTextCtrl(this,-1,subs->GetScriptInfo(_T("Original Editing")),wxDefaultPosition,wxSize(200,20));
	wxStaticText *TimingLabel = new wxStaticText(this,-1,_("Timing:"));
	TimingEdit = new wxTextCtrl(this,-1,subs->GetScriptInfo(_T("Original Timing")),wxDefaultPosition,wxSize(200,20));
	wxStaticText *SyncLabel = new wxStaticText(this,-1,_("Synch point:"));
	SyncEdit = new wxTextCtrl(this,-1,subs->GetScriptInfo(_T("Synch Point")),wxDefaultPosition,wxSize(200,20));
	wxStaticText *UpdatedLabel = new wxStaticText(this,-1,_("Updated by:"));
	UpdatedEdit = new wxTextCtrl(this,-1,subs->GetScriptInfo(_T("Script Updated By")),wxDefaultPosition,wxSize(200,20));
	wxStaticText *UpdateDetailsLabel = new wxStaticText(this,-1,_("Update details:"));
	UpdateDetailsEdit = new wxTextCtrl(this,-1,subs->GetScriptInfo(_T("Update Details")),wxDefaultPosition,wxSize(200,20));
	wxSizer *TopSizer = new wxStaticBoxSizer(wxHORIZONTAL,this,_("Script"));
	wxSizer *TopSizerGrid = new wxFlexGridSizer(0,2,5,5);
	TopSizerGrid->Add(TitleLabel,0,wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL,0);
	TopSizerGrid->Add(TitleEdit,1,0,0);
	TopSizerGrid->Add(OrigScriptLabel,0,wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL,0);
	TopSizerGrid->Add(OrigScriptEdit,1,0,0);
	TopSizerGrid->Add(TranslationLabel,0,wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL,0);
	TopSizerGrid->Add(TranslationEdit,1,0,0);
	TopSizerGrid->Add(EditingLabel,0,wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL,0);
	TopSizerGrid->Add(EditingEdit,1,0,0);
	TopSizerGrid->Add(TimingLabel,0,wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL,0);
	TopSizerGrid->Add(TimingEdit,1,0,0);
	TopSizerGrid->Add(SyncLabel,0,wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL,0);
	TopSizerGrid->Add(SyncEdit,1,0,0);
	TopSizerGrid->Add(UpdatedLabel,0,wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL,0);
	TopSizerGrid->Add(UpdatedEdit,1,0,0);
	TopSizerGrid->Add(UpdateDetailsLabel,0,wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL,0);
	TopSizerGrid->Add(UpdateDetailsEdit,1,0,0);
	TopSizer->Add(TopSizerGrid,0,wxALL,0);

	// Resolution box
	wxSizer *ResSizer = new wxStaticBoxSizer(wxHORIZONTAL,this,_("Resolution"));
	ResXValue = subs->GetScriptInfo(_T("PlayResX"));
	ResYValue = subs->GetScriptInfo(_T("PlayResY"));
	ResX = new wxTextCtrl(this,-1,_T(""),wxDefaultPosition,wxSize(50,20),0,NumValidator(&ResXValue));
	ResY = new wxTextCtrl(this,-1,_T(""),wxDefaultPosition,wxSize(50,20),0,NumValidator(&ResYValue));
	wxStaticText *ResText = new wxStaticText(this,-1,_T("x"));
	wxButton *FromVideo = new wxButton(this,BUTTON_FROM_VIDEO,_("From video"));
	if (!vid->loaded) FromVideo->Enable(false);
	ResSizer->Add(ResX,1,wxRIGHT,5);
	ResSizer->Add(ResText,0,wxALIGN_CENTER | wxRIGHT,5);
	ResSizer->Add(ResY,1,wxRIGHT,5);
	ResSizer->Add(FromVideo,1,0,0);

	// Wrap box
	wxSizer *WrapBox = new wxStaticBoxSizer(wxHORIZONTAL,this,_("Wrap style"));
	wxArrayString options;
	options.Add(_("0: Smart wrapping, top line is wider"));
	options.Add(_("1: End-of-line word wrapping, only \\N breaks"));
	options.Add(_("2: No word wrapping, both \\n and \\N break"));
	options.Add(_("3: Smart wrapping, bottom line is wider"));
	WrapStyle = new wxComboBox(this,-1,_T(""),wxDefaultPosition,wxDefaultSize,options,wxCB_READONLY);
	long n;
	subs->GetScriptInfo(_T("WrapStyle")).ToLong(&n);
	WrapStyle->SetSelection(n);
	WrapBox->Add(WrapStyle,1,0,0);

	// Button sizer
	wxButton *ButtonOK = new wxButton(this,wxID_OK);
	ButtonOK->SetDefault();
	wxSizer *ButtonSizer = new wxBoxSizer(wxHORIZONTAL);
	ButtonSizer->AddStretchSpacer(1);
	ButtonSizer->Add(ButtonOK,0,0,0);

	// MainSizer
	wxSizer *MainSizer = new wxBoxSizer(wxVERTICAL);
	MainSizer->Add(TopSizer,0,wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND,5);
	MainSizer->Add(ResSizer,0,wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND,5);
	MainSizer->Add(WrapBox,0,wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND,5);
	MainSizer->Add(ButtonSizer,0,wxLEFT | wxRIGHT | wxBOTTOM | wxEXPAND,5);

	// Set sizer
	SetSizer(MainSizer);
	MainSizer->SetSizeHints(this);
	CenterOnParent();
}
Пример #13
0
void SubsController::Load(agi::fs::path const& filename, std::string charset) {
	try {
		if (charset.empty())
			charset = CharSetDetect::GetEncoding(filename);
	}
	catch (agi::UserCancelException const&) {
		return;
	}

	// Make sure that file isn't actually a timecode file
	if (charset != "binary") {
		try {
			TextFileReader testSubs(filename, charset);
			std::string cur = testSubs.ReadLineFromFile();
			if (boost::starts_with(cur, "# timecode")) {
				context->videoController->LoadTimecodes(filename);
				return;
			}
		}
		catch (...) {
			// if trying to load the file as timecodes fails it's fairly
			// safe to assume that it is in fact not a timecode file
		}
	}

	const SubtitleFormat *reader = SubtitleFormat::GetReader(filename);

	try {
		AssFile temp;
		reader->ReadFile(&temp, filename, charset);

		bool found_style = false;
		bool found_dialogue = false;

		// Check if the file has at least one style and at least one dialogue line
		for (auto const& line : temp.Line) {
			AssEntryGroup type = line.Group();
			if (type == AssEntryGroup::STYLE) found_style = true;
			if (type == AssEntryGroup::DIALOGUE) found_dialogue = true;
			if (found_style && found_dialogue) break;
		}

		// And if it doesn't add defaults for each
		if (!found_style)
			temp.InsertLine(new AssStyle);
		if (!found_dialogue)
			temp.InsertLine(new AssDialogue);

		context->ass->swap(temp);
	}
	catch (agi::UserCancelException const&) {
		return;
	}
	catch (agi::fs::FileNotFound const&) {
		wxMessageBox(filename.wstring() + " not found.", "Error", wxOK | wxICON_ERROR | wxCENTER, context->parent);
		config::mru->Remove("Subtitle", filename);
		return;
	}
	catch (agi::Exception const& err) {
		wxMessageBox(to_wx(err.GetChainedMessage()), "Error", wxOK | wxICON_ERROR | wxCENTER, context->parent);
		return;
	}
	catch (std::exception const& err) {
		wxMessageBox(to_wx(err.what()), "Error", wxOK | wxICON_ERROR | wxCENTER, context->parent);
		return;
	}
	catch (...) {
		wxMessageBox("Unknown error", "Error", wxOK | wxICON_ERROR | wxCENTER, context->parent);
		return;
	}

	SetFileName(filename);

	// Push the initial state of the file onto the undo stack
	undo_stack.clear();
	redo_stack.clear();
	autosaved_commit_id = saved_commit_id = commit_id + 1;
	context->ass->Commit("", AssFile::COMMIT_NEW);

	// Save backup of file
	if (CanSave() && OPT_GET("App/Auto/Backup")->GetBool()) {
		auto path_str = OPT_GET("Path/Auto/Backup")->GetString();
		agi::fs::path path;
		if (path_str.empty())
			path = filename.parent_path();
		else
			path = config::path->Decode(path_str);
		agi::fs::CreateDirectory(path);
		agi::fs::Copy(filename, path/(filename.stem().string() + ".ORIGINAL" + filename.extension().string()));
	}

	FileOpen(filename);
}