diff --git a/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj b/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj index 68451a990..2be82e2e1 100644 --- a/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj +++ b/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj @@ -1571,14 +1571,6 @@ RelativePath="..\..\src\subtitle_format_mkv.h" > - - - - diff --git a/aegisub/src/subtitle_format_prs.cpp b/aegisub/src/subtitle_format_prs.cpp deleted file mode 100644 index c99809af7..000000000 --- a/aegisub/src/subtitle_format_prs.cpp +++ /dev/null @@ -1,837 +0,0 @@ -// Copyright (c) 2006, Rodrigo Braz Monteiro -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of the Aegisub Group nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// Aegisub Project http://www.aegisub.org/ -// -// $Id$ - -/// @file subtitle_format_prs.cpp -/// @brief Writing of pre-rendered subtitle format files -/// @ingroup subtitle_io -/// - - -/////////// -// Headers -#include "config.h" - -#if USE_PRS == 1 -#ifndef AGI_PRE -#include -#include -#include -#include -#endif - -#include "../prs/prs.h" -#include "ass_dialogue.h" -#include "ass_file.h" -#include "ass_override.h" -#include "avisynth_wrap.h" -#include "charset_conv.h" -#include "dialog_progress.h" -#include "frame_main.h" -#include "main.h" -#include "md5.h" -#include "subtitle_format_prs.h" -#include "utils.h" -#include "vfr.h" -#include "video_box.h" -#include "video_display.h" -#include "video_provider.h" - - -/// @brief Can write to file? -/// @param filename -/// @return -/// -bool PRSSubtitleFormat::CanWriteFile(wxString filename) { -#ifdef __WINDOWS__ - return false; - //return (filename.Right(4).Lower() == _T(".prs")); -#else - return false; -#endif -} - - - -/// @brief Get name -/// @return -/// -wxString PRSSubtitleFormat::GetName() { - return _T("Pre-Rendered Subtitles"); -} - - - -/// @brief Get write wildcards -/// @return -/// -wxArrayString PRSSubtitleFormat::GetWriteWildcards() { - wxArrayString formats; - formats.Add(_T("prs")); - return formats; -} - - - -/// @brief Write file -/// @param filename -/// @param encoding -/// @return -/// -void PRSSubtitleFormat::WriteFile(wxString filename,wxString encoding) { -#ifdef __WINDOWS__ - // Video loaded? - if (VideoContext::Get()->IsLoaded()) throw _T("Video not loaded!"); - - // Create the PRS file - PRSFile file; - - // Create the temporary .ass file - wxString tempFile1 = wxFileName::CreateTempFileName(_T("aegisub")); - wxRemoveFile(tempFile1); - wxString tempFile = tempFile1 + _T(".ass"); - GetAssFile()->Save(tempFile,false,false); - - // Open two Avisynth environments - AviSynthWrapper avs1,avs2; - IScriptEnvironment *env1 = avs1.GetEnv(); - IScriptEnvironment *env2 = avs2.GetEnv(); - - // Prepare the Avisynth environments, that is, generate blank clips and hardsub into them - wxString val = wxString::Format(_T("BlankClip(pixel_type=\"RGB32\",length=%i,width=%i,height=%i,fps=%f"),VideoContext::Get()->GetLength(),VideoContext::Get()->GetWidth(),VideoContext::Get()->GetHeight(),VideoContext::Get()->GetFPS()); - AVSValue script1 = env1->Invoke("Eval",AVSValue(wxString(val + _T(",color=$000000)")).mb_str(wxConvUTF8))); - AVSValue script2 = env2->Invoke("Eval",AVSValue(wxString(val + _T(",color=$FFFFFF)")).mb_str(wxConvUTF8))); - char temp[512]; - strcpy(temp,tempFile.mb_str(csConvLocal)); - AVSValue args1[2] = { script1.AsClip(), temp }; - AVSValue args2[2] = { script2.AsClip(), temp }; - try { - script1 = env1->Invoke("TextSub", AVSValue(args1,2)); - script2 = env2->Invoke("TextSub", AVSValue(args2,2)); - } - catch (AvisynthError &err) { - throw _T("AviSynth error: ") + wxString(err.msg,csConvLocal); - } - PClip clip1 = script1.AsClip(); - PClip clip2 = script2.AsClip(); - - // Get range - std::vector frames = GetFrameRanges(); - int totalFrames = frames.size(); - int toDraw = 0; - for (int i=0;iShow(); - progress->SetProgress(0,toDraw); - - // Render all frames that were detected to contain subtitles - int lastFrameDrawn = 0; - int drawn = 0; - for (int framen=0;framenSetProgress(drawn,toDraw); - progress->SetText(wxString::Format(_T("Writing PRS file. Line: %i/%i (%.2f%%)"),framen,totalFrames,MIN(float(drawn)*100/toDraw,100.0))); - if (frames[framen] == 2) drawn++; - - // Read the frame image - PVideoFrame frame1 = clip1->GetFrame(framen,env1); - PVideoFrame frame2 = clip2->GetFrame(framen,env2); - - // Prepare to get wxImage - int x=0,y=0; - int maxalpha=0; - - // Get wxImage - wxImage bmp = CalculateAlpha(frame1->GetReadPtr(),frame2->GetReadPtr(),frame1->GetRowSize(),frame1->GetHeight(),frame1->GetPitch(),&x,&y,&maxalpha); - if (!bmp.Ok()) continue; - lastFrameDrawn = framen; - - // Get the list of rectangles - std::vector rects; - GetSubPictureRectangles(bmp,rects); - - // Add each sub-image to file - int nrects = rects.size(); - int useFrameN; - for (int i=0;iDestroy(); - else return; - - // Save file - file.Save((const char*)filename.mb_str(csConvLocal)); - wxString filename2 = filename + _T(".prsa"); - file.SaveText((const char*)filename2.mb_str(csConvLocal)); - - // Delete temp file - wxRemoveFile(tempFile); -#endif -} - - - -/// @brief Insert frame into file -/// @param file -/// @param framen -/// @param frames -/// @param bmp -/// @param x -/// @param y -/// @param maxalpha -/// -void PRSSubtitleFormat::InsertFrame(PRSFile &file,int &framen,std::vector &frames,wxImage &bmp,int x,int y,int maxalpha) { - // Generic data holder - size_t datasize = 0; - char *rawData = NULL; - std::vector data; - //bmp.SaveFile(wxString::Format(_T("test_%i.png"),id),wxBITMAP_TYPE_PNG); - - // pngout/optipng optimize - if (optimizer) { - // Get temporary filename - wxString tempFile = wxFileName::CreateTempFileName(_T("aegiprs")); - wxString tempOut = tempFile + _T("out.png"); - - // Prepare arrays to capture output - wxArrayString output; - wxArrayString errors; - - // Generate the temporary PNG and run the optimizer program on it - if (optimizer == 1) { - bmp.SaveFile(tempOut,wxBITMAP_TYPE_PNG); - wxExecute(AegisubApp::folderName + _T("optipng.exe -zc9 -zm8 -zs0-3 -f0 ") + tempOut,output,errors); - } - if (optimizer == 2) { - bmp.SaveFile(tempFile,wxBITMAP_TYPE_PNG); - wxExecute(AegisubApp::folderName + _T("pngout.exe ") + tempFile + _T(" ") + tempOut + _T(" /f0 /y /q"),output,errors); - } - - // Read file back - FILE *fp = fopen(tempOut.mb_str(csConvLocal),"rb"); - fseek(fp,0,SEEK_END); - datasize = ftell(fp); - data.resize(datasize); - rawData = &data[0]; - rewind(fp); - fread(rawData,1,datasize,fp); - fclose(fp); - - // Destroy temporary files - wxRemoveFile(tempFile); - wxRemoveFile(tempOut); - } - - // No optimization (much faster) - else { - // Convert wxImage to PNG directly - wxMemoryOutputStream stream; - bmp.SaveFile(stream,wxBITMAP_TYPE_PNG); - datasize = stream.GetSize(); - data.resize(datasize); - rawData = &data[0]; - stream.CopyTo(rawData,datasize); - } - - // Find start and end times - int startf = framen; - int totalFrames = frames.size(); - while (++framenid = id; - img->imageType = PNG_IMG; - img->w = bmp.GetWidth(); - img->h = bmp.GetHeight(); - img->maxAlpha = maxalpha; - img->dataLen = datasize; - img->data = new char[img->dataLen]; - memcpy(img->data,rawData,img->dataLen); - - // Hash the PRSImage data - md5_state_t state; - md5_init(&state); - md5_append(&state,(md5_byte_t*)img->data,img->dataLen); - md5_finish(&state,(md5_byte_t*)img->md5); - - // Check for duplicates - PRSImage *dupe = file.FindDuplicateImage(img); - int useID = id; - - // Dupe found, use that instead - if (dupe) { - useID = dupe->id; - delete img; - img = NULL; - } - - // Frame is all OK, add it to file - else { - file.AddEntry(img); - id++; - } - - // Set blend data - unsigned char alpha = 255; - unsigned char blend = 0; - - // Check if it's just an extension of last display - if (lastDisplay && lastDisplay->id == (unsigned)useID && (signed)lastDisplay->endFrame == startf-1 && - lastDisplay->x == x && lastDisplay->y == y && lastDisplay->alpha == alpha && lastDisplay->blend == blend) - { - lastDisplay->end = start; - lastDisplay->endFrame = startf; - } - - // It isn't; needs a new display command - else { - // Create PRSDisplay - PRSDisplay *display = new PRSDisplay; - display->start = start; - display->end = end; - display->startFrame = startf; - display->endFrame = endf; - display->id = useID; - display->x = x; - display->y = y; - display->alpha = alpha; - display->blend = blend; - lastDisplay = display; - - // Insert into list - file.AddEntry(display); - } -} - - - -/// @brief Get rectangles of useful glyphs -/// @param image -/// @param rects -/// -void PRSSubtitleFormat::GetSubPictureRectangles(wxImage &image,std::vector &rects) { - // Boundaries - int w = image.GetWidth(); - int h = image.GetHeight(); - int startx = 0; - int starty = 0; - int endx = w-1; - int endy = h-1; - - // Variables - bool hasSubImage = false; - bool isBlankRow = true; - const unsigned char *data = image.GetAlpha(); - const unsigned char *src = data; - unsigned char a; - - // For each row - for (int y=0;y<=h;y++) { - if (y < h) { - // Reset row data - isBlankRow = true; - if (!hasSubImage) { - startx = w; - endx = -1; - } - - // Check row - for (int x=0;x endx) endx = x; - } - } - - // Set sub image status - if (!isBlankRow && !hasSubImage) { - starty = y; - hasSubImage = true; - } - } - - // If the processed row is totally blank and there is a subimage, separate them - if ((isBlankRow && hasSubImage) || y == h) { - // Insert rectangle - endy = y-1; - rects.push_back(wxRect(startx,starty,endx-startx+1,endy-starty+1)); - hasSubImage = false; - } - } -} - - - -/// @brief Get frame ranges -/// @return -/// -std::vector PRSSubtitleFormat::GetFrameRanges() { - // Loop through subtitles in file - std::vector frames; - for (entryIter cur=Line->begin();cur!=Line->end();cur++) { - AssDialogue *diag = AssEntry::GetAsDialogue(*cur); - - // Dialogue found - if (diag && !diag->Comment) { - // Parse tags - diag->ParseASSTags(); - - // Check if there is any animation tag, to flag the line as animated, forcing storage of every frame - // THIS NEEDS OPTIMIZATION! - // Currently it will redraw whole line, even if only some time of it is animated. - // This is later hopefully removed by duplicate checker, but it would be faster if done here - bool hasAnimation = false; - int blocks = diag->Blocks.size(); - AssDialogueBlockOverride *block; - for (int i=0;iBlocks[i]); - if (block) { - // Found an override block, see if it contains any animation tags - int tags = block->Tags.size(); - for (int j=0;jTags[j]->Name; - if (tagName == _T("\\t") || tagName == _T("\\move") || tagName == _T("\\k") || tagName == _T("\\K") || - tagName == _T("\\kf") || tagName == _T("\\ko") || tagName == _T("\\fad") || tagName == _T("\\fade")) { - hasAnimation = true; - } - } - } - } - - // Calculate start and end times - size_t start = VFR_Output.GetFrameAtTime(diag->Start.GetMS(),true); - size_t end = VFR_Output.GetFrameAtTime(diag->End.GetMS(),false); - - // Ensure that the vector is long enough - // Yes, +1, this is an optimization for something below - if (frames.size() <= end+1) frames.resize(end+2); - - // Fill data - // 2 = Store this frame - // 1 = Repeat last frame - // 0 = Don't store this frame - bool lastOn = false; - for (size_t i=start;i<=end;i++) { - // Put a keyframe at the very start, or everywhere if it's animated - if (i == start || hasAnimation) frames[i] = 2; - - else { - // Already set to 1 or 2, meaning that another subtitle is here already - if (frames[i] != 0) lastOn = true; - - // Set to 0, so nothing is here - else { - // Just came out of a subtitle end, put a keyframe here - if (lastOn) { - frames[i] = 2; - lastOn = false; - } - - // Otherwise, just repeat - frames[i] = 1; - } - } - - // Ends right before another "1" block, so make this a "2" - if (i == end && frames[i+1] == 1) frames[i] = 2; - } - - // Clean up - diag->ClearBlocks(); - } - } - - // Done - return frames; -} - - - -/// DOCME -#define IN_ERROR_MARGIN(col1,col2,error) ((col1 > col2 ? ((int)(col1-col2)) : ((int)(col2-col1))) <= (error)) - - -/// @brief e.g. if you have a pixel with 25% opacity, then a difference of as much as 3 in the color channels won't have a visual impact This "flood fills" the image based on alpha, to make it easier to compress, without affecting visual quality Now, since I don't expect anyone to be able to decypher this... -/// @param image -/// -void PRSSubtitleFormat::OptimizeImage(wxImage &image) { - // Get the raw data - unsigned char *data = (unsigned char*) image.GetData(); - unsigned char *alpha = (unsigned char*) image.GetAlpha(); - int w = image.GetWidth(); - int h = image.GetHeight(); - int len = w*h; - - // Create mask for status and fill with zeroes - char *status = new char[len]; - for (int i=0;i highAlpha) highAlpha = alpha[i]; - } - - // Fill mask of "correct" pixels with 2 on highAlpha pixels - for (int i=0;i= w && status[i-w] == 2) { - // Get colors - d1 = *(cur-w*3-3); - d2 = *(cur-w*3-2); - d3 = *(cur-w*3-1); - - // Compare error - if (IN_ERROR_MARGIN(d1,c1,error) && IN_ERROR_MARGIN(d2,c2,error) && IN_ERROR_MARGIN(d3,c3,error)) { - *(cur-3) = d1; - *(cur-2) = d2; - *(cur-1) = d3; - status[i] = 2; - modified++; - continue; - } - } - - // Bottom pixel - if (i < len-w && status[i+w] == 2) { - // Get colors - d1 = *(cur+w*3-3); - d2 = *(cur+w*3-2); - d3 = *(cur+w*3-1); - - // Compare error - if (IN_ERROR_MARGIN(d1,c1,error) && IN_ERROR_MARGIN(d2,c2,error) && IN_ERROR_MARGIN(d3,c3,error)) { - *(cur-3) = d1; - *(cur-2) = d2; - *(cur-1) = d3; - status[i] = 2; - modified++; - continue; - } - } - } - - // End repetion - totalModified += modified; - if (!modified) doRepeat = false; - } - - // End outer loop - if (!totalModified) outerLoop = false; - - // Copy values 1 to 2 - int changes = 0; - for (int i=0;i=0;) { - for (int x=0;x maxx) maxx = x; - if (y < miny) miny = y; - else if (y > maxy) maxy = y; - - // Calculate colour components - //int mod = MAX(0,128/a-1); - //r = MAX(0,r1-mod)*255 / a; - //g = MAX(0,g1-mod)*255 / a; - //b = MAX(0,b1-mod)*255 / a; - r = r1*255/a; - g = g1*255/a; - b = b1*255/a; - } - - // Write to destination - *(dst++) = r; - *(dst++) = g; - *(dst++) = b; - *(dsta++) = a; - - // Store maximum alpha - if (a > maxA) maxA = a; - } - - // Roll back dst - dst -= w*3/2; - dsta -= w/2; - } - - // Store maximum alpha - if (maxalpha) *maxalpha = maxA; - - // Calculate sizes - minx /= 4; - maxx /= 4; - if (dstx) *dstx = minx; - if (dsty) *dsty = miny; - int width = maxx-minx+1; - int height = maxy-miny+1; - - // 100% transparent image; clean up and return an empty one - if (width <= 0 || height <= 0) { - delete [] data; - delete [] alpha; - return wxImage(); - } - - // Create the actual image - wxImage img(w/4,h,data,false); - img.SetAlpha(alpha,false); - - // Return subimage - wxImage subimg = SubImageWithAlpha(img,wxRect(minx,miny,width,height)); - return subimg; -} - - - -/// @brief Modified from wx's source Creates a sub image preserving alpha channel -/// @param source -/// @param rect -/// -wxImage PRSSubtitleFormat::SubImageWithAlpha (wxImage &source,const wxRect &rect) { - wxImage image; - wxCHECK_MSG(source.Ok(), image, wxT("invalid image") ); - wxCHECK_MSG((rect.GetLeft()>=0) && (rect.GetTop()>=0) && (rect.GetRight()<=source.GetWidth()) && (rect.GetBottom()<=source.GetHeight()), image, wxT("invalid subimage size") ); - - int subwidth=rect.GetWidth(); - const int subheight=rect.GetHeight(); - - image.Create(subwidth, subheight, false); - - image.SetAlpha(); - unsigned char *subdata = image.GetData(); - unsigned char *data = source.GetData(); - unsigned char *subalpha = image.GetAlpha(); - unsigned char *alpha = source.GetAlpha(); - - wxCHECK_MSG(subdata, image, wxT("unable to create image")); - - const int subleft=3*rect.GetLeft(); - const int width=3*source.GetWidth(); - const int afullwidth=source.GetWidth(); - int awidth = subwidth; - subwidth*=3; - - data+=rect.GetTop()*width+subleft; - alpha+=rect.GetTop()*afullwidth+rect.GetLeft(); - - for (long j = 0; j < subheight; ++j) { - memcpy(subdata, data, subwidth); - memcpy(subalpha, alpha, awidth); - subdata+=subwidth; - subalpha+=awidth; - data+=width; - alpha+=afullwidth; - } - - return image; -} - -#endif - - diff --git a/aegisub/src/subtitle_format_prs.h b/aegisub/src/subtitle_format_prs.h deleted file mode 100644 index 28ac0330e..000000000 --- a/aegisub/src/subtitle_format_prs.h +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) 2006, Rodrigo Braz Monteiro -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of the Aegisub Group nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGE. -// -// Aegisub Project http://www.aegisub.org/ -// -// $Id$ - -/// @file subtitle_format_prs.h -/// @see subtitle_format_prs.cpp -/// @ingroup subtitle_io -/// - - - - -/////////// -// Headers -#if USE_PRS == 1 - -#ifndef AGI_PRE -#include -#endif - -#include "subtitle_format.h" - - -////////////// -// Prototypes -class PRSImage; -class PRSDisplay; -class PRSFile; - - - -/// DOCME -/// @class PRSSubtitleFormat -/// @brief DOCME -/// -/// DOCME -class PRSSubtitleFormat : public SubtitleFormat { -private: - - /// DOCME - PRSDisplay *lastDisplay; - - /// DOCME - int id; - - /// DOCME - int optimizer; - - void InsertFrame(PRSFile &file,int &framen,std::vector &frames,wxImage &bmp,int x,int y,int maxalpha); - wxImage SubImageWithAlpha(wxImage &src,const wxRect &area); - wxImage CalculateAlpha(const unsigned char* frame1, const unsigned char* frame2, int w, int h, int pitch, int *x=NULL, int *y=NULL, int *maxalpha=NULL); - void GetSubPictureRectangles(wxImage &image,std::vector &rects); - std::vector GetFrameRanges(); - void OptimizeImage(wxImage &image); - -public: - wxString GetName(); - wxArrayString GetWriteWildcards(); - - bool CanWriteFile(wxString filename); - void WriteFile(wxString filename,wxString encoding); -}; - -#endif - -