/* 色情報の省略による画像圧縮 2000/11/ 5 - 2001/ 3/ 4 宍戸 輝光 */ #include LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); BOOL readBMP(LPCTSTR); void loadYUV(LPCTSTR); void saveYUV(void); HINSTANCE hInst; HWND hwMain; LPBYTE lpDIB,lpPixel; LPBITMAPINFO lpbiInfo; DWORD dwWidth,dwHeight,dwLength,dwWV=4,dwHV=4; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){ MSG msg; WNDCLASS wndclass ; hInst=hInstance; /* プロセスのハンドルを保存 */ wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = "CWindow"; RegisterClass(&wndclass); hwMain=CreateWindow("CWindow","YCrCbによる画像圧縮",WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,CW_USEDEFAULT,560,480,NULL,NULL,hInstance,NULL); DragAcceptFiles(hwMain,TRUE); /* ドラッグ&ドロップ受入 */ ShowWindow(hwMain,iCmdShow); /* ウインドウを表示 */ UpdateWindow (hwMain); /* 再描画 */ while (GetMessage (&msg,NULL,0,0)) { /* メッセージループ */ TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam ; } LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { HDROP hDrop; HDC hdc; PAINTSTRUCT ps; TCHAR lpszFn[MAX_PATH+1]; switch (iMsg) { case WM_DROPFILES: /* ファイルがドロップされた時の処理 */ hDrop=(HDROP)wParam; /* HDROPを取得 */ DragQueryFile(hDrop,0,lpszFn,256); /* ファイル名を取得 */ if (lstrcmpi(lpszFn+lstrlen(lpszFn)-4,".bmp")==0) { /* BMP */ if (readBMP(lpszFn)) /* 読みこみ成功ならYCrCb変換・ファイル作成 */ saveYUV(); } else if (lstrcmpi(lpszFn+lstrlen(lpszFn)-4,".yuv")==0) loadYUV(lpszFn); DragFinish(hDrop); /* 終了処理 */ InvalidateRgn(hwnd,NULL,FALSE); UpdateWindow (hwnd); /* 再描画 */ break; case WM_PAINT: hdc=BeginPaint(hwnd,&ps); if (lpDIB!=NULL) /* ビットマップが読み込まれていれば */ StretchDIBits(hdc,4,4,dwWidth,dwHeight, 0,0,dwWidth,dwHeight,lpPixel,lpbiInfo, DIB_RGB_COLORS,SRCCOPY); /* DIBを画面に描画 */ EndPaint(hwnd,&ps); return 0; case WM_DESTROY : if (lpDIB!=NULL) /* DIB用メモリ解放 */ GlobalFree(lpDIB); PostQuitMessage(0); return 0; } return DefWindowProc (hwnd, iMsg, wParam, lParam) ; } BOOL readBMP(LPCTSTR lpszFn) { /* ビットマップ読み込み */ DWORD offset,dummy; HANDLE fh; if (lpDIB!=NULL) /* 以前確保したバッファを解放 */ GlobalFree(lpDIB); fh=CreateFile(lpszFn,GENERIC_READ,0,NULL,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,NULL); /* ファイルオープン */ lpDIB=(LPBYTE)GlobalAlloc (GPTR,GetFileSize(fh,NULL)); /* バッファ確保 */ ReadFile(fh,lpDIB,GetFileSize(fh,NULL),&dummy,NULL); lpbiInfo=(LPBITMAPINFO)(lpDIB+sizeof(BITMAPFILEHEADER)); offset=*(LPDWORD)(lpDIB+10); lpPixel=lpDIB+offset; /* ビットマップバッファの先頭アドレス */ CloseHandle(fh); /* 24ビットフルカラービットマップでなければ無効 */ if (lpDIB[0]!='B' || lpbiInfo->bmiHeader.biBitCount!=24) { GlobalFree(lpDIB); lpDIB=NULL; MessageBox(hwMain,"このファイルは使えません。","エラー",MB_OK); return FALSE; } /* ビットマップの大きさ保存 */ dwWidth=lpbiInfo->bmiHeader.biWidth; dwHeight=lpbiInfo->bmiHeader.biHeight; /* ビットマップの大きさが4の倍数でなければ無効 */ if (dwWidth % 4!=0 || dwHeight %4!=0) { GlobalFree(lpDIB); lpDIB=NULL; MessageBox(hwMain,"ビットマップサイズが不正です。","エラー",MB_OK); return FALSE; } dwLength=dwWidth*3; SetWindowText(hwMain,lpszFn); return TRUE; } void saveYUV(void) { /* YCrCb変換とYUVファイル作成 */ DWORD i,j,k,l,dwSize; double r,g,b,y,u,v; LPBYTE lpWork; HANDLE fh; dwSize=dwWidth*dwHeight+((dwWidth/dwWV)*(dwHeight/dwHV))*2+16; lpWork=GlobalAlloc(GPTR,dwSize); /* ビットマップサイズと色差圧縮レベルを記録 */ *((LPDWORD)lpWork)=dwWidth; *((LPDWORD)lpWork+1)=dwHeight; *((LPDWORD)lpWork+2)=dwWV; *((LPDWORD)lpWork+3)=dwHV; for (i=0;i255) y=255; /* 各ピクセルのyを記録 */ lpWork[(j*dwWV+l)+(i*dwHV+k)*dwWidth+16]=(BYTE)y; u+=0.5*r-0.419*g-0.081*b+128; v+=-0.169*r-0.332*g+0.5*b+128; } /* CrCbを平均化 */ u=u/(dwWV*dwHV); v=v/(dwWV*dwHV); if (u<0) u=0; if (u>255) u=255; if (v<0) v=0; if (v>255) v=255; /* CrCbを記録 */ lpWork[dwWidth*dwHeight+j*2+i*(dwWidth/dwWV)*2+16]=(BYTE)u; lpWork[dwWidth*dwHeight+j*2+i*(dwWidth/dwWV)*2+17]=(BYTE)v; } fh=CreateFile("test.yuv",GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); WriteFile(fh,lpWork,dwSize,&dwSize,NULL); CloseHandle(fh); GlobalFree(lpWork); } void loadYUV(LPCTSTR lpszFn) { DWORD dummy,i,j,k,l; LPBYTE lpWork; double r,g,b,y,u,v; HANDLE fh; fh=CreateFile(lpszFn,GENERIC_READ,0,NULL,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,NULL); /* ファイルオープン */ lpWork=(LPBYTE)GlobalAlloc (GPTR,GetFileSize(fh,NULL)); /* バッファ確保 */ ReadFile(fh,lpWork,GetFileSize(fh,NULL),&dummy,NULL); dwWidth=*((LPDWORD)lpWork); dwHeight=*((LPDWORD)lpWork+1); dwWV=*((LPDWORD)lpWork+2); dwHV=*((LPDWORD)lpWork+3); CloseHandle(fh); dwLength=dwWidth*3; if (lpDIB!=NULL) GlobalFree(lpDIB); lpDIB=GlobalAlloc(GPTR,sizeof(BITMAPINFO)+dwLength*dwHeight); /* メモリイメージ用ポインタ設定 */ lpbiInfo=(LPBITMAPINFO)lpDIB; lpPixel=(LPBYTE)lpDIB+sizeof(BITMAPINFO); /* ビットマップのヘッダ作成 */ lpbiInfo->bmiHeader.biSize=sizeof(BITMAPINFOHEADER); lpbiInfo->bmiHeader.biWidth=dwWidth; lpbiInfo->bmiHeader.biHeight=dwHeight; lpbiInfo->bmiHeader.biPlanes=1; lpbiInfo->bmiHeader.biBitCount=24; for (i=0;i255) r=255; if (g<0) g=0; if (g>255) g=255; if (b<0) b=0; if (b>255) b=255; lpPixel[(j*dwWV+l)*3+(i*dwHV+k)*dwLength]=(BYTE)b; lpPixel[(j*dwWV+l)*3+(i*dwHV+k)*dwLength+1]=(BYTE)g; lpPixel[(j*dwWV+l)*3+(i*dwHV+k)*dwLength+2]=(BYTE)r; } } GlobalFree(lpWork); SetWindowText(hwMain,lpszFn); InvalidateRgn(hwMain,NULL,FALSE); UpdateWindow (hwMain); /* 再描画 */ }