原文:http://blog.chinaunix.net/uid-253932-id-3037805.html

工作需要,要弄截图且缩小。截图倒是好说,WIN API可以搞定,但是缩小且尽量不失真,这个对我来说难度太大了吧。这里主要说说缩小的算法。我从网上找到两个算法分别是bilinear和nearest。但是效果看上去太差了。我先贴上处理后的三种算法效果图,然后再贴算法。

bilinear

nearest

cubic

当然大家可以看的出来,效果最好的自然是Cubic,提供一些该算法的资料,不过我自己是没看懂http://en.wikipedia.org/wiki/Cubic_function。cubic是我们公司多媒体方面的牛人帮我写的。

以下是代码:

#include "stdafx.h"
#include <stdio.h>
#include <string>
#include <windows.h>
#include <math.h>
using namespace std;
enum StretchMode
{
nearest, //最临近插值算法
bilinear, //双线性内插值算法
cubic
};
const int CUBIC_SIZE = 3;
int getSincVec(float *pfVec, float fPos, float fScale)
{
int nPos = (int)fPos;
fPos -= (float)nPos;
memset(pfVec, 0, sizeof(float) * CUBIC_SIZE);
float fSum = 0.f;
for (int i=0; i<CUBIC_SIZE; i++)
{
float fTmp = (i - 1.f + fPos) * 3.14159265358979323846f;
if (fTmp > 0.00001 || fTmp < -0.00001)
{
pfVec[i] = sinf(fTmp * fScale) / fTmp;
}
else
{
pfVec[i] = 1.f;
}
fSum += pfVec[i];
}
fSum = 1.f / fSum;
for (int i=0; i<CUBIC_SIZE; i++)
{
pfVec[i] *= fSum;
}
return nPos;
}
void calcSincMat(float *pfMat, float *pfVecY, float *pfVecX)
{
for (int i=0; i<CUBIC_SIZE; i++)
{
for (int j=0; j<CUBIC_SIZE; j++)
{
pfMat[i * CUBIC_SIZE + j] = pfVecY[i] * pfVecX[j];
}
}
}
void Stretch(const string& srcFile,const string& desFile,int desW,int desH,StretchMode mode)
{
BITMAPFILEHEADER bmfHeader;
BITMAPINFOHEADER bmiHeader;
FILE *pFile;
if ((pFile = fopen(srcFile.c_str(),"rb")) == NULL)
{
printf("open bmp file error.");
exit(-1);
}
//读取文件和Bitmap头信息
fseek(pFile,0,SEEK_SET);
fread(&bmfHeader,sizeof(BITMAPFILEHEADER),1,pFile);
fread(&bmiHeader,sizeof(BITMAPINFOHEADER),1,pFile);
//先不支持小于16位的位图
int bitCount = bmiHeader.biBitCount;
if (bitCount < 16)
{
exit(-1);
}
int srcW = bmiHeader.biWidth;
int srcH = bmiHeader.biHeight;
int lineSize = bitCount * srcW / 8;
//偏移量,windows系统要求每个扫描行按四字节对齐
int alignBytes = ((bmiHeader.biWidth * bitCount + 31) & ~31) / 8L
- bmiHeader.biWidth * bitCount / 8L;
//原图像缓存
int srcBufSize = lineSize * srcH;
BYTE* srcBuf = new BYTE[srcBufSize];
int i,j;
//读取文件中数据
for (i = 0; i < srcH; i++)
{
fread(&srcBuf[lineSize * i],lineSize,1,pFile);
fseek(pFile,alignBytes,SEEK_CUR);
}
//目标图像缓存
int desBufSize = ((desW * bitCount + 31) / 32) * 4 * desH;
int desLineSize = ((desW * bitCount + 31) / 32) * 4;
BYTE *desBuf = new BYTE[desBufSize];
double rateH = (double)srcH / desH;
double rateW = (double)srcW / desW;
//最临近插值算法
if (mode == nearest)
{
for (i = 0; i < desH; i++)
{
//选取最邻近的点
int tSrcH = (int)(rateH * i + 0.5);
for (j = 0; j < desW; j++)
{
int tSrcW = (int)(rateW * j + 0.5);
memcpy(&desBuf[i * desLineSize] + j * bmiHeader.biBitCount / 8,&srcBuf[tSrcH * lineSize] + tSrcW * bmiHeader.biBitCount / 8,bmiHeader.biBitCount / 8);
}
}
}
//双线型内插值算法
else if (mode == bilinear)
{
for (i = 0; i < desH; i++)
{
int tH = (int)(rateH * i);
int tH1 = min(tH + 1,srcH - 1);
float u = (float)(rateH * i - tH);
for (j = 0; j < desW; j++)
{
int tW = (int)(rateW * j);
int tW1 = min(tW + 1,srcW - 1);
float v = (float)(rateW * j - tW);
//f(i+u,j+v) = (1-u)(1-v)f(i,j) + (1-u)vf(i,j+1) + u(1-v)f(i+1,j) + uvf(i+1,j+1)
for (int k = 0; k < 3; k++)
{
desBuf[i * desLineSize + j * bitCount / 8 + k] =
(1 - u)*(1 - v) * srcBuf[tH * lineSize + tW * bitCount / 8 + k] +
(1 - u)*v*srcBuf[tH1 * lineSize + tW * bitCount / 8+ k] +
u * (1 - v) * srcBuf[tH * lineSize + tW1 * bitCount / 8 + k] +
u * v * srcBuf[tH1 * lineSize + tW1 * bitCount / 8 + k];
}
}
}
}
else
{
float pfVecX[CUBIC_SIZE], pfVecY[CUBIC_SIZE], pfMat[CUBIC_SIZE][CUBIC_SIZE];
int nPixelBytes = bitCount / 8;
for (i=1; i<desH-1; i++)
{
int nSrcY = getSincVec(pfVecY, rateH * i, 1.f / rateH);
for (j = 1; j < desW-1; j++)
{
int nSrcX = getSincVec(pfVecX, rateW * j, 1.f / rateW);
calcSincMat(pfMat[0], pfVecY, pfVecX);
BYTE *pbyTmpDes = desBuf + i * desLineSize + j * nPixelBytes;
BYTE *pbyTmpSrc = srcBuf + nSrcY * lineSize + nSrcX * nPixelBytes;
for (int k = 0; k < 3; k++)
{
float fTmp = pbyTmpSrc[0] * pfMat[1][1];
fTmp += pbyTmpSrc[-lineSize] * pfMat[0][1];
fTmp += pbyTmpSrc[lineSize] * pfMat[2][1];
fTmp += pbyTmpSrc[-nPixelBytes] * pfMat[1][0];
fTmp += pbyTmpSrc[-nPixelBytes-lineSize] * pfMat[0][0];
fTmp += pbyTmpSrc[-nPixelBytes+lineSize] * pfMat[2][0];
fTmp += pbyTmpSrc[nPixelBytes] * pfMat[1][2];
fTmp += pbyTmpSrc[nPixelBytes-lineSize] * pfMat[0][2];
fTmp += pbyTmpSrc[nPixelBytes+lineSize] * pfMat[2][2];
if (fTmp < 0.f) fTmp = 0.f;
if (fTmp > 255.f) fTmp = 255.f;
*pbyTmpDes++ = (BYTE)fTmp;
pbyTmpSrc++;
}
}
}
}
//创建目标文件
HFILE hfile = _lcreat(desFile.c_str(),0);
//文件头信息
BITMAPFILEHEADER nbmfHeader;
nbmfHeader.bfType = 0x4D42;
nbmfHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)
+ desW * desH * bitCount / 8;
nbmfHeader.bfReserved1 = 0;
nbmfHeader.bfReserved2 = 0;
nbmfHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
//Bitmap头信息
BITMAPINFOHEADER bmi;
bmi.biSize=sizeof(BITMAPINFOHEADER);
bmi.biWidth=desW;
bmi.biHeight=desH;
bmi.biPlanes=1;
bmi.biBitCount=bitCount;
bmi.biCompression=BI_RGB;
bmi.biSizeImage=0;
bmi.biXPelsPerMeter=0;
bmi.biYPelsPerMeter=0;
bmi.biClrUsed=0;
bmi.biClrImportant=0;
//写入文件头信息
_lwrite(hfile,(LPCSTR)&nbmfHeader,sizeof(BITMAPFILEHEADER));
//写入Bitmap头信息
_lwrite(hfile,(LPCSTR)&bmi,sizeof(BITMAPINFOHEADER));
//写入图像数据
_lwrite(hfile,(LPCSTR)desBuf,desBufSize);
_lclose(hfile);
}
int main(int argc, char* argv[])
{
FILE *pFile;
if ((pFile = fopen("e://t.bmp","rb")) == NULL)
{
printf("open bmp file error.");
return -1;
}
string srcFile("e://t.bmp");
string desFileN("e://nearest.bmp");
string desFileB("e://bilinear.bmp");;
string desFileC("e://cubic.bmp");
//Stretch(srcFile,desFileN,235,136,nearest);
//Stretch(srcFile,desFileB,235,136,bilinear);
Stretch(srcFile,desFileC,235,136,cubic);
//int alignBytes = ~31;
//printf("alignbytes : %d",alignBytes);
return 0;
}

  

