📄 tspuimage.cpp
字号:
/*
* Copyright (c) 2005,2006 Milan Cutka
*
* 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 St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "stdafx.h"
#include "TspuImage.h"
#include "simd.h"
#include "TffPict.h"
#include "Tlibmplayer.h"
#include "Tconfig.h"
#include "IffdshowBase.h"
//=================================================== TspuImage ===================================================
TspuImage::TspuImage(const TspuPlane src[3],const CRect &rcclip,const CRect &rectReal,const CRect &rectOrig,const TrenderedSubtitleLines::TprintPrefs &prefs):TrenderedSubtitleWordBase(false)
{
if (rectReal.Width()<0) return;
Tscaler *scaler=NULL;
int scale=prefs.dvd?0x100:prefs.vobscale;
for (int i=0;i<3;i++)
{
rect[i]=CRect(roundRshift(rectReal.left,prefs.shiftX[i]),roundRshift(rectReal.top,prefs.shiftY[i]),roundRshift(rectReal.right,prefs.shiftX[i]),roundRshift(rectReal.bottom,prefs.shiftY[i]));
int dstdx=roundDiv(scale*(rectOrig.Width() ?roundDiv(prefs.dx*rect[i].Width() ,(unsigned int)rectOrig.Width() ):rect[i].Width() ),0x100U);
int dstdy=roundDiv(scale*(rectOrig.Height()?roundDiv(prefs.dy*rect[i].Height(),(unsigned int)rectOrig.Height()):rect[i].Height()),0x100U);
plane[i].alloc(CSize(dstdx,dstdy),1);
if (!scaler || scaler->srcdx!=rect[i].Width() || scaler->srcdy!=rect[i].Height())
{
if (scaler) delete scaler;
scaler=Tscaler::create(prefs,rect[i].Width(),rect[i].Height(),dstdx,dstdy);
}
scaler->scale(src[i].c+rect[i].top*src[i].stride+rect[i].left,src[i].r+rect[i].top*src[i].stride+rect[i].left,src[i].stride,plane[i].c,plane[i].r,plane[i].stride);
rect[i]+=CPoint(roundRshift(rcclip.left,prefs.shiftX[i]),roundRshift(rcclip.top,prefs.shiftY[i]));
rect[i].left=roundDiv(int(prefs.dx*rect[i].left),rectOrig.Width());rect[i].right=rect[i].left+dstdx;
rect[i].top=roundDiv(int(prefs.dy*rect[i].top),rectOrig.Height());rect[i].bottom=rect[i].top+dstdy;
dx[i]=rect[i].Width();dy[i]=rect[i].Height();
bmp[i]=plane[i].c;msk[i]=plane[i].r;
bmpmskstride[i]=plane[i].stride;
}
dxCharY=dx[0];dyCharY=dy[0];
if (scaler) delete scaler;
}
//=============================================== TspuImage::Tscaler ==============================================
TspuImage::Tscaler* TspuImage::Tscaler::create(const TrenderedSubtitleLines::TprintPrefs &prefs,int srcdx,int srcdy,int dstdx,int dstdy)
{
switch (prefs.dvd?0:prefs.vobaamode)
{
case 1:return new TscalerApprox(prefs,srcdx,srcdy,dstdx,dstdy);
case 2:return new TscalerFull(prefs,srcdx,srcdy,dstdx,dstdy);
case 3:return new TscalerBilin(prefs,srcdx,srcdy,dstdx,dstdy);
case 4:return new TscalerSw(prefs,srcdx,srcdy,dstdx,dstdy);
default:
case 0:return new TscalerPoint(prefs,srcdx,srcdy,dstdx,dstdy);
}
}
//============================================ TspuImage::TscalerPoint ============================================
TspuImage::TscalerPoint::TscalerPoint(const TrenderedSubtitleLines::TprintPrefs &prefs,int srcdx,int srcdy,int dstdx,int dstdy):Tscaler(srcdx,srcdy,dstdx,dstdy)
{
}
void TspuImage::TscalerPoint::scale(const unsigned char *srci,const unsigned char *srca,stride_t srcStride,unsigned char *dsti,unsigned char *dsta,stride_t dstStride)
{
if (srcdx==dstdx && srcdy==dstdy)
{
TffPict::copy(dsti,dstStride,srci,srcStride,srcdx,srcdy);
TffPict::copy(dsta,dstStride,srca,srcStride,srcdx,srcdy);
}
else
{
int scalex=0x100*dstdx/srcdx;
int scaley=0x100*dstdy/srcdy;
for (int y=0;y<dstdy;y++)
{
int unscaled_y=y*0x100/scaley;
stride_t strides=srcStride*unscaled_y;
stride_t scaled_strides=dstStride*y;
for (int x=0;x<dstdx;x++)
{
int unscaled_x=x*0x100/scalex;
dsti[scaled_strides+x]=srci[strides+unscaled_x];
dsta[scaled_strides+x]=srca[strides+unscaled_x];
}
}
}
}
//============================================ TspuImage::TscalerApprox ===========================================
TspuImage::TscalerApprox::TscalerApprox(const TrenderedSubtitleLines::TprintPrefs &prefs,int srcdx,int srcdy,int dstdx,int dstdy):Tscaler(srcdx,srcdy,dstdx,dstdy)
{
scalex=0x100*dstdx/srcdx;
scaley=0x100*dstdy/srcdy;
}
void TspuImage::TscalerApprox::scale(const unsigned char *srci,const unsigned char *srca,stride_t srcStride,unsigned char *dsti,unsigned char *dsta,stride_t dstStride)
{
unsigned int height=srcdy;
for (int y=0;y<dstdy;y++,dsti+=dstStride,dsta+=dstStride)
{
const unsigned int unscaled_top=y*0x100/scaley;
unsigned int unscaled_bottom=(y+1)*0x100/scaley;
if (unscaled_bottom>=height)
unscaled_bottom=height-1;
unsigned char *dstiLn=dsti,*dstaLn=dsta;
for (int x=0;x<dstdx;x++,dstiLn++,dstaLn++)
{
const unsigned int unscaled_left=x*0x100/scalex;
unsigned int unscaled_right=(x+1)*0x100/scalex;
unsigned int width=srcdx;
if (unscaled_right>=width)
unscaled_right=width-1;
unsigned int alpha=0,color=0;
int cnt=0;
for (unsigned int walky=unscaled_top;walky<=unscaled_bottom;walky++)
for (unsigned int walkx=unscaled_left;walkx<=unscaled_right;walkx++)
{
cnt++;
stride_t base=walky*srcStride+walkx;
unsigned int tmp=srca[base];
alpha+=tmp;
color+=tmp*srci[base];
}
*dstiLn=(unsigned char)(alpha?color/alpha:0);
*dstaLn=(unsigned char)(cnt?alpha/cnt:0);
}
}
}
//============================================ TspuImage::TscalerFull =============================================
TspuImage::TscalerFull::TscalerFull(const TrenderedSubtitleLines::TprintPrefs &prefs,int srcdx,int srcdy,int dstdx,int dstdy):Tscaler(srcdx,srcdy,dstdx,dstdy)
{
}
void TspuImage::TscalerFull::scale(const unsigned char *srci,const unsigned char *srca,stride_t srcStride,unsigned char *dsti,unsigned char *dsta,stride_t dstStride)
{
const double scalex=(double)0x100*dstdx/srcdx;
const double scaley=(double)0x100*dstdy/srcdy;
/* Best antialiasing. Very slow. */
/* Any pixel (x, y) represents pixels from the original
rectangular region comprised between the columns
unscaled_y and unscaled_y + 0x100 / scaley and the rows
unscaled_x and unscaled_x + 0x100 / scalex
The original rectangular region that the scaled pixel
represents is cut in 9 rectangular areas like this:
+---+-----------------+---+
| 1 | 2 | 3 |
+---+-----------------+---+
| | | |
| 4 | 5 | 6 |
| | | |
+---+-----------------+---+
| 7 | 8 | 9 |
+---+-----------------+---+
The width of the left column is at most one pixel and
it is never null and its right column is at a pixel
boundary. The height of the top row is at most one
pixel it is never null and its bottom row is at a
pixel boundary. The width and height of region 5 are
integral values. The width of the right column is
what remains and is less than one pixel. The height
of the bottom row is what remains and is less than
one pixel.
The row above 1, 2, 3 is unscaled_y. The row between
1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4,
5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom.
The row beneath 7, 8, 9 is unscaled_y_bottom.
The column left of 1, 4, 7 is unscaled_x. The column
between 1, 4, 7 and 2, 5, 8 is left_right_column. The
column between 2, 5, 8 and 3, 6, 9 is (unsigned
int)unscaled_x_right. The column right of 3, 6, 9 is
unscaled_x_right. */
const double inv_scalex = (double) 0x100 / scalex;
const double inv_scaley = (double) 0x100 / scaley;
for (int y = 0; y < dstdy; ++y,dsti+=dstStride,dsta+=dstStride)
{
const double unscaled_y = y * inv_scaley;
const double unscaled_y_bottom = unscaled_y + inv_scaley;
const unsigned int top_low_row = (unsigned int)std::min(unscaled_y_bottom, unscaled_y + 1.0);
const double top = top_low_row - unscaled_y;
const unsigned int height = unscaled_y_bottom > top_low_row
? (unsigned int) unscaled_y_bottom - top_low_row
: 0;
const double bottom = unscaled_y_bottom > top_low_row
? unscaled_y_bottom - floor(unscaled_y_bottom)
: 0.0;
unsigned char *dstiLn=dsti,*dstaLn=dsta;
for (int x = 0; x < dstdx; ++x,dstiLn++,dstaLn++)
{
const double unscaled_x = x * inv_scalex;
const double unscaled_x_right = unscaled_x + inv_scalex;
const unsigned int left_right_column = (unsigned int)std::min(unscaled_x_right, unscaled_x + 1.0);
const double left = left_right_column - unscaled_x;
const unsigned int width = unscaled_x_right > left_right_column
? (unsigned int) unscaled_x_right - left_right_column
: 0;
const double right = unscaled_x_right > left_right_column
? unscaled_x_right - floor(unscaled_x_right)
: 0.0;
double color = 0.0;
double alpha = 0.0;
double tmp;
stride_t base;
/* Now use these informations to compute a good alpha,
and lightness. The sum is on each of the 9
region's surface and alpha and lightness.
transformed alpha = sum(surface * alpha) / sum(surface)
transformed color = sum(surface * alpha * color) / sum(surface * alpha)
*/
/* 1: top left part */
base = srcStride * (unsigned int) unscaled_y;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -