如何才能生成高质量的缩略图呢?(我用StretchBlt生成的缩略图惨不忍睹啊)

shally5 2003-10-15 04:35:25
我用如下方法在ListView中生成缩略图,但惨不忍睹;
有什么其它的高质量生成缩略图的方法吗?
TImageList * SmallBitmap=new TImageList(this);
Graphics::TBitmap * bmpS=new Graphics::TBitmap();
Graphics::TBitmap * bmpD=new Graphics::TBitmap();
TListItem *lvitem;
SmallBitmap->Width=100;
SmallBitmap->Height=100;
SmallBitmap->Clear();
ListView1->Items->Clear();
ListView1->LargeImages=SmallBitmap;
bmpS->LoadFromFile("c:\\111.bmp");
//bmpD->PixelFormat=pf24bit;
bmpD->Width=100;
bmpD->Height=100;
::StretchBlt(bmpD->Canvas->Handle,0,0,100,100,
bmpS->Canvas->Handle,0,0,bmpS->Width,bmpS->Height-0,0xCC0020);
int i=SmallBitmap->Add(bmpD,NULL);
lvitem=ListView1->Items->Add();
lvitem->Caption="111.bmp";
lvitem->ImageIndex=i;
delete bmpS;
delete bmpD;
...全文
255 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
swites 2003-10-20
  • 打赏
  • 举报
回复
ok!
weibz0525 2003-10-20
  • 打赏
  • 举报
回复
用SetStretchBltMode
不过我看效果也不大:(
pp616 2003-10-20
  • 打赏
  • 举报
回复
不支持9x的。使用价值不高。不过可以判断系统。如果是9x的用COLORONCOLOR,nt系统用HALFTONE。这样就完美了。
zyl910 2003-10-18
  • 打赏
  • 举报
回复
用HALFTONE(STRETCH_HALFTONE)最好

SetStretchBltMode(HDC,HALFTONE)




MSDN:HALFTONE Maps pixels from the source rectangle into blocks of pixels in the destination rectangle. The average color over the destination block of pixels approximates the color of the source pixels.
After setting the HALFTONE stretching mode, an application must call the SetBrushOrgEx function to set the brush origin. If it fails to do so, brush misalignment occurs.

This option is not supported on Windows 95/98/Me.


huangjuliang 2003-10-17
  • 打赏
  • 举报
回复
学习!!!
potlee 2003-10-17
  • 打赏
  • 举报
回复
学习!
zzhong2 2003-10-16
  • 打赏
  • 举报
回复
找到啦!
下面就是那位大侠的贴子
void __fastcall TShowPicForm::ZoomFun(float ZTimes)
{
//TODO: 缩放的函数。
//if(strTemp=="")return;
int ImgWidth,ImgHeight;//原来的大小
int Anewiw,Anewih;//新大小
double tmpwscale,tmphscale;//宽高比
int int_ImgPixByte;//每个像素占用的字节

ImgWidth = ShowPicImage->Picture->Bitmap->Width;
ImgHeight = ShowPicImage->Picture->Bitmap->Height;
if(ImgWidth==0||ImgHeight==0)
{
TJPEGImage *temp= new TJPEGImage();
temp->LoadFromFile(strTemp);
ShowPicImage->Picture->Bitmap->Assign(temp);
delete temp;
temp=NULL;
ImgWidth = ShowPicImage->Picture->Bitmap->Width;
ImgHeight = ShowPicImage->Picture->Bitmap->Height;
}
Anewiw=ImgWidth*ZTimes;
Anewih=ImgHeight*ZTimes;

if((ShowPicImage->Picture->Bitmap->PixelFormat != pf24bit) &&
(ShowPicImage->Picture->Bitmap->PixelFormat != pf32bit) )
ShowPicImage->Picture->Bitmap->PixelFormat = pf24bit;
Graphics::TBitmap *newbmp = new Graphics::TBitmap();
try
{
newbmp->Width = Anewiw;
newbmp->Height = Anewih;
newbmp->PixelFormat = ShowPicImage->Picture->Bitmap->PixelFormat;

if(ShowPicImage->Picture->Bitmap->PixelFormat == pf24bit) int_ImgPixByte = 3;
if(ShowPicImage->Picture->Bitmap->PixelFormat == pf32bit) int_ImgPixByte = 4;

tmpwscale = double(ImgWidth)/double(Anewiw);
tmphscale = double(ImgHeight)/double(Anewih);

double tempnewx,tempnewy;
double tempdiffx,tempdiffy;
int tempnewxi,tempnewyi;
double tempf00,tempf10,tempf01,tempf11;
double temprgb;
int tmprgbint;

Byte *OldScanLine,*OldAddScan,*NewScanLine;

int Multi_old;
int Multi_new;

for(int i=0;i<Anewih;i++)
{
tempnewy = double(i)*tmphscale;
if(tempnewy<0.0) tempnewy=0.0;
else if(tempnewy >= ImgHeight) tempnewy = ImgHeight-1;
tempnewyi = floor(tempnewy);
tempdiffy = tempnewy-tempnewyi;

OldScanLine = static_cast<Byte*>(ShowPicImage->Picture->Bitmap->ScanLine[tempnewyi]);
OldAddScan = static_cast<Byte*>(ShowPicImage->Picture->Bitmap->ScanLine[tempnewyi+1]);
NewScanLine = static_cast<Byte*>(newbmp->ScanLine[i]);

for(int j=0;j<Anewiw;j++)
{
Application->ProcessMessages();
tempnewx = double(j)*tmpwscale;
if(tempnewx<0.0) tempnewx=0.0;
else if(tempnewx>=ImgWidth) tempnewx=ImgWidth-1;
tempnewxi = floor(tempnewx);
tempdiffx = tempnewx-tempnewxi;

Multi_old = tempnewxi * int_ImgPixByte;
Multi_new = j * int_ImgPixByte;
//tmpmulti = j * int_ImgPixByte;
for(int k=0;k<3;k++)
{
//双线性插值
Application->ProcessMessages();
tempf00 = OldScanLine[Multi_old+k];
if((tempnewyi<ImgHeight-1)&&(tempnewxi<ImgWidth-1))
{
tempf10 = OldScanLine[Multi_old+k+int_ImgPixByte];
tempf01 = OldAddScan[Multi_old+k];
tempf11 = OldAddScan[Multi_old+k+int_ImgPixByte];
}
else if((tempnewyi==ImgHeight-1)&&(tempnewxi<ImgWidth-1))
{
tempf10 = OldScanLine[Multi_old+k+int_ImgPixByte];
tempf01 = 0.0;
tempf11 = 0.0;
tempdiffy = 0.0;
}
else if((tempnewyi<ImgHeight-1)&&(tempnewxi==ImgWidth-1))
{
tempf10 = 0.0;
tempf01 = OldAddScan[Multi_old+k];
tempf11 = 0.0;
tempdiffx = 0.0;
}
else
{
tempf10=0.0;
tempf01=0.0;
tempf11=0.0;
tempdiffx=0.0;
tempdiffy=0.0;
}
temprgb =(tempf10-tempf00)*tempdiffx
+(tempf01-tempf00)*tempdiffy
+(tempf11+tempf00-tempf01-tempf10)*tempdiffx*tempdiffy
+tempf00;
tmprgbint = floor( temprgb+0.5 );
NewScanLine[Multi_new+k] = tmprgbint;
}
}
}
ShowPicImage->Picture->Bitmap->Width = Anewiw;
ShowPicImage->Picture->Bitmap->Height = Anewih;
ShowPicImage->Picture->Bitmap->Assign(newbmp);
}__finally{
delete newbmp;
}
}
//---------------------------------------------------------------------------

sfemil 2003-10-16
  • 打赏
  • 举报
回复
再调用StretchBlt之前需要调用SetStretchBltMode(HDC,COLORONCOLOR)
这样就可以保证缩放之后的图象质量
zzhong2 2003-10-15
  • 打赏
  • 举报
回复
以前有个贴子,问的就是这个问题,有位大侠给出了实现代码,用的是双线性插值法,我在我参与的问题里已找不到这个贴子了,在我得分的问题里也找不到了,贴子名我也忘了,可惜;CSDN这点真不方便,我得分的问题应多保留些日子
zzhong2 2003-10-15
  • 打赏
  • 举报
回复
有一本参考书《实用微机图象处理》北航出版社 周孝宽 主编;其中有一节叫
数字图象的几何变换,就是讲这个的,你可以到书店去看看相关的图象处理的书,里面大都有几何变换这一章节,里面肯定有算法,要不你就等我周末回家取得资料给你发一分,里面还有图解;全是数学公式

下面简单写几句:(抄书)
图象几何变换的基本原理如图2.44所示(CSDN贴不了图,哎..)
原图象坐标系(u—v)上的数字图象f(u,v)变换为另一个坐标系上的数字图象g(x,y),且满足:
f(u,v)=g(x,y)=f(p(x,y),q(x,y))
u=p(x,y)
v=q(x,y)
其中f(u,v)的值代表原图象的象素灰度值,g(x,y)的值代表目标图象的象素灰度值
p(x,y),q(x,y)分别为x轴坐标变换函数和y轴坐标变换函数
坐标变换:
1恒等变换,2位移变换,3翻转变换,
4缩放变换
u=p(x,y)=x/c
v=q(x,y)=y/d
上式意为f图象在x轴方向上放大c倍,在y轴方向上放大d倍而得到g图象,当c,d小于1时实际是缩小变换。
5旋转变换
在具体作几何变换时,原图象f(u,v)是已知的,变换的目标图象g(x,y)是待定的。为方便计算(x,y)目标坐标取为整数,这样与之对应的点在(u,v)原图上的坐标一般就不是整数了。而非整数的(u,v)坐标,在原图象上其值f(u,v)是没有定义的。为此必须根据原图象上与该(u,v)点相邻的整数坐标象素值,内插计算出该点灰度值f(u,v).如图....所示,为求(u0,v0)点(非整数坐标点)的灰度值f(u0,v0),需用(u',v'),(u'+1,v'),(u',v'+1),(u'+1,v'+1)等四个整数坐标点的灰度值按某种规则来插值计算(u0,v0)点的灰度值f(u0,v0).这就是所谓灰度插值计算。
常用的灰度插值方法有三种:
1最近邻法
2双线性插值法
3三次内插法
误差一个比一个小,计算复杂程度一个比一个大
1最近邻法
将与(u0,v0)点最近的整数坐标(u',v')点的灰度值取为(u0,v0)点的灰度值。在(u0,v0)点各相邻象素间灰度(颜色)变化较小时,这种方法是一种简单快速的方法,但当(u0,v0)点相邻象素灰度差很大时,这种灰度估值方法会产生较大误差。
2双线性插值法
这种方法是对近邻法的一种改进,即用线性内插方法,根据(u0,v0)点的四个邻点的灰度值,插值计算出f(u0,v0)值。具体计算过程如图...所示,即
先根据f(u',v')及f(u'+1,v')插值求f(u0,v'),即
f(u0,v')=(1-a)f(u',v')+a*f(u'+1,v')
再根据f(u',v'+1)及f(u'+1,v'+1)插值求f(u0,v'+1),即
f(u0,v'+1)=(1-a)f(u',v'+1)+a*f(u'+1,v'+1)
最后根据f(u0,v')及f(u0,v'+1)插值求f(u0,v0),即
f(u0,v0)=(1-b)f(u0,v')+b*f(u0,v'+1)
=f(u',v')(1-a)(1-b)+f(u'+1,v')a(1-b)
+f(u',v'+1)(1-a)b+f(u'+1,v'+1)a*b
在实际计算时,若对任一s值,规定[s]表示其值不超过s的最大整数,则上式中
u'=[u0]
v'=[v0]
a=u0-[u0]
b=v0-[v0]
比如:
u0=p(16,2)=16/5
v0=q(16,2)=13/2
f图象在x轴方向上放大5倍,在y轴方向上放大2倍
u0=3.2,v0=6.5
u'=[u0]=3
v'=[v0]=6
a=u0-[u0]=0.2
b=v0-[v0]=0.5
上述计算过程进行了两次线性插值,所以叫双线性插值法。双线性灰度插值计算方法由于已考虑到了(u0,v0)点的直接邻点对它的影响,因此一般能得到令人满意的插值效果,但这种方法具有低通滤波性质,使高频分量受到损失。为要得到更精确的灰度插值效果,可采用三次内插法。
3三次内插法
为要得到更精确的(u0,v0)点的灰度值,就不仅需考虑(u0,v0)点直接邻点对它的影响,而需要考虑到该点周围16个邻点的灰度值对它的影响,如图...所示。三次内插法采用sin(π/x)/(π/x)的三次近似多项式....太多的公式、矩阵

以上公试算出的只是(u0,v0)点的灰度值,彩色图象象素点由RGB红绿蓝三种颜色组成,你必须分别算出每个分色的灰度值(色度值),然后再合成一个新象素,这才是目的坐标(x,y)点的象素值。
我看还是用Canvas的StretchDraw方法吧,这么算太麻烦了
SCUM 2003-10-15
  • 打赏
  • 举报
回复
插值

翻书去吧
shally5 2003-10-15
  • 打赏
  • 举报
回复
可是从资源管理器中,从菜单中选[查看]->[缩略图]后,资源管理器显示的缩略图就很好啊!?那它是如何作的呢?
klbt 2003-10-15
  • 打赏
  • 举报
回复
非常困难,很难找到好的不失真压缩方法。
jiangchun_xn 2003-10-15
  • 打赏
  • 举报
回复
很难,因为细节丢失了,假如保留细节,比例又会失真,比如一条直线,怎么处理。

:(

13,824

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder相关内容讨论区
社区管理员
  • 基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