BITMAP图片压缩算法三则--bilinear、nearest、cubic的更多相关文章

  1. BMCP位图图片压缩算法

    什么是位图?位图也称像素图像或点阵图像,是由多个点组成的,这些点被称为像素.位图可以模仿照片的真实效果,具有表现力强.细腻.层次多和细节多等优点. 图片的压缩格式:在Windows系统中,我们常见的b ...

  2. C# 大图片压缩算法,减少图片体积

    声明: 图片压缩算法,不建议对小图片进行压缩,一般文件小于1m的,真心没必要压缩, 图片很小的,例如:几百KB的图片,有可能不会减少图片体积,反而压缩后更大,也很正常, 请大家合理使用,并不是,所有图 ...

  3. Android中如何将Bitmap byte裸数据转换成Bitmap图片int数据

    Android中如何将Bitmap byte裸数据转换成Bitmap图片int数据 2014-06-11 10:45:14   阅读375次 我们在JNI中处理得到的BMP图片Raw数据,我们应该如何 ...

  4. Android—将Bitmap图片保存到SD卡目录下或者指定目录

    直接上代码就不废话啦 一:保存到SD卡下 File file = new File(Environment.getExternalStorageDirectory(), System.currentT ...

  5. Bitmap 图片格式并用 C++ 读写 Bitmap

    转自 Bitmap 图片格式并用 C++ 读写 Bitmap 1.Bitmap 图片格式 每部分的具体内容就不展开了.要说的有两点: (1)调色板不是必须的,可有可无,有没有调色板可以通过位图文件头的 ...

  6. BitMap 图片格式与Base64Image格式互转方法

    BitMap 图片格式与Base64Image格式互转方法 /// <summary> /// 图片转为base64编码的字符串 /// </summary> /// < ...

  7. Android开发之常用必备工具类图片bitmap转成字符串string与String字符串转换为bitmap图片格式

    作者:程序员小冰,CSDN博客:http://blog.csdn.net/qq_21376985 QQ986945193 博客园主页:http://www.cnblogs.com/mcxiaobing ...

  8. Android性能优化系列之Bitmap图片优化

    https://blog.csdn.net/u012124438/article/details/66087785 在Android开发过程中,Bitmap往往会给开发者带来一些困扰,因为对Bitma ...

  9. android 通过uri获取bitmap图片并压缩

    很多人在调用图库选择图片时会在onActivityResult中用Media.getBitmap来获取返回的图片,如下: Uri mImageCaptureUri = data.getData(); ...

随机推荐

  1. CCF-CSP 最大的矩形

    问题描述 在横轴上放了n个相邻的矩形,每个矩形的宽度是1,而第i(1 ≤ i ≤ n)个矩形的高度是hi.这n个矩形构成了一个直方图.例如,下图中六个矩形的高度就分别是3, 1, 6, 5, 2, 3 ...

  2. MYSQL 主从复制(NIOT)

    一.主数据库操作设置(A) 1.修改配置文件,vim /etc/my.cnf,然后重启mysqld,/etc/init.d/mysqld restart [mysqld]<要在mysqld中括号 ...

  3. python setup.py install 报错ImportError: No module named setuptools

    学习光荣之路python课程时,使用python setup.py install安装其他模块时,第一次安装某模块成功了.安装另一模块却报错ImportError: No module named s ...

  4. 开机自动挂载 VHD 的方法

    一.批处理 除了将 VHD 文件用人工方式在[磁盘管理]里[附加]来挂载以外,也能用[脚本]来实现自动挂载. 打开[启动],将写好的 mount.bat 放入即可: Mount.bat 文件的内容为: ...

  5. 【第四篇】Volley修改之GsonRequest

    json解析工具类的引入,这里引用lite马天宇的解析json的工具类: public class GsonImpl extends Json { private Gson gson = new Gs ...

  6. 淘淘商城_day08_课堂笔记

    今日大纲 问题,如何实现商品数据的同步? 学习MQ(消息队列) 搭建RabbitMQ的环境 学习RabbitMQ的队列 学习Spring-Rabbit 使用RabbitMQ完成商品数据的同步 如何实现 ...

  7. Struts2第二天

    Struts2第二天 昨天: 1.Action的编写方式:实现Action接口.继承ActionSupport.自定义pojo作为action 2.action调用方法:默认的execute.meth ...

  8. github上一些觉得对自己工作有用的项目收集

    usefullProjectCollect github上一些觉得对自己工作有用的项目收集 技能类 markdown语法中文说明 全文检索 elasticsearch bigdesk elastics ...

  9. 草料生成app自动下载的二维码

    草料官网http://cli.im/app 填写iOS和安卓的appid就好了

  10. 《JS权威指南学习总结--9.2 类和构造函数》

    内容要点: 例9-1展示了在JS中定义类的其中一种方法.但这种方法并不常用,毕竟它没有定义构造函数,构造函数是用来初始化新创建的对象的. 使用关键字new来调用构造函数会自动创建一个新对象,因此构造函 ...