Разбор BMP файл
Я вот хочу обработать BMP файл. Структуру BMP знаю прекрасно, но у меня не получается обрезать BMP по контору, да и сместить как-то надо бы....:)
Спасибо,
с уважением sqwerty!
P.S. Если интересно, то могу показать код по разборку BMP.
{
__int8 bfType[2];
__int32 bfSize;
__int16 bfReserved1;
__int16 bfReserved2;
__int16 bfOffBits;
} BITMAPFILEHEADER;
typedef struct
{
__int32 biSize;
__int32 biWidth;
__int32 biHeight;
__int16 biPlanes;
__int16 biBitCount;
__int32 biCompression;
__int32 biSizeImage;
__int32 biXPelsPerMeter;
__int32 biYPelsPerMeter;
__int32 biClrUsed;
__int32 biClrImportant;
} BITMAPINFOHEADER;
// Собственно обрез по контуру
__int8* crop(__int8* rastr, int height, int width, int nb)
{
int i=0,j=0, k=0;
__int8 tempw=0, temph=0;
int height_board=0,height_board1=0, he=0, wi=0;
height_board=height/2;
int s = height*width*3, ind=0;
unsigned char *ff = new unsigned char
for(j=1200;j<width*3;j++)
{
for(i=0,k=height-1;i<height_board;i++,k--)
{
ff[ind++]=(*(rastr+i*(width*3+nb)+j));
// *(rastr+i*(width*3+nb)+j)=255;
ff[ind++]=(*(rastr+k*(width*3+nb)+j));
//*(rastr+k*(width*3+nb)+j)=255;
}
}
for(j=0;j<width*3-1200;j++)
{
for(i=0,k=height-1;i<height_board;i++,k--)
{
ff[ind++]=(*(rastr+i*(width*3+nb)+j));
// *(rastr+i*(width*3+nb)+j)=0;
ff[ind++]=(*(rastr+k*(width*3+nb)+j));
//*(rastr+k*(width*3+nb)+j)=0;
}
}
for(j=0;j<width*3;j++)
{
for(i=0,k=0;i<height_board, k<50;i++,k++)
{
tempw=(*(rastr+i*(width*3+nb)+j));
*(rastr+i*(width*3+nb)+j)=0;
temph=(*(rastr+k*(width*3+nb)+j));
*(rastr+k*(width*3+nb)+j)=0;
}
for(i=height-1,k=height-1; i>height_board;i--,k--)
{
if(k>200){
tempw=(*(rastr+i*(width*3+nb)+j));
*(rastr+i*(width*3+nb)+j)=0;
temph=(*(rastr+k*(width*3+nb)+j));
*(rastr+k*(width*3+nb)+j)=0;
}
else{
tempw=(*(rastr+i*(width*3+nb)+j));
*(rastr+i*(width*3+nb)+j)=tempw;
temph=(*(rastr+k*(width*3+nb)+j));
*(rastr+k*(width*3+nb)+j)=temph;
}
}
}
return rastr;
}
Чтобы вырезать часть изображения, можно использовать Method Clone.
Полезная ссылка: http://rsdn.ru/summary/626.xml
или же необходимо менять и структуру BMP вместе с остальными..?, т.е. не структуру, а смещение я имею ввиду...
вот как определяю растр:
__int8* rastr=NULL;
rastr=(__int8*)malloc(ihead.biSizeImage);
//Чтение растра
fread(rastr,ihead.biSizeImage,1,bmp_src);
rastr = crop(rastr,ihead.biHeight,ihead.biWidth,nb);
да, я смотрю с помощью rawviewer что получилось на выходе. на вход подаю YV12.
я тупо переписываю заголовок в новый файл, а вообще-то я дважды записываю матрицу в файл, сначала заголовок и сама матрица, патом растр записываю...
может в этом и всё дело...?
Вот в этом ваша проблема. Почитайте внимательно спецификацию BMP-формата. В BMP-файле первые два байта - это "BM", после этого идет размер файла в байтах. После этого 4 байта нули. Потом - размер описания формата в байтах, потом само описание, а потом растр. Скорее всего, эта последовательность у вас где-то нарушается.
1. данные растра выровняны DWORD в строке не зависимо от формата, те это совсем не значит что в DWORD именно одна точка,тем более что это большая редкость.
2. как вы проверили что там нет RLE...
3. и как можно структуры просто копировать...
Так как сегодня Рождество, вот вам мой подарок, преобразование любого файла в ВМР с альфа каналом (DWORD - один пиксел):
//**
//**
//**
//*************************************************************
void TFrame::LoadAlphaImage(void)
{
//****
HANDLE token;
GdiplusStartupInput in;
GdiplusStartupOutput out;
BITMAP bitmap;
BITMAPINFO bitmapinfo;
GpImage * pImage = NULL;
GpGraphics * pGraphics;
GpStatus status = Ok;
CHAR value[MAX_TEXT_SIZE];
HDC hdc;
HDC memdc;
//
GdiplusStartup((ULONG_PTR *)&token,&in,&out);
// вообщем можно загрузить любой файлец, не только ВМР
XString::SystemToUnicode("alpha.png",(LPWORD)value);
status = GdipLoadImageFromFile((WCHAR *)value,&pImage);
if( status == Ok )
{
//
GdipGetImageWidth(pImage,(UINT *)&ImageWidth);
GdipGetImageHeight(pImage,(UINT *)&ImageHeight);
// создаем эталонный контекст
hdc = CreateDC("DISPLAY",NULL,NULL,NULL);
// создаем временный контекст для исходного изображения
memdc = CreateCompatibleDC(hdc);
// создаем совместимое изображение
memset((void *)&bitmapinfo,0,sizeof(BITMAPINFO));
bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmapinfo.bmiHeader.biWidth = ImageWidth;
bitmapinfo.bmiHeader.biHeight = ImageHeight;
bitmapinfo.bmiHeader.biPlanes = 1;
bitmapinfo.bmiHeader.biBitCount = 32;
bitmapinfo.bmiHeader.biCompression = BI_RGB;
bitmapinfo.bmiHeader.biSizeImage = bitmapinfo.bmiHeader.biWidth * (bitmapinfo.bmiHeader.biBitCount / 8) * bitmapinfo.bmiHeader.biHeight;
hWindowImage = CreateDIBSection(memdc,&bitmapinfo,DIB_RGB_COLORS,NULL,NULL,0);
// выбираем изображение в контекст
SelectObject(memdc,hWindowImage);
//
GdipCreateFromHDC(memdc,&pGraphics);
GdipDrawImageRect(pGraphics,pImage,0,0,(REAL)ImageWidth,(REAL)ImageHeight);
//
GdipDisposeImage(pImage);
GdipDeleteGraphics(pGraphics);
// удаляем временные контексты
DeleteDC(hdc);
DeleteDC(memdc);
}
//
GdiplusShutdown((ULONG_PTR)token);
//****
XMemory * pFile;
HICOLOR_RGB * pData;
BITMAPFILEHEADER * pFileHeader;
BITMAPINFOHEADER * pInfoHeader;
int width;
int height;
//
pFile = new XMemory();
if( pFile->Initialize() )
{
//
if( pFile->SetSize(sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)) )
{
//
GetImageBits(hWindowImage,&pData,&width,(int *)&height);
pFile->AppendData((LPBYTE)pData,width*height*sizeof(HICOLOR_RGB));
FreeImageBits(pData);
//
pFileHeader = (BITMAPFILEHEADER *)pFile->GetPointer();
pInfoHeader = (BITMAPINFOHEADER *)pFile->GetPointer(sizeof(BITMAPFILEHEADER));
//
pFileHeader->bfType = 0x4D42;
pFileHeader->bfSize = pFile->GetSize();
pFileHeader->bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
//
pInfoHeader->biSize = sizeof(BITMAPINFOHEADER);
pInfoHeader->biWidth = width;
pInfoHeader->biHeight = height;
pInfoHeader->biPlanes = 1;
pInfoHeader->biBitCount = 32;
pInfoHeader->biCompression = BI_RGB;
pInfoHeader->biSizeImage = pFile->GetSize() - sizeof(BITMAPFILEHEADER) - sizeof(BITMAPINFOHEADER);
pInfoHeader->biXPelsPerMeter = 72;
pInfoHeader->biYPelsPerMeter = 72;
//
pFile->Save("alpha.bmp");
}
//
pFile->Release();
}
//
delete pFile;
}
//*************************************************************
typedef struct _HICOLOR_RGB
{
union
{
// цельный цвет
DWORD Color;
// составляющие
struct
{
BYTE B;
BYTE G;
BYTE R;
BYTE Alpha;
} Layer;
};
} HICOLOR_RGB, *PHICOLOR_RGB, *LPHICOLOR_RGB;
//*************************************************************
//**
//** Получить блок данных изображения
//**
//*************************************************************
BOOL XGraphics::GetImageBits(HBITMAP hImage, LPHICOLOR_RGB * pImageBits, int * pWidth, int * pHeight)
{
//****
HDC hdc;
HDC sdc;
BITMAP bitmap;
BITMAPINFO bitmapinfo;
BOOL alloc = FALSE;
// создаем эталонный контекст
hdc = CreateDC("DISPLAY",NULL,NULL,NULL);
// создаем временный контекст для исходного изображения
sdc = CreateCompatibleDC(hdc);
// определяем размеры исходного изображения
GetObject(hImage,sizeof(BITMAP),&bitmap);
// определяем структуру для получения данных изображения
bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmapinfo.bmiHeader.biWidth = bitmap.bmWidth;
bitmapinfo.bmiHeader.biHeight = bitmap.bmHeight;
bitmapinfo.bmiHeader.biPlanes = 1;
bitmapinfo.bmiHeader.biBitCount = 32;
bitmapinfo.bmiHeader.biCompression = BI_RGB;
bitmapinfo.bmiHeader.biSizeImage = bitmap.bmWidth * sizeof(HICOLOR_RGB) * bitmap.bmHeight;
bitmapinfo.bmiHeader.biXPelsPerMeter = 0;
bitmapinfo.bmiHeader.biYPelsPerMeter = 0;
bitmapinfo.bmiHeader.biClrUsed = 0;
bitmapinfo.bmiHeader.biClrImportant = 0;
// если блок данных отсутствует
if( *(pImageBits) == NULL )
{
// выделяем память для данных
*(pImageBits) = (LPHICOLOR_RGB)GlobalAlloc(GPTR,bitmapinfo.bmiHeader.biSizeImage);
// выставляем признак выделения блока данных
alloc = TRUE;
}
// если блок данных существует
if( *(pImageBits) )
{
// получаем данные
if( GetDIBits(sdc,hImage,0,bitmap.bmHeight,(LPVOID)*(pImageBits),&bitmapinfo,DIB_RGB_COLORS) )
{
// удаляем временные контексты
DeleteDC(hdc);
DeleteDC(sdc);
// возвращаем размер изображения
*(pWidth) = bitmap.bmWidth;
*(pHeight) = bitmap.bmHeight;
return TRUE;
}
// если память под данные выделяли
if( alloc )
{
// освобождаем память
GlobalFree(*(pImageBits));
*(pImageBits) = NULL;
}
}
// удаляем временные контексты
DeleteDC(hdc);
DeleteDC(sdc);
return FALSE;
}
//*************************************************************
//**
//** Получить изображение на основании его данных
//**
//*************************************************************
BOOL XGraphics::SetImageBits(LPHICOLOR_RGB pImageBits, int width, int height, HBITMAP * pImage)
{
//****
HDC hdc;
HDC sdc;
BITMAPINFO bitmapinfo;
HBITMAP hImage;
// создаем эталонный контекст
hdc = CreateDC("DISPLAY",NULL,NULL,NULL);
// создаем временный контекст для исходного изображения
sdc = CreateCompatibleDC(hdc);
// создаем совместимое изображение
hImage = CreateCompatibleBitmap(hdc,width,height);
// определяем структуру для создания изображения
bitmapinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmapinfo.bmiHeader.biWidth = width;
bitmapinfo.bmiHeader.biHeight = height;
bitmapinfo.bmiHeader.biPlanes = 1;
bitmapinfo.bmiHeader.biBitCount = 32;
bitmapinfo.bmiHeader.biCompression = BI_RGB;
bitmapinfo.bmiHeader.biSizeImage = width * sizeof(HICOLOR_RGB) * height;
bitmapinfo.bmiHeader.biXPelsPerMeter = 0;
bitmapinfo.bmiHeader.biYPelsPerMeter = 0;
bitmapinfo.bmiHeader.biClrUsed = 0;
bitmapinfo.bmiHeader.biClrImportant = 0;
// создаем изображение
if( SetDIBits(sdc,hImage,0,height,(LPVOID)pImageBits,&bitmapinfo,DIB_RGB_COLORS) )
{
// если изображение существует - удаляем его
if( *(pImage) ) DeleteObject((HBITMAP)*(pImage));
// возвращаем изображение
*(pImage) = hImage;
// удаляем временные контексты
DeleteDC(hdc);
DeleteDC(sdc);
// возвращаем изображение
return TRUE;
}
// удаляем временные контексты
DeleteDC(hdc);
DeleteDC(sdc);
// удаляем изображение
DeleteObject((HBITMAP)hImage);
return FALSE;
}
//*************************************************************
//**
//** Освободить данные изображения
//**
//*************************************************************
BOOL XGraphics::FreeImageBits(LPHICOLOR_RGB pImageBits)
{
// освобождаем память
if( GlobalFree(pImageBits) ) return FALSE;
return TRUE;
}
Вообщем остальное (типа XMemory) приводить смысла нет, так как вам важен принцип, а он тут изложен полностью...
Вам важен блок pData (растр в DWORD с которым можно работать) и заполнение полей заголовка перед сохранением...
PS кстати не забудьте, что строки растра идут снизу вверх...
Делается это вот так, сначала создаем окно с:
hWindow = CreateWindowEx(WS_EX_LAYERED,"TTestFrameClass",NULL,WS_POPUP,(GetSystemMetrics(SM_CXSCREEN)-ImageWidth)/2,(GetSystemMetrics(SM_CYSCREEN)-ImageHeight)/2,ImageWidth,ImageHeight,hParent,NULL,hApplicationInstance,NULL);
потом формируется вид окна в виде растра с требуемыми параметрами, делается SetImageBits и далее следующее:
//**
//** Полная перерисовка окна
//**
//*************************************************************
void TFrame::RepaintWindow(void)
{
//****
HDC hdc;
HDC memdc;
RECT window;
BLENDFUNCTION Blend;
POINT Offset;
POINT WindowOffset;
SIZE WindowSize;
// открываем контекст перерисовки
hdc = GetDC(hWindow);
// создаем копию совместимого контекста
memdc = CreateCompatibleDC(hdc);
// выбираем полученное изображение в качестве текущего для установки
SelectObject(memdc,(HBITMAP)hWindowImage);
// готовим данные для установки
Blend.BlendOp = AC_SRC_OVER;
Blend.SourceConstantAlpha = 255;
Blend.AlphaFormat = AC_SRC_ALPHA;
Blend.BlendFlags = 0;
//
Offset.x = 0;
Offset.y = 0;
//
GetWindowRect(hWindow,&window);
WindowOffset.x = window.left;
WindowOffset.y = window.top;
//
WindowSize.cx = ImageWidth;
WindowSize.cy = ImageHeight;
// устанавливаем рабочее изображение
UpdateLayeredWindow(hWindow,hdc,&WindowOffset,&WindowSize,memdc,&Offset,0,&Blend,ULW_ALPHA);
// удаляем совместимый контекст
DeleteDC(memdc);
// закрываем контекст перерисовки
ReleaseDC(hWindow,hdc);
}
Тем более в обоих случаях применения таскать в ресурсах PNG не удобно, а вот ВМР очень даже...
PS Кстати в таких окнах нет обработки WM_PAINT, по этому необходимо сначала рисовать ВМР в памяти а потом его устанавливать в качесте вида окна...
PPS Вообщем всех с Рождеством...
1. Прочитать и записать BMP в новый файл это понятно, но главная задача не в этом, а в том, что надо с начало матрицу (не заголовок) загрузить в буфер (в виде растра или как-то по другому), затем обрезать эту матрицу по контуру (при этом меняется размер файла, ширина, высота и горизонтальное/вертикальное разрешение, пиксел/м, оставшиеся мусор и пр.).
2. Обрезанную матрицу прикрепить к заголовку BMP и записать в новый файл.
Я пробовал тупо взять высоту и ширину, и сократить на нужный размер и переписать размер изображения (не файла). Получилось как-то искаженно, но я думаю это из-за горизонтальное/вертикальное разрешение, пиксел/м, т.к. они остались прежними и я не знаю как рассчитывать???
P.S. я работаю без API, так та будет более понятливее и чище код
Мне не надо ее повторять, так как то что вам надо и так уже описали далее, только сами ничего не поняли
2. Обрезанную матрицу прикрепить к заголовку BMP и записать в новый файл.
Я пробовал тупо взять высоту и ширину, и сократить на нужный размер и переписать размер изображения (не файла). Получилось как-то искаженно, но я думаю это из-за горизонтальное/вертикальное разрешение, пиксел/м, т.к. они остались прежними и я не знаю как рассчитывать???
Попробуйте не "тупо"... Предварительно ознакомившись с теорией - Роджерс Д. Алгоритмические основы машинной графики, 1989 год. Особенно то что касается спрайтовой анимации и найдите хорошую книгу по форматам графических файлов.
код должен быть правильным а не "чистым"...
{
FILE *bmp_src,*bmp_dest; //{ для чтения картинки }
int res; //{ код ошибки открытия файла }
BITMAPFILEHEADER fhead,fhead_dest;
BITMAPINFOHEADER ihead,ihead_dest; //{ информация о картинке }
nsigned char* rastr=NULL;
__int8* turned_rastr=NULL;
//{ байт, прочитанный из файла }
short int b=0;
int nb=0; //{ кол-во байт (кратное четырем) соответствующее строке }
long i, j;
bmp_src= fopen(f_src, "rb");
bmp_dest= fopen(f_dest, "wb");
//Чтение заголовков
fread(&fhead.bfType, 2, 1, bmp_src);[/HTML]
fread(&fhead.bfSize, 4, 1, bmp_src);
fread(&fhead.bfReserved1, 2, 1, bmp_src);
fread(&fhead.bfReserved2, 2, 1, bmp_src);
fread(&fhead.bfOffBits, 4, 1, bmp_src);
fread(&ihead, sizeof(ihead), 1, bmp_src);
if (ihead.biBitCount != 24)
return(-2); //Если картинка не 24-битная
fhead_dest=fhead;
ihead_dest=ihead;
int nWidth ;
int nHeight ;
nWidth = ihead_dest.biWidth;
nHeight = ihead_dest.biHeight;
nWidth = QWIDTHBYTES(nWidth,8);
int bmpsize = nWidth*nHeight;
unsigned char * lpbit = new unsigned char[bmpsize];
float fProportion = (float)85/100.f;// здесь пока что в ручную управляю размерность
int tempw=nWidth, temph=nHeight;
unsigned char * temp = new unsigned char[bmpsize];
fseek(bmp_src, fhead.bfOffBits, SEEK_SET); //смещаемся к растру
fread(lpbit,sizeof(bmpsize), 1, bmp_src);
memcpy(temp,lpbit,tempw*temph);
delete [] lpbit;
lpbit=NULL;
nWidth = (int)((float)nWidth*fProportion+0.5);
nWidth = QWIDTHBYTES(nWidth,8);
nHeight = (int)((float)nHeight*fProportion+0.5);
if ((ihead.biWidth*3)%4 !=0 )
nb=4-(ihead.biWidth*3)%4;
lpbit = new unsigned char[nWidth*nHeight];
// в цикле происходить сам процесс преобразования матрицы (в данном случае уменьшения на заданную fProportion)
for (int i=0;i<nHeight;i++)
for(int j=0;j<nWidth;j++)
{
int h,w;
w = (int)((float)j/fProportion+0.5);
h = (int)((float)i/fProportion+0.5);
DWORD k = i*nWidth+j;
DWORD l = h*tempw+w;
if(h>=temph || w>=tempw)
*(lpbit+k)=0;
else
*(lpbit+k)=*(temp+l);
}
delete [] temp;
ihead_dest.biHeight=nHeight;
ihead_dest.biWidth=nWidth;
ihead_dest.biSizeImage=ihead_dest.biHeight*ihead_dest.biWidth*3+(4-(ihead_dest.biWidth*3)%4)*ihead_dest.biHeight;
fhead_dest.bfSize = (ihead_dest.biHeight*ihead_dest.biWidth*3+fhead.bfOffBits+(4-(ihead_dest.biWidth*3)%4)*ihead_dest.biHeight);
//Формирование заголовка выходного файла
fwrite(&fhead_dest.bfType, 2, 1, bmp_dest);
fwrite(&fhead_dest.bfSize, 4, 1, bmp_dest);
fwrite(&fhead_dest.bfReserved1, 2, 1, bmp_dest);
fwrite(&fhead_dest.bfReserved2, 2, 1, bmp_dest);
fwrite(&fhead_dest.bfOffBits, 4, 1, bmp_dest);
fwrite(&ihead_dest, sizeof(ihead), 1, bmp_dest);
rastr=(unsigned char*)malloc(ihead.biSizeImage);
fseek(bmp_src, fhead.bfOffBits, SEEK_SET); //смещаемся к растру
fseek(bmp_dest, fhead_dest.bfOffBits, SEEK_SET); //смещаемся к растру
//Чтение растра
fread(rastr,ihead.biSizeImage,1,bmp_src);
//Преобразование растра
//Запись растра
fwrite(rastr,ihead_dest.biSizeImage,1,bmp_dest);
free(rastr);
fclose(bmp_src);
fclose(bmp_dest);
return (-4);
}
На выходе изображения искажается, я пока не знаю как это исправить....и прошу помочь в этом. Спасибо.
и выходная изображения
Я уже прочел эту книгу
Что мешает прочитать BMP в память (двумерный массив) любой доступной библиотекой, обработать как надо и обратно в BMP сохранить?
Твою никак не отформатированную портянку ни один нормальный человек смотреть не будет.
давайте так - что значит обрезать по контуру и для чего это вам нужно. Как только объясните, я вам напишу "чистый" код чсла так 11... в качестве учебного пособия...
PS Я прочел кодец. там проще потратить пару часов на написание нового чем пару дней объяснять что к чему...
PS Я прочел кодец. там проще потратить пару часов на написание нового чем пару дней объяснять что к чему...
Хорошо.
В общем, мне надо взять изображению YV12. Изменить размер (увеличить/уменьшить), обрезать, сместить и добавить шум. А потом попробовать восстановить исходную изображению.
И чтобы разница между исходной и выходной была минимальная. Это один из способов для выполнения одной задачи.
изображение в этом формате прикрепите к сообщению, так как оно имеет отличную от ВМР растра (http://en.wikipedia.org/wiki/YV12#Y.27UV420p_.28and_Y.27V12.29) структуру - Сначала w*h картинка яркости, потом w/2 * h/2 картинка U, потом w/2 * h/2 картинка V. + надо делать преобразование в RGB...
PS я так и не увидел описания цели (что надо делать после понятно), но для чего - нет...
Цель, пока точно не ясно. Ну как, ясно, но боюсь рассказать, вдруг если не получиться задуманное, то это будет не к чему... А Вам зачем знать цель?
У меня пока сделано обрезания, resize (почти)....
Учтите - это как обещал учебный вариант, его можно еще оптимизировать и оптимизировать. При этом шум простой, а сдвижка делается очень легко используя существующие методы.
Особое внимание обратите на переменные в параметрах преобразований, так как проверок на их корректноть нет, но если они корректны, то работает с любыми размерами. Именно по этому применил "несколько отличные" функции для работы с файлами и памятью, но вы можете их легко заменить на привычные вам...
typedef struct _HICOLOR
{
union
{
// цельный цвет
DWORD Color;
// составляющие
struct
{
BYTE B;
BYTE G;
BYTE R;
BYTE Alpha;
} Layer;
};
} HICOLOR, *PHICOLOR, *LPHICOLOR;
//*************************************************************
//*
//* Старт программы
//*
//*************************************************************
int main(int Count, char ** pArguments)
{
//****
HANDLE hFile;
BITMAPFILEHEADER FileHeader;
BITMAPINFOHEADER InfoHeader;
LPBYTE pFileData;
LPHICOLOR pImageData;
DWORD Size;
DWORD LineSize;
DWORD FileOffset;
DWORD ImageOffset;
DWORD x;
DWORD y;
// открываем файл
hFile = CreateFile(*(pArguments+1),GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);
// читаем заголовок файла
ReadFile(hFile,(LPVOID)&FileHeader,sizeof(BITMAPFILEHEADER),&Size,NULL);
// читаем заголовок изображения
ReadFile(hFile,(LPVOID)&InfoHeader,sizeof(BITMAPINFOHEADER),&Size,NULL);
// если это изображение R8G8B8
if( InfoHeader.biBitCount == 24 )
{
// выделяем память под данные файла изображения
pFileData = (LPBYTE)GlobalAlloc(GPTR,InfoHeader.biSizeImage);
// читаем данные файла изображения
SetFilePointer(hFile,FileHeader.bfOffBits,NULL,FILE_BEGIN);
ReadFile(hFile,(LPVOID)pFileData,InfoHeader.biSizeImage,&Size,NULL);
// закрываем файл
CloseHandle(hFile);
// вычисляем размер линии по горизонтали, так как она должна быть выравнена на DWORD
// это нужно для дальнейших преобразований
LineSize = InfoHeader.biSizeImage / InfoHeader.biHeight;
// выделяем память под рабочие данные изображения
pImageData = (LPHICOLOR)GlobalAlloc(GPTR,InfoHeader.biWidth*InfoHeader.biHeight*sizeof(HICOLOR));
// формируем рабочее изображение
for( y=0; y<InfoHeader.biHeight; y++ )
{
for( x=0; x<InfoHeader.biWidth; x++ )
{
// расчитываем смещения
FileOffset = y * LineSize + x * 3;
ImageOffset = y * InfoHeader.biWidth + x;
// формируем рабочие данные
(pImageData+ImageOffset)->Layer.Alpha = 0xFF;
(pImageData+ImageOffset)->Layer.B = *(pFileData+FileOffset);
(pImageData+ImageOffset)->Layer.G = *(pFileData+FileOffset+1);
(pImageData+ImageOffset)->Layer.R = *(pFileData+FileOffset+2);
}
}
// освобождаем ранее выделенную память под данные файла изображения
GlobalFree(pFileData);
// Изменяем размер
Resize(&pImageData,(LPDWORD)&InfoHeader.biWidth,(LPDWORD)&InfoHeader.biHeight,InfoHeader.biWidth/2,InfoHeader.biHeight/2);
// Обрезаем
Cut(&pImageData,(LPDWORD)&InfoHeader.biWidth,(LPDWORD)&InfoHeader.biHeight,InfoHeader.biWidth/4,InfoHeader.biHeight/4,InfoHeader.biWidth*3/4,InfoHeader.biHeight*3/4);
// Добавляем шум
AppendNoise(pImageData,InfoHeader.biWidth,InfoHeader.biHeight);
// вычисляем размер линии по горизонтали, так как она должна быть выравнена на DWORD
// это нужно для дальнейших преобразований
for( LineSize=InfoHeader.biWidth*3; (LineSize & 0x00000003); LineSize++ );
// заполняем описание нового изображения
InfoHeader.biSizeImage = LineSize * InfoHeader.biHeight;
FileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + InfoHeader.biSizeImage;
// выделяем память под данные файла изображения
pFileData = (LPBYTE)GlobalAlloc(GPTR,InfoHeader.biSizeImage);
// формируем готовое изображение
for( y=0; y<InfoHeader.biHeight; y++ )
{
for( x=0; x<InfoHeader.biWidth; x++ )
{
// расчитываем смещения
FileOffset = y * LineSize + x * 3;
ImageOffset = y * InfoHeader.biWidth + x;
// формируем рабочие данные
*(pFileData+FileOffset) = (pImageData+ImageOffset)->Layer.B;
*(pFileData+FileOffset+1) = (pImageData+ImageOffset)->Layer.G;
*(pFileData+FileOffset+2) = (pImageData+ImageOffset)->Layer.R;
}
}
// освобождаем ранее выделенную память под рабочие данные изображения
GlobalFree(pImageData);
// создаем файл
hFile = CreateFile(*(pArguments+2),GENERIC_WRITE,FILE_SHARE_WRITE,NULL,CREATE_ALWAYS,0,NULL);
// записываем заголовок файла
WriteFile(hFile,(LPVOID)&FileHeader,sizeof(BITMAPFILEHEADER),&Size,NULL);
// записываем заголовок изображения
WriteFile(hFile,(LPVOID)&InfoHeader,sizeof(BITMAPINFOHEADER),&Size,NULL);
// записываем само изображение
WriteFile(hFile,(LPVOID)pFileData,InfoHeader.biSizeImage,&Size,NULL);
// закрываем файл
CloseHandle(hFile);
// освобождаем ранее выделенную память под данные файла изображения
GlobalFree(pFileData);
}
// закрываем файл
else CloseHandle(hFile);
return 0;
}
//*
//* Обрезать
//*
//*************************************************************
void Cut(LPHICOLOR * pImageData, LPDWORD pWidth, LPDWORD pHeight, DWORD left, DWORD top, DWORD right, DWORD bottom)
{
//****
LPHICOLOR pNewImageData;
DWORD ImageOffset;
DWORD NewImageOffset;
DWORD x;
DWORD y;
DWORD width;
DWORD height;
// расчитываем новый размер
width = right - left + 1;
height = bottom - top + 1;
// выделяем память под результирующие рабочие данные изображения
pNewImageData = (LPHICOLOR)GlobalAlloc(GPTR,width*height*sizeof(HICOLOR));
// формируем обрезанное рабочее изображение
for( y=0; y<height; y++ )
{
for( x=0; x<width; x++ )
{
// расчитываем смещения
ImageOffset = (y + top) * (*(pWidth)) + x + left;
NewImageOffset = y * width + x;
// формируем рабочие данные
(pNewImageData+NewImageOffset)->Color = (*(pImageData)+ImageOffset)->Color;
}
}
// освобождаем ранее выделенную память под рабочие данные изображения
GlobalFree(*(pImageData));
// и передаем новую
*(pImageData) = pNewImageData;
// возвращаем новые размеры
*(pWidth) = width;
*(pHeight) = height;
}
//*************************************************************
//*
//* Изменить размер
//*
//*************************************************************
void Resize(LPHICOLOR * pImageData, LPDWORD pWidth, LPDWORD pHeight, DWORD NewWidth, DWORD NewHeight)
{
//****
LPHICOLOR pNewImageData;
DWORD ImageOffset;
DWORD NewImageOffset;
DWORD X;
DWORD Y;
DWORD NewX;
DWORD NewY;
DWORD CountX;
DWORD CountY;
// выделяем память под результирующие рабочие данные изображения
pNewImageData = (LPHICOLOR)GlobalAlloc(GPTR,NewWidth*NewHeight*sizeof(HICOLOR));
// формируем рабочее изображение с новыми размерами
// Основа этих "хитрых" преобразований корнями уходит в целочисленные методы формирования
// графических примитивов по Брезенхему, с которыми вы должны быть знакомы, так как прочитали указанную мною книгу...
for( Y=NewY=0,CountY=0; NewY<NewHeight; NewY++,CountY+=*(pHeight) )
{
while( CountY >= NewHeight )
{
CountY -= NewHeight;
Y++;
}
for( X=NewX=0,CountX=0; NewX<NewWidth; NewX++,CountX+=*(pWidth) )
{
while( CountX >= NewWidth )
{
CountX -= NewWidth;
X++;
}
// расчитываем смещения
ImageOffset = Y * (*(pWidth)) + X;
NewImageOffset = NewY * NewWidth + NewX;
// формируем рабочие данные
(pNewImageData+NewImageOffset)->Color = (*(pImageData)+ImageOffset)->Color;
}
}
// освобождаем ранее выделенную память под рабочие данные изображения
GlobalFree(*(pImageData));
// и передаем новую
*(pImageData) = pNewImageData;
// возвращаем новые размеры
*(pWidth) = NewWidth;
*(pHeight) = NewHeight;
}
//*************************************************************
//*
//* Добавить шум
//*
//*************************************************************
void AppendNoise(LPHICOLOR pImageData, DWORD width, DWORD height)
{
//****
DWORD ImageOffset;
DWORD x;
DWORD y;
SYSTEMTIME time;
DWORD Count;
DWORD Random;
BYTE gray;
// инициализируем датчик случайных чисел на основании текущего времени
GetLocalTime(&time);
Random = time.wMilliseconds * time.wSecond * time.wMinute * time.wHour;
// формиуруем шум
for( Count=0; Count<10000; Count++ )
{
// генерируем положение
Random = Random * 214013 + 2531011;
x = Random % width;
Random = Random * 214013 + 2531011;
y = Random % height;
// генерируем "цвет" шума - реализация может быть разной
gray = (BYTE)(Random % 255);
// расчитываем смещение
ImageOffset = y * width + x;
// формируем рабочие данные
(pImageData+ImageOffset)->Layer.B = (pImageData+ImageOffset)->Layer.B * gray / 255;
(pImageData+ImageOffset)->Layer.G = (pImageData+ImageOffset)->Layer.G * gray / 255;
(pImageData+ImageOffset)->Layer.R = (pImageData+ImageOffset)->Layer.R * gray / 255;
}
}
Могу еще задавать вопросы или обратиться снова, если вдруг возникнут трудности?
Еще раз спасибо...