跪求:24位BMP转256色后图片扭曲(付程序)
问题:当用的24位色图片的宽度是偶数时不扭曲,当宽度是奇数时会扭曲,找了好久都找不问题。
求达人帮忙。
#ifndef __BMPTEST_H_
#define __BMPTEST_H_
#include <stdio.h>
typedef unsigned char BYTE;
typedef unsigned short WORD;
// BMP图像各部分说明如下
typedef struct
{
long imageSize;
long blank;
long startPosition;
void show(void)
{
printf("BMP Head:\n");
printf("Image Size:%d\n",imageSize);
printf("Image Data Start Position : %d\n",startPosition);
}
}BmpHead;
typedef struct
{
long Length;
long width;
long height;
WORD colorPlane;
WORD bitColor;
long zipFormat;
long realSize;
long xPels;
long yPels;
long colorUse;
long colorImportant;
void show(void)
{
printf("infoHead Length:%d\n",Length);
printf("width&height:%d*%d\n",width,height);
printf("colorPlane:%d\n",colorPlane);
printf("bitColor:%d\n",bitColor);
printf("Compression Format:%d\n",zipFormat);
printf("Image Real Size:%d\n",realSize);
printf("Pels(X,Y):(%d,%d)\n",xPels,yPels);
printf("colorUse:%d\n",colorUse);
printf("Important Color:%d\n",colorImportant);
}
}InfoHead;
typedef struct
{
BYTE rgbBlue;
BYTE rgbGreen;
BYTE rgbRed;
BYTE rgbReserved;
void show(void)
{
printf("Mix Plate B,G,R:%d %d %d\n",rgbBlue,rgbGreen,rgbRed);
}
}RGBMixPlate;
#endif
/************************
* change bmp to .....
* by shanlimin 2005-9-25
* bmpTransfer.cpp
* compile:
* g++ bmpTransfer.cpp
************************/
#include "bmp.h"
#include <string.h>
#include <assert.h>
#include <stdlib.h>
char asciichar[256]={
'.','.','.','.','.','.',
'.','.','.','.','.','.','.','.','.','.',
',',',',',',',',',',',',',',',',',',',',
':',':',':',':',':',':',':',':',':',':',
';',';',';',';',';',';',';',';',';',';',
'=','=','=','=','=','=','=','=','=','=',
'+','+','+','+','+','+','+','+','+','+',
'i','i','i','i','i','i','i','i','i','i',
't','t','t','t','t','t','t','t','t','t',
'r','r','r','r','r','r','r','r','r','r',
'%','%','%','%','%','%','%','%','%','%',
's','s','s','s','s','s','s','s','s','s',
'*','*','*','*','*','*','*','*','*','*',
'h','h','h','h','h','h','h','h','h','h',
'#','#','#','#','#','#','#','#','#','#',
'&','&','&','&','&','&','&','&','&','&',
'$','$','$','$','$','$','$','$','$','$',
'@','@','@','@','@','@','@','@','@','@',
'V','V','V','V','V','V','V','V','V','V',
'Z','Z','Z','Z','Z','Z','Z','Z','Z','Z',
'X','X','X','X','X','X','X','X','X','X',
'E','E','E','E','E','E','E','E','E','E',
'R','R','R','R','R','R','R','R','R','R',
'B','B','B','B','B','B','B','B','B','B',
'W','W','W','W','W','W','W','W','W','W',
'M','M','M','M','M','M','M','M','M','M'
};
int zoom;
BmpHead headBMP;
InfoHead infoHead;
BYTE* pColorData; //用于24bit
RGBMixPlate mainColor[256];//调色板
BYTE* Index = NULL;//用于256
int nPad;
void read_24bit_bmp_file(char *filename);
void save_256_bmp_file(char *filename);
void trans_24bit_to_256();
int Transfer(WORD *color24bit, int len, BYTE *Index, RGBMixPlate *mainColor);
//计算平方差的函数
int PFC(int color1, int color2)
{
int x,y,z;
x = (color1 & 0xf) - (color2 & 0xf);
y = ((color1>>4) & 0xf) - ((color2>>4) & 0xf);
z = ((color1>>8) & 0xf) - ((color2>>8) & 0xf);
return (x*x + y*y + z*z);
};
//直接插入排序
int Sort1(int *src, int *attach, int n)
{
int cur, cur1;
int i,j,k=0;
for (i = 1; i < n; i++)
{
cur = src[i];
cur1 = attach[i];
for (j = i - 1; j >= 0; j--)
{
if (cur > src[j])
{
src[j+1] = src[j];
attach[j+1] = attach[j];
}
else
break;
}
src[j+1] = cur;
attach[j+1] = cur1;
}
return 0;
}
//快速排序
int Sort2(int *src, int *attach, int n)
{
if (n <= 12)
return Sort1(src, attach, n);
int low = 1, high = n - 1;
int tmp;
while (low <= high)
{
while (src[low] >= src[0])
{
if (++low > n - 1)
break;
}
while (src[high] < src[0])
{
if (--high < 1)
break;
}
if (low > high)
break;
{
tmp = src[low];
src[low] = src[high];
src[high] = tmp;
tmp = attach[low];
attach[low] = attach[high];
attach[high] = tmp;
}
low++;
high--;
}
{
tmp = src[low - 1];
src[low - 1] = src[0];
src[0] = tmp;
tmp = attach[low - 1];
attach[low - 1] = attach[0];
attach[0] = tmp;
}
if (low > 1)
Sort2(src, attach, low - 1);
if (low < n)
Sort2(&src[low], &attach[low], n - low);
return 0;
}
int main()//int argc,char* argv[])
{
int argc = 4;
char *argv[5] = {"0", "-2", "2.bmp", "256.bmp", ""};
zoom=1;//用于缩小转换后的ASCII图,zoom越大图越小
if (argc < 4)
{
printf("Usage:\n");
printf(" %s format filename1 filename2\n", argv[0]);
printf(" format : choose change mode like: -2 -g -a\n");
printf(" -2 to 256 -g to gray -a to ascii\n");
printf(" filename1 : source 24bit BMP filename like: xxx.bmp\n");
printf(" filename2 : new 256 color BMP filename\n");
return -1;
}
if(argc==5)
zoom=atoi(argv[4]);
char* filename = argv[2]; //"image.bmp";//
char* newFile = argv[3]; //"256.bmp";//
if(strcmp(argv[1],"-2")==0)
{
read_24bit_bmp_file(filename);
trans_24bit_to_256();
save_256_bmp_file(newFile); //写新文件
delete []Index; //释放分配的内存
}
delete []pColorData;
return 0;
}
void save_256_bmp_file(char *filename)
{
/************ 写一个新的256色BMP文件 *******************/
FILE *p1 = fopen(filename,"wb");
if (NULL == p1)
{
printf("open new file failed.\n");
return ;
}
char hh[2] = {0x42, 0x4D};
fwrite(hh,1,2,p1); //BMP文件开头两字节, 0x4d42 = "BM"
fwrite(&headBMP, 1, 12, p1); //BMP文件头
//infoHead.xPels = 96L;
//infoHead.yPels = 96L;
fwrite(&infoHead, 1, 40, p1); //BMP文件头信息
fwrite(mainColor, 1, sizeof(mainColor), p1);//写调色盘信息
int w = infoHead.width;
int h = infoHead.height;
if (nPad != 0) // 调整图像长度不是4的倍数的情况
{// 补上填充的0
char szBuf[4] = {0, 0, 0, 0};
for (int i = 0; i < h; i++)
{
fwrite(Index + i * w, 1, w, p1);
fwrite(szBuf, 1, nPad, p1);
}
}
else
{
fwrite(Index, 1, w*h, p1);
}
fclose(p1);
}
问题点数:40、回复次数:17Top
1 楼hszr(随风)回复于 2006-07-22 15:48:38 得分 0
续上面的程序:
void trans_24bit_to_256()
{
long nData = headBMP.imageSize-headBMP.startPosition;//infoHead.realSize;
/************ 24bit到256色的颜色数据转换 *****************/
nPad = infoHead.width % 4;
int w = infoHead.width;
int h = infoHead.height;
if (nPad != 0) //去掉数据区中填充的0
{
nPad = 4 - nPad;
BYTE* pNewData = new BYTE[w * h * 3];
for (int i = 0; i < h; i++)
{
memcpy(pNewData + i * w * 3, pColorData + i * (w * 3 + nPad), w * 3);
}
delete []pColorData;
pColorData = pNewData;
}
long nNewData = w * h;
Index = new BYTE[nNewData];
memset(mainColor, 0, sizeof(mainColor)); //调色板
WORD* shortColor = new WORD[nNewData];
int iRed, iGreen, iBlue;
for (int i = 0; i < nNewData; i++) //取RGB颜色的高4位
{
iRed = pColorData[i*3]>>4;
iGreen = pColorData[i*3+1]>>4;
iBlue = pColorData[i*3+2]>>4;
shortColor[i] = (iRed<<8) + (iGreen<<4) + iBlue;
}
//调用转换函数
Transfer(shortColor, nNewData, Index, mainColor);
//256色位图的调色盘数据(保存在mainColor)和图像数据区的数据(保存在Index中)
delete []shortColor;
//修改一下前面读出的BmpHead和InfoHead的结构信息
headBMP.imageSize = 14 + 40 + 4*256 + nData/3; //1189;//
// 4*256是调色盘的长度,nData/3是图像数据区长度
headBMP.startPosition += 4*256; //新文件加上了调色盘部分
infoHead.bitColor = 8; //颜色位数改为8
infoHead.realSize = nData/3; //1189;// //图像数据区长度
}
void read_24bit_bmp_file(char *filename)
{
FILE* p;
p = fopen(filename,"rb");
if (p == NULL)
{
printf("!!!file %s open failed.\n", filename);
}
printf("file %s open success.\n",filename);
/********** read BMP head ********************/
fseek(p,2,SEEK_CUR);
fread(&headBMP,1,12,p);
headBMP.show();
fread(&infoHead,1,40,p);
infoHead.show();
if (infoHead.bitColor != 24)
{
fclose(p);
printf("This is not a 24bit BMP file.\n");
return;
}
long nData = headBMP.imageSize-headBMP.startPosition;//infoHead.realSize;
/*********** read Image Date **************/
pColorData = new BYTE[nData];
fread(pColorData,1,nData,p);
/*********** read file over ***************/
int leftData = 0;
char ch = 0;
while (!feof(p))
{
fread(&ch,1,1,p);
leftData++;
}
if (leftData)
printf("%d bytes not read in file.\n", leftData);
printf("read file over.\n");
if(!fclose(p))
{
printf("file close.\n");
}
// 24位BMP文件信息都读出来了,可以查看打印信息
}
//将24bit的象素颜色数据转换为256色图的图像数据(即索引值)
int Transfer(WORD *color24bit, int len, BYTE *Index, RGBMixPlate *mainColor)
{
int usedTimes[4096] = {0};
int miniColor[4096];
int i;
for (i = 0; i < 4096; i++)
miniColor[i] = i;
i = 0;
for (i = 0; i < len; i++)
{
assert(color24bit[i] < 4096);
usedTimes[color24bit[i]]++;
}
int numberOfColors = 0;
for (i = 0; i < 4096; i++)
{
if (usedTimes[i] > 0)
numberOfColors++;
}
//对usedTimes进行排序,排序过程中minColor数组(保存了颜色值)也作与useTimes
//数组相似的交换
Sort2(usedTimes, miniColor, 4096);
//usedTimes数组中是各颜色使用频率,从高到低排列,显然第numberOfColor个之后的都为0
//miniColor数组中是相应的颜色数据</font>
//将前256个颜色数据保存到256色位图的调色盘中
for(i = 0; i < 256; i++)
{
mainColor[i].rgbBlue = (BYTE)((miniColor[i]>>8)<<4);
mainColor[i].rgbGreen = (BYTE)(((miniColor[i]>>4) & 0xf)<<4);
mainColor[i].rgbRed = (BYTE)((miniColor[i] & 0xf)<<4);
mainColor[i].rgbReserved = 0;
}
int *colorIndex = usedTimes;//用原来的useTimes数组来保存索引值
memset(colorIndex, 0, sizeof(int) * 4096);
if (numberOfColors <= 256)
{
for (i = 0; i < numberOfColors; i++)
colorIndex[miniColor[i]] = i;
}
else//为第256之后的颜色在前256种颜色中找一个最接近的
{
for (i = 0; i < 256; i++)
colorIndex[miniColor[i]] = i;
int index, tmp, tmp1;
for (i = 256; i < numberOfColors; i++)
{
tmp = PFC(miniColor[0], miniColor[i]);
index = 0;
for (int j = 1; j < 256; j++)
{
tmp1 = PFC(miniColor[j], miniColor[i]);
if (tmp > tmp1)
{
tmp = tmp1;
index = j;
}
}
colorIndex[miniColor[i]] = index;
}
}
//记录各点颜色数据的索引值,即256色位图的颜色数据
for (i = 0; i < len; i++)
{
assert(colorIndex[color24bit[i]] < 256);
Index[i] = colorIndex[color24bit[i]];
}
return 1;
}
各位可以把上面的程序复制到机器上运行Top
2 楼hszr(随风)回复于 2006-07-22 15:51:29 得分 0
我找了好几天了,都没发现问题。
各位达人帮帮我Top
3 楼jixingzhong(瞌睡虫·星辰)回复于 2006-07-22 17:26:58 得分 20
用的24位色图片的宽度是偶数时不扭曲,当宽度是奇数时会扭曲
=============================
从这里看,
楼主在处理的时候,
在边界上存在问题,
可能是 处理或者是 写新文件的时候,
对于 奇数宽度 图像,
边界点被忽略了一个,
或者是其他原因,造成了扭曲 ...
楼主主要检查一下你的 转换部分、 新文件生成部分,
代码不少,
看起来有点麻烦啊 ...Top
4 楼vosine()回复于 2006-07-22 18:47:57 得分 0
lz, bmp有个对齐的问题!
不对奇的要补齐的!Top
5 楼hszr(随风)回复于 2006-07-22 20:42:30 得分 0
我知道读去BMP宽度要是4的倍数,也在程序里做了处理。
不对奇的要补齐的!===》 就是补上是4的倍数嘛Top
6 楼ccwcc()回复于 2006-07-23 10:43:11 得分 0
很可能是Zoom的时候出了问题。
建议把各个功能抽取出来,单独测试。Top
7 楼hszr(随风)回复于 2006-07-23 13:31:05 得分 0
怎么就没有建设性的建议了???Top
8 楼martmy(白金汉公爵)回复于 2006-07-23 17:35:08 得分 0
你看是不是字节对齐的问题。分配空间时四字节对其Top
9 楼martmy(白金汉公爵)回复于 2006-07-23 17:37:19 得分 0
((pic_width + 31) >> 3) & ~3Top
10 楼hszr(随风)回复于 2006-07-23 19:52:45 得分 0
martmy(白金汉公爵)
((pic_width + 31) >> 3) & ~3 =======> 这是图片的大小
字节对齐了
Top
11 楼hmily0917(卖造钱机)回复于 2006-07-23 22:19:51 得分 0
http://www.pris.edu.cn/imgprocess/theory/subject.htm
楼主 我不太清楚 但是知道一个网站 你看有没有!?Top
12 楼hmily0917(卖造钱机)回复于 2006-07-23 22:21:59 得分 20
我们定义了一个宏#define WIDTHBYTES(i) ((i+31)/32*4),上面曾经提到过,每一行的字节数必须是4的整倍数,只要调用WIDTHBYTES(bi.biWidth*bi.biBitCount)就能完成这一换算.举一个例子,对于2色图,如果图象宽是31,则每一行需要31位存储,合3个字节加7位,因为字节数必须是4的整倍数,所以应该是4,而此时的biWidth=31,biBitCount=1,WIDTHBYTES(31*1)=4,和我们设想的一样。再举一个256色的例子,如果图象宽是31,则每一行需要31个字节存储,因为字节数必须是4的整倍数,所以应该是32,而此时的biWidth=31,biBitCount=8,WIDTHBYTES(31*8)=32,和我们设想的一样。你可以多举几个例子来验证一下Top
13 楼hszr(随风)回复于 2006-07-24 11:42:28 得分 0
各位大虾先看了我的代码再发言吧,上面说的我的都做了,
就是TMD不知道在哪里出错了Top
14 楼hhyytt(鹦鹉螺)回复于 2006-07-24 16:27:52 得分 0
我改好了,楼主。Top
15 楼hszr(随风)回复于 2006-07-24 16:38:17 得分 0
真的,是哪里出的问题?
Top
16 楼hszr(随风)回复于 2006-07-24 16:41:56 得分 0
能把你的程序发我吗?
邮箱: hszr99@126.com
MSN: hszr@hotmail.com
QQ: 420649191
谢谢Top
17 楼hszr(随风)回复于 2006-07-24 18:32:01 得分 0
求人不如求己,还是自己解决了Top




