Aegisub/vsfilter/patchfiles/gaussian-blur.patch
Niels Martin Hansen 65990cc0eb Update patch files as far as possible. Not everything is properly included.
csriapi.cpp is removed since the version a one dir up is the correct one, this one wasn't maintained.
These patch files were used as base for porting the patches to guliverkli2.

Originally committed to SVN as r2288.
2008-07-25 19:33:55 +00:00

332 lines
11 KiB
Diff

Index: C:/Users/jfs/Dev/Aegisub/vsfilter/subtitles/subtitles.vcproj
===================================================================
--- C:/Users/jfs/Dev/Aegisub/vsfilter/subtitles/subtitles.vcproj (revision 2283)
+++ C:/Users/jfs/Dev/Aegisub/vsfilter/subtitles/subtitles.vcproj (revision 2284)
@@ -241,6 +241,10 @@
>
</File>
<File
+ RelativePath=".\SeparableFilter.h"
+ >
+ </File>
+ <File
RelativePath=".\SSF.h"
>
</File>
Index: C:/Users/jfs/Dev/Aegisub/vsfilter/subtitles/Rasterizer.h
===================================================================
--- C:/Users/jfs/Dev/Aegisub/vsfilter/subtitles/Rasterizer.h (revision 2283)
+++ C:/Users/jfs/Dev/Aegisub/vsfilter/subtitles/Rasterizer.h (revision 2284)
@@ -85,7 +85,7 @@
bool ScanConvert();
bool CreateWidenedRegion(int borderX, int borderY);
void DeleteOutlines();
- bool Rasterize(int xsub, int ysub, int fBlur);
+ bool Rasterize(int xsub, int ysub, int fBlur, double fGaussianBlur);
CRect Draw(SubPicDesc& spd, CRect& clipRect, byte* pAlphaMask, int xsub, int ysub, const long* switchpts, bool fBody, bool fBorder);
};
Index: C:/Users/jfs/Dev/Aegisub/vsfilter/subtitles/RTS.cpp
===================================================================
--- C:/Users/jfs/Dev/Aegisub/vsfilter/subtitles/RTS.cpp (revision 2283)
+++ C:/Users/jfs/Dev/Aegisub/vsfilter/subtitles/RTS.cpp (revision 2284)
@@ -127,11 +127,11 @@
m_fDrawn = true;
- if(!Rasterize(p.x&7, p.y&7, m_style.fBlur)) return;
+ if(!Rasterize(p.x&7, p.y&7, m_style.fBlur, m_style.fGaussianBlur)) return;
}
else if((m_p.x&7) != (p.x&7) || (m_p.y&7) != (p.y&7))
{
- Rasterize(p.x&7, p.y&7, m_style.fBlur);
+ Rasterize(p.x&7, p.y&7, m_style.fBlur, m_style.fGaussianBlur);
}
m_p = p;
@@ -1421,6 +1421,8 @@
params.Add(cmd.Mid(2)), cmd = cmd.Left(2);
else if(!cmd.Find(L"a"))
params.Add(cmd.Mid(1)), cmd = cmd.Left(1);
+ else if(!cmd.Find(L"blur"))
+ params.Add(cmd.Mid(4)), cmd = cmd.Left(4);
else if(!cmd.Find(L"bord"))
params.Add(cmd.Mid(4)), cmd = cmd.Left(4);
else if(!cmd.Find(L"be"))
@@ -1536,6 +1538,13 @@
if(sub->m_scrAlignment < 0)
sub->m_scrAlignment = (n > 0 && n < 12) ? ((((n-1)&3)+1)+((n&4)?6:0)+((n&8)?3:0)) : org.scrAlignment;
}
+ else if(cmd == L"blur")
+ {
+ double n = CalcAnimation(wcstod(p, NULL), style.fGaussianBlur, fAnimate);
+ style.fGaussianBlur = !p.IsEmpty()
+ ? (n < 0 ? 0 : n)
+ : org.fGaussianBlur;
+ }
else if(cmd == L"bord")
{
double dst = wcstod(p, NULL);
Index: C:/Users/jfs/Dev/Aegisub/vsfilter/subtitles/STS.cpp
===================================================================
--- C:/Users/jfs/Dev/Aegisub/vsfilter/subtitles/STS.cpp (revision 2283)
+++ C:/Users/jfs/Dev/Aegisub/vsfilter/subtitles/STS.cpp (revision 2284)
@@ -2907,6 +2907,7 @@
fUnderline = false;
fStrikeOut = false;
fBlur = 0;
+ fGaussianBlur = 0;
fontShiftX = fontShiftY = fontAngleZ = fontAngleX = fontAngleY = 0;
relativeTo = 2;
}
@@ -2929,6 +2930,7 @@
&& alpha[2] == s.alpha[2]
&& alpha[3] == s.alpha[3]
&& fBlur == s.fBlur
+ && fGaussianBlur == s.fGaussianBlur
&& relativeTo == s.relativeTo
&& IsFontStyleEqual(s));
}
@@ -3004,7 +3006,7 @@
s.colors[0], s.colors[1], s.colors[2], s.colors[3], s.alpha[0], s.alpha[1], s.alpha[2], s.alpha[3],
s.charSet,
s.fontName, s.fontSize, s.fontScaleX, s.fontScaleY, s.fontSpacing, s.fontWeight,
- (int)s.fItalic, (int)s.fUnderline, (int)s.fStrikeOut, s.fBlur,
+ (int)s.fItalic, (int)s.fUnderline, (int)s.fStrikeOut, s.fBlur, s.fGaussianBlur,
s.fontAngleZ, s.fontAngleX, s.fontAngleY,
s.relativeTo);
@@ -3027,7 +3029,7 @@
s.fontName = WToT(GetStr(str)); s.fontSize = GetFloat(str);
s.fontScaleX = GetFloat(str); s.fontScaleY = GetFloat(str);
s.fontSpacing = GetFloat(str); s.fontWeight = GetInt(str);
- s.fItalic = !!GetInt(str); s.fUnderline = !!GetInt(str); s.fStrikeOut = !!GetInt(str); s.fBlur = GetInt(str);
+ s.fItalic = !!GetInt(str); s.fUnderline = !!GetInt(str); s.fStrikeOut = !!GetInt(str); s.fBlur = GetInt(str); s.fGaussianBlur = GetFloat(str);
s.fontAngleZ = GetFloat(str); s.fontAngleX = GetFloat(str); s.fontAngleY = GetFloat(str);
s.relativeTo = GetInt(str);
}
Index: C:/Users/jfs/Dev/Aegisub/vsfilter/subtitles/SeparableFilter.h
===================================================================
--- C:/Users/jfs/Dev/Aegisub/vsfilter/subtitles/SeparableFilter.h (revision 0)
+++ C:/Users/jfs/Dev/Aegisub/vsfilter/subtitles/SeparableFilter.h (revision 2284)
@@ -0,0 +1,121 @@
+/*
+ Copyright 2007 Niels Martin Hansen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+ Contact:
+ E-mail: <jiifurusu@gmail.com>
+ IRC: jfs in #aegisub on irc.rizon.net
+
+ */
+
+#pragma once
+
+#ifdef _OPENMP
+#include <omp.h>
+#endif
+#include <math.h>
+
+
+// Filter an image in horizontal direction with a one-dimensional filter
+// PixelWidth is the distance in bytes between pixels
+template<ptrdiff_t PixelDist>
+void SeparableFilterX(unsigned char *src, unsigned char *dst, int width, int height, ptrdiff_t stride, int *kernel, int kernel_size, int divisor)
+{
+#pragma omp parallel for
+ for (int y = 0; y < height; y++) {
+ unsigned char *in = src + y*stride;
+ unsigned char *out = dst + y*stride;
+ for (int x = 0; x < width; x++) {
+ int accum = 0;
+ for (int k = 0; k < kernel_size; k++) {
+ int xofs = k - kernel_size/2;
+ if (x+xofs < 0) xofs += width;
+ if (x+xofs >= width) xofs -= width;
+ accum += (int)(in[xofs*PixelDist] * kernel[k]);
+ }
+ accum /= divisor;
+ if (accum > 255) accum = 255;
+ if (accum < 0) accum = 0;
+ *out = (unsigned char)accum;
+ in+=PixelDist;
+ out+=PixelDist;
+ }
+ }
+}
+
+
+// Filter an image in vertical direction with a one-dimensional filter
+// This one templated with PixelWidth since the channel interlacing is horizontal only,
+// filtering once vertically will automatically catch all channels.
+// (Width must be multiplied by pixel width for that to happen though.)
+template<ptrdiff_t PixelDist>
+void SeparableFilterY(unsigned char *src, unsigned char *dst, int width, int height, ptrdiff_t stride, int *kernel, int kernel_size, int divisor)
+{
+#pragma omp parallel for
+ width *= PixelDist;
+ for (int x = 0; x < width; x+=PixelDist) {
+ unsigned char *in = src + x;
+ unsigned char *out = dst + x;
+ for (int y = 0; y < height; y++) {
+ int accum = 0;
+ for (int k = 0; k < kernel_size; k++) {
+ int yofs = k - kernel_size/2;
+ if (y+yofs < 0) yofs += height;
+ if (y+yofs >= height) yofs -= height;
+ accum += (int)(in[yofs*stride] * kernel[k]);
+ }
+ accum /= divisor;
+ if (accum > 255) accum = 255;
+ if (accum < 0) accum = 0;
+ *out = (unsigned char)accum;
+ in += stride;
+ out += stride;
+ }
+ }
+}
+
+
+static inline double NormalDist(double sigma, double x)
+{
+ if (sigma <= 0 && x == 0) return 1;
+ else if (sigma <= 0) return 0;
+ else return exp(-(x*x)/(2*sigma*sigma)) / (sigma * sqrt(2*3.1415926535));
+}
+
+
+struct GaussianKernel {
+ int *kernel;
+ int width;
+ int divisor;
+ inline GaussianKernel(double sigma)
+ {
+ width = (int)(sigma*3 + 0.5) | 1; // binary-or with 1 to make sure the number is odd
+ if (width < 3) width = 3;
+ kernel = new int[width];
+ kernel[width/2] = (int)(NormalDist(sigma, 0) * 255);
+ divisor = kernel[width/2];
+ for (int x = width/2-1; x >= 0; x--) {
+ int val = (int)(NormalDist(sigma, width/2-x) * 255 + 0.5);
+ divisor += val*2;
+ kernel[x] = val;
+ kernel[width - x - 1] = val;
+ }
+ }
+ inline ~GaussianKernel()
+ {
+ delete[] kernel;
+ }
+};
Index: C:/Users/jfs/Dev/Aegisub/vsfilter/subtitles/STS.h
===================================================================
--- C:/Users/jfs/Dev/Aegisub/vsfilter/subtitles/STS.h (revision 2283)
+++ C:/Users/jfs/Dev/Aegisub/vsfilter/subtitles/STS.h (revision 2284)
@@ -50,6 +50,7 @@
bool fUnderline;
bool fStrikeOut;
int fBlur;
+ double fGaussianBlur;
double fontAngleZ, fontAngleX, fontAngleY;
double fontShiftX, fontShiftY;
int relativeTo; // 0: window, 1: video, 2: undefined (~window)
Index: C:/Users/jfs/Dev/Aegisub/vsfilter/subtitles/Rasterizer.cpp
===================================================================
--- C:/Users/jfs/Dev/Aegisub/vsfilter/subtitles/Rasterizer.cpp (revision 2283)
+++ C:/Users/jfs/Dev/Aegisub/vsfilter/subtitles/Rasterizer.cpp (revision 2284)
@@ -25,6 +25,7 @@
#include <vector>
#include <algorithm>
#include "Rasterizer.h"
+#include "SeparableFilter.h"
Rasterizer::Rasterizer() : mpPathTypes(NULL), mpPathPoints(NULL), mPathPoints(0), mpOverlayBuffer(NULL)
{
@@ -679,7 +680,7 @@
mOutline.clear();
}
-bool Rasterizer::Rasterize(int xsub, int ysub, int fBlur)
+bool Rasterizer::Rasterize(int xsub, int ysub, int fBlur, double fGaussianBlur)
{
_TrashOverlay();
@@ -700,17 +701,25 @@
mWideBorder = (mWideBorder+7)&~7;
- if(!mWideOutline.empty() || fBlur)
+ if(!mWideOutline.empty() || fBlur || fGaussianBlur > 0)
{
+ int bluradjust = 0;
+ if (fGaussianBlur > 0)
+ mWideBorder += (int)(fGaussianBlur*3*8 + 0.5) | 1;
+ if (fBlur)
+ mWideBorder += 8;
+
+ mWideBorder = (mWideBorder+7)&~7;
+
// Expand the buffer a bit when we're blurring, since that can also widen the borders a bit
- width += 2*mWideBorder + (fBlur ? 16 : 0);
- height += 2*mWideBorder + (fBlur ? 16 : 0);
+ width += 2*mWideBorder + bluradjust*2;
+ height += 2*mWideBorder + bluradjust*2;
- xsub += mWideBorder + (fBlur ? 8 : 0);
- ysub += mWideBorder + (fBlur ? 8 : 0);
+ xsub += mWideBorder + bluradjust;
+ ysub += mWideBorder + bluradjust;
- mOffsetX -= mWideBorder + (fBlur ? 8 : 0);
- mOffsetY -= mWideBorder + (fBlur ? 8 : 0);
+ mOffsetX -= mWideBorder + bluradjust;
+ mOffsetY -= mWideBorder + bluradjust;
}
mOverlayWidth = ((width+7)>>3) + 1;
@@ -759,6 +768,28 @@
}
}
+ // Do some gaussian blur magic
+ if (fGaussianBlur > 0)
+ {
+ GaussianKernel filter(fGaussianBlur);
+ if (mOverlayWidth >= filter.width && mOverlayHeight >= filter.width)
+ {
+ int pitch = mOverlayWidth*2;
+
+ byte *tmp = new byte[pitch*mOverlayHeight];
+ if(!tmp) return(false);
+
+ int border = !mWideOutline.empty() ? 1 : 0;
+
+ byte *src = mpOverlayBuffer + border;
+
+ SeparableFilterX<2>(src, tmp, mOverlayWidth, mOverlayHeight, pitch, filter.kernel, filter.width, filter.divisor);
+ SeparableFilterY<2>(tmp, src, mOverlayWidth, mOverlayHeight, pitch, filter.kernel, filter.width, filter.divisor);
+
+ delete[] tmp;
+ }
+ }
+
// If we're blurring, do a 3x3 box blur
// Can't do it on subpictures smaller than 3x3 pixels
for (int pass = 0; pass < fBlur; pass++)
}
// For CPUID usage in Rasterizer::Draw