// ■C言語で画像処理(メニューで選択できるようにして機能追加をやりやすく) #include "myWin2.h" #include "stdio.h" #include "math.h" #include #define swap(type, X,Y) do{type T; T=X;X=Y; Y=T;}while(0) #define LB_1 1001 #define LB_2 1002 #define LB_3 1003 #define XST 310 #define YST 80 #define REGION 1 #define DESTINATION 2 #define RED(X) (X & 0xFF) #define GREEN(X) ((X>> 8) & 0xFF) #define BLUE(X) ((X>>16) & 0xFF) typedef struct{ COLORREF LineColor; int LineWidth; COLORREF PaintColor; int DrawMode; } DrawAttribute; DrawAttribute drawAttribute={0x00, 1, 0xFFFFFF, R2_COPYPEN}; //ファイル入出力用 static HBITMAP hBitmap=NULL;static HDC hMain=NULL, hdc; static BITMAP bitmap; static TCHAR str[255];static HANDLE hF; static OPENFILENAME CC;static BYTE dtBuff[16]; static TCHAR strFile[1024],strFileTitle[128];//TCHAR msg[4200]; static TCHAR sFilter[]= TEXT("BMP Files\0*.bmp\0") TEXT("Jpeg Files\0*.jpg\0GIF Files\0*.gif\0") TEXT("All Files\0*.*\0"); static TCHAR sFilter2[]= TEXT("BMP Files\0*.bmp\0"); //メニュー用 static HMENU hm,hmFile,hmColorNum,hmFilter, hmColor,hmEdit; static MENUITEMINFO mi; enum file_ID{ F_OPEN=5000, F_SAVE, F_EXIT}; enum display_ID{ D_GRAY=5010, D_HEXA}; enum filter_ID { F_EAGE=5020, F_SHADE, F_AVER, F_MEDI, F_GAMMA, F_MOSA, F_DIST}; enum color_ID { C_CONT=5030, C_RGB, C_RGB2}; enum edit_ID { E_UNDO=5040, E_STORE, E_COPY, E_ATTR, E_LINE, E_RECT, E_ELLP}; //トーンカーブ計算用 static int X, Y, IMS=0; ;static int XDT[5], YDT[5]; //トーンカーブダイアログ用変数 static HDC hBuff2; static HBITMAP hBM2; static HWND hwParent;//親ウィンドウハンドル //親ウィンドウ用 static HDC hBuff[3]; //ビットマップ描画用 static HBITMAP hBM[3];//ビットマップ描画用 static BITMAP bM[3];//ビットマップ描画用 static HCURSOR hc; int Xstart=310, DX=-1; int filter[3][3]={{1,1,1},{1,1,1},{1,1,1}}; static SCROLLINFO scr[3]; static HWND scroll[3],scrLbl[3]; static int mouseMode=0, XR1, YR1, XR2, YR2, XT, YT; static long width,height, imageSize, mCtab,nBmi,nImage; static BITMAPINFO *pBmpInfo;BYTE *pbPixBit; static BITMAPFILEHEADER bmpFileHeader; static double scale=1.0; static int editMode=0; void changeEMode(HWND hw, int menuID){ editMode=menuID; mi.fMask=MIIM_STATE; mi.fState=MFS_UNCHECKED; SetMenuItemInfo(hm,E_COPY,FALSE,&mi); SetMenuItemInfo(hm,E_LINE,FALSE,&mi); SetMenuItemInfo(hm,E_RECT,FALSE,&mi); SetMenuItemInfo(hm,E_ELLP,FALSE,&mi); mi.fState=MFS_CHECKED; SetMenuItemInfo(hm,menuID,FALSE,&mi); } //エンコーダクラスIDの設定 static HGLOBAL hMem; static DWORD nFileSize; static IStream *iStream=NULL; void procDIBCreate(HWND hw){//出力はビットマップのみ int mCtab; int nBit=GetObject(hBM[0],sizeof(bitmap),(PVOID) &bM[0]); switch(bitmap.bmBitsPixel){ case 1: mCtab= 2; break; case 4: mCtab= 16; break; case 8: mCtab=256; break; case 24: case 32: mCtab= 0; break;// DDBが32ビットのときもある } nBmi=sizeof(RGBQUAD)*mCtab; nImage=(((bitmap.bmWidth*bitmap.bmBitsPixel)+31)/8)*bitmap.bmHeight; pBmpInfo=(BITMAPINFO *)malloc(nBmi+nImage); pbPixBit=((BYTE *)pBmpInfo+nBmi); // BMPファイルヘッダ bmpFileHeader.bfType = 0x4D42; bmpFileHeader.bfSize = sizeof(BITMAPFILEHEADER)+nBmi+nImage + sizeof(BITMAPINFOHEADER); bmpFileHeader.bfReserved1 = bmpFileHeader.bfReserved2 = 0; bmpFileHeader.bfOffBits = nBmi+sizeof(BITMAPINFOHEADER); // BMP情報ヘッダ pBmpInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); pBmpInfo->bmiHeader.biWidth = bM[0].bmWidth; pBmpInfo->bmiHeader.biHeight = bM[0].bmHeight; pBmpInfo->bmiHeader.biPlanes = 1; pBmpInfo->bmiHeader.biBitCount = //DDBが32ビットのとき24ビットに bitmap.bmBitsPixel==32 ? 24 : bitmap.bmBitsPixel; pBmpInfo->bmiHeader.biCompression = BI_RGB; pBmpInfo->bmiHeader.biSizeImage = 0; pBmpInfo->bmiHeader.biXPelsPerMeter= 0; pBmpInfo->bmiHeader.biYPelsPerMeter= 0; pBmpInfo->bmiHeader.biClrUsed = mCtab; pBmpInfo->bmiHeader.biClrImportant = mCtab; // ピクセルデータおよび色テーブル取得 pbPixBit=(BYTE *)malloc(nImage+nBmi); hdc=GetWindowDC(hw); GetDIBits(hBuff[0], hBM[0], 0, bM[0].bmHeight, (LPVOID)pbPixBit ,pBmpInfo, DIB_RGB_COLORS); } void procWrite(BYTE *DT, DWORD N){//ファイルへの書き込み DWORD dwWriteSize; WriteFile(hF,DT,N,&dwWriteSize,NULL); } void bmpFileName(TCHAR str[]){ TCHAR bmp[]=TEXT("tmp.bmp"); int i=0,ied;while(str[i]!=0)i++; ied=i; while(str[i]!=TCHAR('.') && i>=0)i--; if(ied==0 && i<0){ int j; for( j=0;bmp[j]!=0;j++) str[j]=bmp[j]; str[j]=0; } else{ int j; if(i<0)i=ied; for(j=3;bmp[j]!=0;j++,i++)str[i]=bmp[j]; str[i]=0; } } void fileSave(HWND hw){//ファイル保存 bmpFileName(strFile); CC.lpstrFile=strFile; CC.lpstrFilter=sFilter2; if(GetSaveFileName(&CC)){ hF=CreateFile(strFile,GENERIC_WRITE,0,NULL,CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if(hF==INVALID_HANDLE_VALUE) MessageBox(hw,TEXT("ファイルオープンエラー"),TEXT("エラー"),MB_OK); else{ procDIBCreate(hw); procWrite((BYTE *)&bmpFileHeader,sizeof(BITMAPFILEHEADER)); procWrite((BYTE *)pBmpInfo ,sizeof(BITMAPINFOHEADER)); procWrite((BYTE *)pbPixBit ,nBmi+nImage); FlushFileBuffers(hF); CloseHandle(hF); free(pbPixBit); free(pBmpInfo); } } } void getHandle(HWND hw){//エンコーダクラスIDの設定 DWORD nReadByte; short type; OLE_HANDLE hOle; IPicture *iPicture; nFileSize=GetFileSize(hF,NULL); hMem=GlobalAlloc(GMEM_MOVEABLE,nFileSize);//移動可能グローバル領域 LPVOID pvData=GlobalLock(hMem); ReadFile(hF,pvData, nFileSize, &nReadByte, NULL); GlobalUnlock(hMem); CloseHandle(hF); CreateStreamOnHGlobal(hMem,TRUE,&iStream);//ストリーム生成と変換 OleLoadPicture(iStream,nFileSize,FALSE,IID_IPicture,(LPVOID*)&iPicture); iStream->Release(); iPicture->get_Type(&type); if(type==PICTYPE_BITMAP)iPicture->get_Handle(&hOle); hBitmap=(HBITMAP)hOle; SelectObject(hMain,hBitmap);//ビットマット取得 GetObject(hBitmap,sizeof(BITMAP),&bitmap); GlobalFree(hMem); } void fileOpen(HWND hw){//ファイル入力 CC.lpstrFilter=sFilter; if(GetOpenFileName(&CC)){ hF=CreateFile(CC.lpstrFile,GENERIC_READ, 0,NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,NULL); if(hF==INVALID_HANDLE_VALUE) MessageBox(hw,TEXT("オープンエラー"),TEXT("エラー"),MB_OK); else{ hdc=GetDC(hw); hMain=CreateCompatibleDC(NULL); getHandle(hw); CloseHandle(hF); scale=1.0; for(int i=0;i<3;i++){ BitBlt(hBuff[i],0,0,bitmap.bmWidth,bitmap.bmHeight,hMain,0,0,SRCCOPY); GetObject(hBM[i],sizeof(BITMAP),&bM[i]); } } InvalidateRect(hw,NULL,TRUE); } } void clearDlgBitmap(){//ビットマップのクリア SelectObject(hBuff2,GetStockObject(NULL_PEN)); PatBlt(hBuff2,0,0,1000,600,WHITENESS); } //---------スプライン補間用---------------------- double difference(int i1,int i2){//■微分値(X方向は256で除した値とする) return ((double)(YDT[i2 ]-YDT[i1]))/((double)(XDT[i2]-XDT[i1]))*256.0; } int spline(double X, int i){//■スプライン補間 int i1=i, i2=i+1;double DY1, DY2,DD=256; //X方向の値をそのまま使うと if(abs(X-XDT[i1])<0.1) return (int) YDT[i1]; //誤差が大きくなるので256で除した if(abs(X-XDT[i2])<0.1) return (int) YDT[i2]; //値を用いる if(i1==0) DY1=difference(1,0); else DY1=difference(i2, i-1); if(i2==4) DY2=difference(4,3); else DY2=difference(i2+1,i1); double SG=(double)(XDT[i2]-XDT[i1])/DD, SG2=SG*SG, SG3=SG2*SG; double A1=2.0*((double)(YDT[i1]-YDT[i2]))/SG3+(DY1+DY2)/SG2; double A2=3.0*((double)(YDT[i2]-YDT[i1]))/SG2-(2.0*DY1+DY2)/SG; double A3=DY1, A4=YDT[i1]; double T= (X-(double)XDT[i1])/DD; double T2=T*T; double T3=T2*T; int R=(int) (A1*T3+A2*T2+A3*T+A4);if(R<0) R=0; if(R>255)R=255; return R; } int setValue(double X){//カラートーン値を求める関数 if(X<=XDT[0])return 0; if(X>=XDT[4])return 255;//範囲外を除く for(int i=0;i<4;i++) if(X>=XDT[i] && Xi;j--)//X座標の小さい順にソート if(XDT[j-1]>XDT[j]){ swap(int, XDT[j-1],XDT[j]);swap(int, YDT[j-1],YDT[j]); } } void initData(){//■初期値設定 XDT[0]=YDT[0]=0; XDT[4]=YDT[4]=255;//最初と最後は固定 XDT[1]=25; YDT[1]=80;XDT[2]=70; YDT[2]=180; XDT[3]=160; YDT[3]=240; } void viewChange(HWND hw, int X, int Y){//■座標値の変更 int MinDT = 9999999, ID=0, DX, DY, RR; for(int i=1;i<=3; i++){ DX = X-XDT[i]; DY=Y-YDT[i]; RR=DX*DX+DY*DY; if(RR=255) X=254;// 0 < X < 255とする  if(Y<=0) Y=0; if(Y>=255) Y=255;// 0 ≦ Y ≦ 255とする IMS=ID; XDT[IMS]=X; YDT[IMS]=Y;setData(); drawFig(hw); } } void dlgCreate(HWND hw, WPARAM wp,LPARAM lp){//■ダイアログボックス開始時 initData(); HDC hdc=GetDC(hw); hBM2=CreateCompatibleBitmap(hdc,300,300); hBuff2=CreateCompatibleDC(hdc); SelectObject(hBuff2,hBM2); viewChange(hw,127,127); drawFig(hw); ReleaseDC(hw,hdc); } void dlgLButtonDown(HWND hw, WPARAM wp,LPARAM lp){//■ダイアログボックス viewChange(hw,LOWORD(lp)-10,265-HIWORD(lp)); // 左ボタンダウン } void dlgLButtonUp(HWND hw, WPARAM wp,LPARAM lp){ //■ダイアログボックス IMS=0; // 左ボタンアップ } void dlgMouseMove(HWND hw, WPARAM wp,LPARAM lp){ //■ダイアログボックス if(GetKeyState(VK_LBUTTON)<0 && IMS!=0) // マウス移動 viewChange(hw,LOWORD(lp)-10,265-HIWORD(lp)); } void dlgCommand(HWND hw, WPARAM wp,LPARAM lp){ //■ダイアログボックス switch(LOWORD(wp)){ // コマンド処理 case IDOK : drawContrast(hwParent) ; return; case IDCANCEL: PostMessage(hw,WM_CLOSE,0,0); return; } } void dlgPaint(HWND hw,WPARAM wp,LPARAM lp){ //■ダイアログボックス PAINTSTRUCT ps; HDC hdc=BeginPaint(hw,&ps); // 再表示 BitBlt(hdc,0,0,1000,600,hBuff2,0,0,SRCCOPY); EndPaint(hw,&ps); } BOOLEAN dlgClose(){ //■ダイアログボックスのクローズ処理 DestroyWindow(hwDlg);hwDlg=NULL; DeleteDC(hBuff2);DeleteObject(hBM2); return TRUE; } BOOL CALLBACK DialogProc(HWND hw, UINT msg, WPARAM wp, LPARAM lp){ switch(msg){ case WM_CLOSE : return dlgClose(); case WM_CREATE : dlgCreate (hw,wp,lp); break; case WM_COMMAND : dlgCommand (hw,wp,lp); break; case WM_LBUTTONDOWN: dlgLButtonDown(hw,wp,lp); break; case WM_LBUTTONUP : dlgLButtonUp (hw,wp,lp); break; case WM_MOUSEMOVE : dlgMouseMove (hw,wp,lp); break; case WM_PAINT : dlgPaint (hw,wp,lp); break; } return FALSE; } void dlgToneCurve(HWND hw){//■トーンカーブダイアログの表示 if(!hwDlg){ hwDlg=CreateDialog(hInstance, TEXT("TONE"),hw,DialogProc); hwParent=hw; //親ウィンドウハンドル保存 SendMessage(hwDlg,WM_CREATE,0,0);//初期化起動 } } int rasterTable[4]={R2_COPYPEN,R2_MASKPEN, R2_MERGEPEN,R2_XORPEN}; int tmpLineColor, tmpPaintColor; int strToInt(TCHAR str[]){ char asc[128];int i; for(i=0; str[i];i++) asc[i]=(char)str[i]; asc[i]=0; sscanf(asc,"%d",&i); return i; } void dlg2Exsample(HWND hw){ TCHAR str[128]; HWND hEdit=GetDlgItem(hw,6002); GetWindowText(hEdit,str,127); int w=strToInt(str); HPEN pen = CreatePen(PS_SOLID,w,tmpLineColor);SelectObject(hBuff2,pen); HBRUSH brush = CreateSolidBrush(tmpPaintColor);SelectObject(hBuff2,brush); Rectangle(hBuff2,110, 80,170,140); DeleteObject(pen);DeleteObject(brush); InvalidateRect(hw,NULL,TRUE); } CHOOSECOLOR CDlg; COLORREF CustC[16]; void dlg2Create(HWND hw, WPARAM wp,LPARAM lp){//■ダイアログボックス開始時 HDC hdc=GetDC(hw); hBM2=CreateCompatibleBitmap(hdc,300,300); hBuff2=CreateCompatibleDC(hdc); SelectObject(hBuff2,hBM2); clearDlgBitmap(); ReleaseDC(hw,hdc); HWND hEdit=GetDlgItem(hw,6002);//線の太さをテキストボックスに表示 TCHAR str[128]; wsprintf(str,TEXT("%d"),drawAttribute.LineWidth); SetWindowText(hEdit,str); int ID=0;//ラスタ指定によるラジオボタンの設定 for(int i=0;i<4;i++) if(drawAttribute.DrawMode==rasterTable[i]){ID=i; break;} CheckRadioButton(hw,6010,6013, 6010+ID); tmpLineColor=drawAttribute.LineColor; //線の色を作業変数に移動する tmpPaintColor=drawAttribute.PaintColor; //塗り潰しの色を作業変数に移動する dlg2Exsample(hw); CDlg.lStructSize=sizeof(CHOOSECOLOR);//色選択ダイアログボックス CDlg.hwndOwner=hw; CDlg.hInstance=0; CDlg.lpCustColors = CustC; CDlg.Flags=CC_ANYCOLOR; } void dlg2LineColor(HWND hw){//線の色の設定 if(ChooseColor(&CDlg)){ tmpLineColor=CDlg.rgbResult; dlg2Exsample(hw); } } void dlg2PaintColor(HWND hw){//塗り潰し色の設定 if(ChooseColor(&CDlg)){ tmpPaintColor=CDlg.rgbResult; dlg2Exsample(hw); } } void dlg2OK(HWND hw){//OKボタンの処理 int ID=0;TCHAR str[128]; for(int i=0;i<4;i++)//ラスタ指定設定 if(IsDlgButtonChecked(hw, 6010+i)==BST_CHECKED){ ID=i; break;} drawAttribute.DrawMode=rasterTable[ID]; HWND hEdit=GetDlgItem(hw,6002); GetWindowText(hEdit,str,127); drawAttribute.LineWidth=strToInt(str);//線の太さ drawAttribute.LineColor=tmpLineColor; //線の色 drawAttribute.PaintColor=tmpPaintColor;//塗り潰し色 PostMessage(hw,WM_CLOSE,0,0); } void dlg2RadioButton(HWND hw,WPARAM wp){ CheckRadioButton(hw,6010,6013, LOWORD(wp)); } void dlg2Command(HWND hw, WPARAM wp,LPARAM lp){ //■ダイアログボックス switch(LOWORD(wp)){ // コマンド処理 case IDOK : dlg2OK(hw) ; return; case IDCANCEL: PostMessage(hw,WM_CLOSE,0,0); return; case 6003 : dlg2LineColor(hw);return; case 6004 : dlg2PaintColor(hw);return; case 6014 : dlg2Exsample(hw);return; case 6010 : case 6011 : case 6012 : case 6013 : dlg2RadioButton(hw,wp);break; } } BOOL CALLBACK Dialog2Proc(HWND hw, UINT msg, WPARAM wp, LPARAM lp){ switch(msg){ case WM_CLOSE : return dlgClose(); case WM_CREATE : dlg2Create (hw,wp,lp); break; case WM_COMMAND : dlg2Command (hw,wp,lp); break; case WM_PAINT : dlgPaint (hw,wp,lp); break; } return FALSE; } void figAttr(HWND hw){//■ if(!hwDlg){ hwDlg=CreateDialog(hInstance, TEXT("DRAWATTR"),hw,Dialog2Proc); hwParent=hw; //親ウィンドウハンドル保存 SendMessage(hwDlg,WM_CREATE,0,0);//初期化起動 } } //----------------トーンカープ表示用 ここまで------------------ int pixel(int X, int Y){ return GetPixel(hBuff[1],X, Y);} void setPixel(int X, int Y, int C){SetPixel(hBuff[0],X,Y,C);} void drawEdge(HWND hw){//■エッジ抽出 COLORREF C1, C2, C3, R1, R2, G1, G2, B1, B2; for(int i=0;i<300;i++)for(int j=0;j<300;j++){ int i1= (i==299)?298: i, j1=(j==299)? 298: j, i2=i1+1, j2=j1+1; C1=pixel(i1, j1); C2=pixel(i2, j1); C3=pixel(i1, j2); R1=abs((int)(RED (C1)-RED (C2))); G1=abs((int)(GREEN(C1)-GREEN(C2))); B1=abs((int)(BLUE (C1)-BLUE (C2))); R2=abs((int)(RED (C1)-RED (C3))); G2=abs((int)(GREEN(C1)-GREEN(C3))); B2=abs((int)(BLUE (C1)-BLUE (C3))); setPixel(i,j,RGB((R1+R2)/2,(G1+G2)/2,(G1+G2)/2)); } InvalidateRect(hw,NULL,TRUE); } int mixColor(int C1, int C2, double Alfa){ return (int)((double)C1*(1-Alfa)+(double)C2*Alfa); } void drawRGB(HWND hw){//RGB比率の変更 COLORREF C,R,G,B; for(int i=0;i<300;i++)for(int j=0;j<300;j++){ int i1= (i==299)?298: i, j1=(j==299)? 298: j, i2=i1+1, j2=j1+1; C=pixel(i1, j1); R=(int)((double)RED (C)*(double)scr[0].nPos/100); G=(int)((double)GREEN(C)*(double)scr[1].nPos/100); B=(int)((double)BLUE (C)*(double)scr[2].nPos/100); setPixel(i,j,RGB(R,G,B)); } InvalidateRect(hw,NULL,TRUE); } void setCoff(int i, COLORREF *CC, double *D){//RGB強調のときの比率の設定 if(scr[i].nPos>=50) {*CC = 0xFF; *D=(scr[i].nPos-50.0)/50.0;} else{ *CC = 0x0; *D=(50.0-scr[i].nPos)/50.0;} } void drawRGB2(HWND hw){//RGBの強調 COLORREF C,R,G,B, CC; double D; for(int i=0;i<300;i++)for(int j=0;j<300;j++){ int i1= (i==299)?298: i, j1=(j==299)? 298: j, i2=i1+1, j2=j1+1; C=pixel(i1, j1); setCoff(0, &CC, &D); R= mixColor(RED (C), CC,D); setCoff(1, &CC, &D); G= mixColor(GREEN(C), CC,D); setCoff(2, &CC, &D); B= mixColor(BLUE (C), CC,D); setPixel(i,j,RGB(R,G,B)); } InvalidateRect(hw,NULL,TRUE); } void drawDistinct(HWND hw){//鮮明化 int C0, C1, C2, C3,C4, R1, R2, G1, G2, B1, B2, R,G,B; double AR, AG, AB, Alfa=0.5;//Alfa:鮮明化の度合い。0〜1 for(int i=1;i<299;i++)for(int j=0;j<300;j++){ int i1=i+1, j1=j+1,i2=i-1, j2=j-1; C0=pixel(i , j );//該当ピクセルの色と周辺ピクセルの色 C1=pixel(i1, j ); C2=pixel(i , j1); C3=pixel(i2, j ); C4=pixel(i , j2); R=RED(C0); G=GREEN(C0); B=BLUE(C0);//周辺の明るさとの差 R1= R*4 - RED (C1)- RED (C2)- RED (C3) - RED (C4); G1= G*4 - GREEN(C1)- GREEN(C2)- GREEN(C3) - GREEN(C4); B1= B*4 - BLUE (C1)- BLUE (C2)- BLUE (C3) - BLUE (C4); AR=abs((double)R1/255)*Alfa;//強調度合い AG=abs((double)G1/255)*Alfa; AB=abs((double)B1/255)*Alfa; R2=0xFF;if(R1<0) R2=0; //周辺が暗い場合は明るく G2=0xFF;if(G1<0) G2=0; //周辺が明るい場合は暗く B2=0xFF;if(B1<0) B2=0; //周辺色との差で明暗強調 R1=mixColor(R, R2, AR);if(R1>255) R1=255; G1=mixColor(G, G2, AG);if(G1>255) G1=255; B1=mixColor(B, B2, AB);if(B1>255) B1=255; setPixel(i,j,RGB(R1,G1,B1)); } InvalidateRect(hw,NULL,TRUE); } void drawContrast(HWND hw){//明暗の強調(コントラスト) int C0, R1, G1, B1, R,G,B; for(int i=1;i<299;i++)for(int j=0;j<300;j++){ int i1=i+1, j1=j+1,i2=i-1, j2=j-1; C0=pixel(i , j );//該当ピクセルの色と R=RED(C0); G=GREEN(C0); B=BLUE(C0);//周辺の明るさとの差 double Z=(double)setValue(((double)R+(double)G+(double)B)/3)/255.0; R1= (int)(Z*R); G1= (int)(Z*G); B1= (int)(Z*B); setPixel(i,j,RGB(R1,G1,B1)); } InvalidateRect(hw,NULL,TRUE); } void procFilter(int filter[3][3]){//フィルタ処理 for(int i=1;i<299;i++)for(int j=0;j<300;j++){ COLORREF C; int R=0,G=0,B=0, T=0; for(int k1=0;k1<=2; k1++)for(int k2=0;k2<=2; k2++){ C=pixel(i+k1-1,j+k2-1); T+= filter[k1][k2]; R+=RED(C)*filter[k1][k2]; G+=GREEN(C)*filter[k1][k2]; B+=BLUE(C)*filter[k1][k2]; } R/=T; G/=T; B/=T; if(R>255)R=255; if(G>255)G=255; if(B>255)B=255; setPixel(i,j,RGB(R,G,B)); } } void drawShade(HWND hw){//平滑化フィルタ int filter[3][3]={{1,1,1},{1,1,1},{1,1,1}}; procFilter(filter); InvalidateRect(hw,NULL,TRUE); } void drawAverage(HWND hw){//加重平均フィルタ int filter[3][3]={{1,2,1},{2,4,2},{1,2,1}}; procFilter(filter); InvalidateRect(hw,NULL,TRUE); } void drawMedian(HWND hw){//メディアンフィルタ for(int i=1;i<299;i++)for(int j=0;j<300;j++){ int R=0,G=0,B=0, T=0, filter[9], k=0; for(int k1=0;k1<=2; k1++)for(int k2=0;k2<=2; k2++,k++) filter[k]=pixel(i+k1-1, j+k2-1); for(int k1=0;k1<8;k1++)for(int k2=8;k2>k1; k2--) if(filter[k2-1]>filter[k2]) swap(int,filter[k2-1],filter[k2]); setPixel(i,j,filter[4]); } InvalidateRect(hw,NULL,TRUE); } void drawGamma(HWND hw){//ガンマ補正 トーンカーブは、 double DP=0.8; //255*pow(色/255,DP)の式で近似。DP<1のとき強調。 for(int i=1;i<299;i++)for(int j=0;j<300;j++){ COLORREF C=pixel(i, j); double R=255*pow((double)RED (C)/255, DP); double G=255*pow((double)GREEN(C)/255, DP); double B=255*pow((double)BLUE (C)/255, DP); setPixel(i,j,RGB((int)R,(int)G,(int)B)); } InvalidateRect(hw,NULL,TRUE); } void drawMosaic(HWND hw){//モザイク処理(位置は固定)、 BitBlt(hBuff[0],0,0,bM[1].bmWidth,bM[1].bmHeight,hBuff[1],0,0,SRCCOPY); for(int i=60;i<140; i+=8)for(int j=40;j<120;j+=8){ int N=0, R=0, G=0, B=0, C=0; for(int k1=0;k1<8; k1++)for(int k2=0;k2<8; k2++){ N++; COLORREF C=pixel(i+k1, j+k2); R+=RED(C); G+=GREEN(C); B+=BLUE(C); } C=RGB(R/N, G/N, B/N); for(int k1=0;k1<8; k1++)for(int k2=0;k2<8; k2++) setPixel(i+k1,j+k2,C); } InvalidateRect(hw,NULL,TRUE); } void drawMono(HWND hw){//モノクロ画像化 COLORREF C; for(int i=0;i<300;i++)for(int j=0;j<300;j++){ C=pixel(i,j); C=(RED(C)+GREEN(C)+BLUE(C))/3; setPixel(i,j,RGB(C,C,C)); } InvalidateRect(hw,NULL,TRUE); } int sepColor3(int C){ return C<90? 0:(C<150? 0x80: 0xFF);} void drawColor16(HWND hw){//16色画像化 int Ctab[][2]={//16色カラー色にないコードの、みなしカラー色の対応表 {0x0080FF, 0x008080}, {0x00FF80, 0x008080}, {0x8000FF, 0x800080}, {0x80FF00, 0x808000}, {0x80FF80, 0xC0C0C0}, {0x80FFFF, 0xFFFFFF}, {0xFF0080, 0xFF00FF}, {0xFF8000, 0xFFFF00}, {0xFF8080, 0xC0C0C0}, {0xFF80FF, 0xFFFFFF}, {0xFFFF80, 0xFFFFFF} }; COLORREF C; for(int i=0;i<300;i++)for(int j=0;j<300;j++){ C=pixel(i,j); int R=sepColor3(RED(C)), G=sepColor3(GREEN(C)),B=(BLUE(C)); R=(R< 86)? 0: (R<171? 0x80: 0xFF);//減色初期計算 G=(G< 86)? 0: (G<170? 0x80: 0xFF); B=(B< 180)? 0: B=0xFF; if(R==0x00){ if((G==0xFF && B==0x80) || (G==0xFF && B==0x80))C=0x008080; else C=RGB(R,G,B); } C=RGB(R,G,B); int ID=-1; for(int k=0;k<11;k++){ if(C==Ctab[k][0]){ ID=k; break;}} if(ID>=0) C=Ctab[ID][1]; setPixel(i,j,C); } InvalidateRect(hw,NULL,TRUE); } void drawMove(HWND hw){//結果反映 BitBlt(hBuff[1],0,0,bM[1].bmWidth,bM[1].bmHeight,hBuff[0],0,0,SRCCOPY); InvalidateRect(hw,NULL,TRUE); } void drawUndo(HWND hw){//元に戻す BitBlt(hBuff[0],0,0,bM[1].bmWidth,bM[1].bmHeight,hBuff[1],0,0,SRCCOPY); InvalidateRect(hw,NULL,TRUE); } void createButton(HWND hw, TCHAR name[], int X,int Y, int w, int h, int No){ CreateWindow(TEXT("BUTTON"),name,WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON, X,Y,w,h, hw, (HMENU)No,hInstance,NULL); } HWND createLabel(HWND hw, TCHAR name[], int X,int Y, int w, int h, int No){ return CreateWindow(TEXT("STATIC"),name,WS_CHILD|WS_VISIBLE|SS_LEFT, X,Y,w,h, hw, (HMENU)No,hInstance,NULL); } void createScroll(HWND hw){ for(int i=0;i<3;i++){ scroll[i]= CreateWindow(TEXT("SCROLLBAR"),TEXT(""), WS_CHILD | WS_VISIBLE | SBS_HORZ, 30, i*20, 200, 20, hw, (HMENU)(2000+i), hInstance,NULL); scrLbl[i]=createLabel(hw,TEXT(" 100%"), 240, i*20, 60,20, 2100+i); scr[i].cbSize = sizeof(SCROLLINFO) ; scr[i].fMask=SIF_PAGE | SIF_RANGE; scr[i].nMin = 0; scr[i].nMax=100; scr[i].nPage=10; SetScrollInfo(scroll[i],SB_CTL, & scr[i],TRUE); scr[i].fMask=SIF_POS;scr[i].nPos=100; SetScrollInfo(scroll[i],SB_CTL, & scr[i],TRUE); } } void clearBitmap(int i){ SelectObject(hBuff[i], GetStockObject(NULL_PEN)); PatBlt(hBuff[i], 0,0,300,300,WHITENESS); } void createLabelGroup(HWND hw){ createLabel(hw,TEXT("R"),10, 0,20,20,LB_1); createLabel(hw,TEXT("G"),10, 20,20,20,LB_2); createLabel(hw,TEXT("B"),10, 40,20,20,LB_3); createLabel(hw,TEXT("左図で左ボタンドラッギングで複写範囲指定。"),300,0,400,20,LB_3); createLabel(hw,TEXT("続く左クリックで複写。右クリックで複写中止。"),300,20,400,20,LB_3); createLabel(hw,TEXT("右図の左右ボタンクリックでゴミピクセル混入。"),300,40,400,20,LB_3); } void createBitmapGroup(HWND hw){ HDC hdc=GetDC(hw); for(int i=0;i<3;i++){//コンテキストDC生成 hBM[i]= CreateCompatibleBitmap(hdc,300,300);//ビットマップ生成 hBuff[i]=CreateCompatibleDC(hdc);SelectObject(hBuff[i],hBM[i]); clearBitmap(0); GetObject(hBM[i],sizeof(BITMAP),&bM[i]); } } void createMenuGroup(HWND hw){ hm=CreateMenu(); hmFile=CreateMenu();// hmColorNum=CreateMenu(); hmFilter=CreateMenu();hmColor=CreateMenu();hmEdit=CreateMenu(); mi.cbSize=sizeof(MENUITEMINFO); mi.fMask=MIIM_TYPE|MIIM_SUBMENU; mi.fType=MFT_STRING; mi.hSubMenu=hmFile ; mi.dwTypeData=TEXT("ファイル(&F)"); InsertMenuItem(hm,0,TRUE, &mi); //mi.hSubMenu=hmColorNum; mi.dwTypeData=TEXT("減色(&D)" ); InsertMenuItem(hm,1,TRUE, &mi); mi.hSubMenu=hmFilter ; mi.dwTypeData=TEXT("画像補正(&F)"); InsertMenuItem(hm,2,TRUE, &mi); mi.hSubMenu=hmColor ; mi.dwTypeData=TEXT("色相変化(&C)"); InsertMenuItem(hm,3,TRUE, &mi); mi.hSubMenu=hmEdit ; mi.dwTypeData=TEXT("編集(&E)") ; InsertMenuItem(hm,4,TRUE, &mi); mi.fMask=MIIM_TYPE|MIIM_ID; mi.wID=F_OPEN; mi.dwTypeData=TEXT("開く(&O)");InsertMenuItem(hmFile,0,TRUE, &mi); mi.wID=F_SAVE; mi.dwTypeData=TEXT("保存(&S)");InsertMenuItem(hmFile,1,TRUE, &mi); mi.fType=MFT_SEPARATOR ;InsertMenuItem(hmFile,2,TRUE, &mi); mi.fType=MFT_STRING; mi.wID=F_EXIT; mi.dwTypeData=TEXT("終了(&X)");InsertMenuItem(hmFile,3,TRUE, &mi); //減色メニュー //mi.wID=D_GRAY; mi.dwTypeData=TEXT("グレイスケール(&G)");InsertMenuItem(hmColorNum,0,TRUE, &mi); //mi.wID=D_HEXA; mi.dwTypeData=TEXT("16色(&H)" );InsertMenuItem(hmColorNum,1,TRUE, &mi); //画像補正メニュー mi.wID=F_EAGE ; mi.dwTypeData=TEXT("エッジ抽出(&E)" );InsertMenuItem(hmFilter,0,TRUE, &mi); mi.wID=F_SHADE; mi.dwTypeData=TEXT("ぼかし(&S)" );InsertMenuItem(hmFilter,1,TRUE, &mi); mi.wID=F_AVER ; mi.dwTypeData=TEXT("加重平均(&A)" );InsertMenuItem(hmFilter,2,TRUE, &mi); mi.wID=F_MEDI ; mi.dwTypeData=TEXT("メディアン(&M)" );InsertMenuItem(hmFilter,3,TRUE, &mi); mi.wID=F_GAMMA; mi.dwTypeData=TEXT("ガンマ補正(&G)" );InsertMenuItem(hmFilter,4,TRUE, &mi); mi.wID=F_MOSA ; mi.dwTypeData=TEXT("モザイク処理(&O)");InsertMenuItem(hmFilter,5,TRUE, &mi); mi.wID=F_DIST ; mi.dwTypeData=TEXT("鮮明化(&D)" );InsertMenuItem(hmFilter,6,TRUE, &mi); //色相変化メニュー mi.wID=D_GRAY; mi.dwTypeData=TEXT("グレイスケール(&G)");InsertMenuItem(hmColor,0,TRUE, &mi); mi.wID=D_HEXA; mi.dwTypeData=TEXT("16色(&H)" );InsertMenuItem(hmColor,1,TRUE, &mi); mi.fType=MFT_SEPARATOR ;InsertMenuItem(hmColor,2,TRUE, &mi); mi.fType=MFT_STRING; mi.wID=C_CONT ; mi.dwTypeData=TEXT("明暗強調(&C)");InsertMenuItem(hmColor,3,TRUE, &mi); mi.wID=C_RGB ; mi.dwTypeData=TEXT("混合比率(&M)");InsertMenuItem(hmColor,4,TRUE, &mi); mi.wID=C_RGB2 ; mi.dwTypeData=TEXT("色相強弱(&S)");InsertMenuItem(hmColor,5,TRUE, &mi); //編集メニュー mi.wID=E_UNDO ; mi.dwTypeData=TEXT("元に戻す(&U)");InsertMenuItem(hmEdit,0,TRUE, &mi); mi.wID=E_STORE; mi.dwTypeData=TEXT("結果反映(&S)");InsertMenuItem(hmEdit,1,TRUE, &mi); mi.fType=MFT_SEPARATOR ;InsertMenuItem(hmEdit,2,TRUE, &mi); mi.fType=MFT_STRING; mi.wID=E_ATTR ; mi.dwTypeData=TEXT("図形属性(&A)");InsertMenuItem(hmEdit,3,TRUE, &mi); mi.fType=MFT_SEPARATOR ;InsertMenuItem(hmEdit,4,TRUE, &mi); mi.fType=MFT_STRING; mi.wID=E_COPY ; mi.dwTypeData=TEXT("複写(&C)" );InsertMenuItem(hmEdit,5,TRUE, &mi); mi.wID=E_LINE ; mi.dwTypeData=TEXT("直線描画(&L)");InsertMenuItem(hmEdit,6,TRUE, &mi); mi.wID=E_RECT ; mi.dwTypeData=TEXT("矩形描画(&R)");InsertMenuItem(hmEdit,7,TRUE, &mi); mi.wID=E_ELLP ; mi.dwTypeData=TEXT("楕円描画(&E)");InsertMenuItem(hmEdit,8,TRUE, &mi); SetMenu(hw, hm); } void createGetFileDialog(HWND hw){ CC.lStructSize =sizeof(OPENFILENAME); CC.hwndOwner =hw ; CC.hInstance =hInstance; CC.lpstrFilter =sFilter ; CC.nFilterIndex =1; CC.lpstrCustomFilter=NULL ; CC.nMaxCustFilter=0; CC.lpstrFile =strFile ; CC.nMaxFile =1024; CC.lpstrFileTitle =strFileTitle; CC.nMaxFileTitle =128; CC.lpstrInitialDir =TEXT("D:\\"); CC.lpstrTitle =TEXT("GDI+で表示"); CC.lpstrDefExt =TEXT("jpg") ; CC.FlagsEx =0; CC.Flags = OFN_EXPLORER|OFN_FILEMUSTEXIST|OFN_DONTADDTORECENT| OFN_NOTESTFILECREATE; } void procCreate(HWND hw, WPARAM wp, LPARAM lp){ initData(); MoveWindow(hw, 0,0,700, 500,TRUE); SetWindowText(hw,TEXT("C言語で画像処理")); //createButtonGroup(hw); createScroll (hw); createLabelGroup (hw); createBitmapGroup(hw); createMenuGroup (hw); createGetFileDialog(hw); hc=LoadCursor(NULL, IDC_ARROW);SetCursor(hc); fileOpen(hw); InvalidateRect(hw,NULL,TRUE); } void drawLine(HWND hw){//線指定時表示 HPEN pen=CreatePen(PS_SOLID,1,0xFFFFFF); SelectObject(hBuff[0],pen); SetROP2(hBuff[0],R2_XORPEN); MoveToEx(hBuff[0],XR1,YR1,NULL); LineTo(hBuff[0],XR2,YR2); SetROP2(hBuff[0],R2_COPYPEN); DeleteObject(pen); InvalidateRect(hw,NULL,TRUE); } void drawEllipseExec(HWND hw){//矩形表示 HPEN pen=CreatePen(PS_SOLID,drawAttribute.LineWidth,drawAttribute.LineColor); SelectObject(hBuff[0],pen); HBRUSH brush=CreateSolidBrush(drawAttribute.PaintColor); SelectObject(hBuff[0],brush); SetROP2(hBuff[0],drawAttribute.DrawMode); Ellipse(hBuff[0],XR1,YR1,XR2,YR2); SetROP2(hBuff[0],R2_COPYPEN); DeleteObject(brush);DeleteObject(pen); InvalidateRect(hw,NULL,TRUE); } void drawRectangleExec(HWND hw){//矩形表示 HPEN pen=CreatePen(PS_SOLID,drawAttribute.LineWidth,drawAttribute.LineColor); SelectObject(hBuff[0],pen); HBRUSH brush=CreateSolidBrush(drawAttribute.PaintColor); SelectObject(hBuff[0],brush); SetROP2(hBuff[0],drawAttribute.DrawMode); Rectangle(hBuff[0],XR1,YR1,XR2,YR2); SetROP2(hBuff[0],R2_COPYPEN); DeleteObject(brush);DeleteObject(pen); InvalidateRect(hw,NULL,TRUE); } void drawLineExec(HWND hw){//線を描く HPEN pen=CreatePen(PS_SOLID,drawAttribute.LineWidth,drawAttribute.LineColor); SelectObject(hBuff[0],pen); SetROP2(hBuff[0],drawAttribute.DrawMode); MoveToEx(hBuff[0],XR1,YR1,NULL); LineTo(hBuff[0],XR2,YR2); SetROP2(hBuff[0],R2_COPYPEN); DeleteObject(pen); InvalidateRect(hw,NULL,TRUE); } void drawEllipse(HWND hw){//楕円指定時の表示 HPEN pen=CreatePen(PS_SOLID,1,0xFFFFFF); SelectObject(hBuff[0],pen); HBRUSH brush=CreateSolidBrush(0x00); SelectObject(hBuff[0],brush); SetROP2(hBuff[0],R2_XORPEN); Ellipse(hBuff[0],XR1,YR1, XR2,YR2); SetROP2(hBuff[0],R2_COPYPEN); DeleteObject(brush);DeleteObject(pen); InvalidateRect(hw,NULL,TRUE); } void drawFrame(HWND hw){//選択範囲指定時の枠組み表示 HPEN pen=CreatePen(PS_SOLID,1,0xFFFFFF); SelectObject(hBuff[0],pen); HBRUSH brush=CreateSolidBrush(0x00); SelectObject(hBuff[0],brush); SetROP2(hBuff[0],R2_XORPEN); Rectangle(hBuff[0],XR1,YR1, XR2,YR2); SetROP2(hBuff[0],R2_COPYPEN); DeleteObject(brush);DeleteObject(pen); InvalidateRect(hw,NULL,TRUE); } void moveImage(){//イメージの移動 int XT1=XT,YT1=YT, XT2=XT-(XR2-XR1),YT2=YT-(YR2-YR1); if(XT1>XT2)swap(int, XT1,XT2); if(YT1>YT2)swap(int, YT1,YT2); BitBlt(hBuff[0], XT1,YT1,XT2-XT1,YT2-YT1,hBuff[0],XR1,YR1,SRCCOPY); } void drawFrame2(HWND hw){//複写指定直前の枠組み表示 BitBlt(hBuff[0],0,0,bM[1].bmWidth,bM[1].bmHeight,hBuff[2],0,0,SRCCOPY); moveImage(); InvalidateRect(hw,NULL,TRUE); } void setPixel2(HWND hw, int X, int Y, int C){ SetPixel(hBuff[1],X,Y,C); InvalidateRect(hw,NULL,TRUE); } void procCopyLButtonDown(HWND hw, WPARAM wp, LPARAM lp){ int X=LOWORD(lp)-XST, Y=HIWORD(lp)-YST, X2=LOWORD(lp)-10; if (Y>0 && Y0 && X0 && X20 && Y0 && X0 && X20 && Y0 && X2XR2) swap(int, XR1, XR2); if(YR1>YR2) swap(int, YR1, YR2); BitBlt(hBuff[2],0,0,bM[1].bmWidth,bM[1].bmHeight,hBuff[0],0,0,SRCCOPY); XT=X2; YT=Y; drawFrame2(hw); InvalidateRect(hw,NULL,TRUE); } } } } void procLineLButtonUp(HWND hw, WPARAM wp, LPARAM lp){ int X=LOWORD(lp)-XST, Y=HIWORD(lp)-YST, X2=LOWORD(lp)-10; if (Y>0 && Y0 && X2XR2) swap(int, XR1, XR2); if(YR1>YR2) swap(int, YR1, YR2); if (editMode==E_RECT) drawRectangleExec(hw); else if(editMode==E_ELLP) drawEllipseExec(hw); } mouseMode=0; InvalidateRect(hw,NULL,TRUE); } } } } void procLButtonUp(HWND hw, WPARAM wp, LPARAM lp){ if(editMode==E_COPY) procCopyLButtonUp(hw, wp, lp); else if(editMode==E_LINE || editMode==E_RECT|| editMode==E_ELLP) procLineLButtonUp(hw, wp, lp); } void procCopyMouseMove(HWND hw, WPARAM wp, LPARAM lp){ int Y=HIWORD(lp)-YST, X2=LOWORD(lp)-10; if (Y>0 && Y0 && X20 && Y0 && X20 && Y0 && X0 && X20) scr[i].nPos--;break; case SB_LINERIGHT:if(scr[i].nPos<(scr[i].nMax)) scr[i].nPos++;break; case SB_PAGELEFT :if(scr[i].nPos>=(int)scr[i].nPage) scr[i].nPos -=scr[i].nPage;break; case SB_PAGERIGHT: if((scr[i].nPos+(int)scr[i].nPage)<(scr[i].nMax-1)) scr[i].nPos +=scr[i].nPage;break; case SB_THUMBPOSITION:scr[i].nPos=HIWORD(wp); } SetScrollInfo(scroll[i],SB_CTL, & scr[i],TRUE); TCHAR str[256]; wsprintf(str,TEXT(" %3d%%"),scr[i].nPos); SetWindowText(scrLbl[i], str); } void procDestroy(){//イベント for(int i=0;i<3;i++){DeleteDC(hBuff[i]); DeleteObject(hBM[i]);} PostQuitMessage(0) ; } void procExit(HWND hw){ if(MessageBox(hw, TEXT("終了してもよろしいですか"), TEXT("画像処理例題"),MB_OKCANCEL)==IDOK) {procDestroy();return;} } void procCommand(HWND hw, WPARAM wp, LPARAM lp){//イベント hc=LoadCursor(NULL, IDC_WAIT);SetCursor(hc); switch(LOWORD(wp)){ case F_EAGE :drawEdge (hw); break; case F_SHADE :drawShade (hw); break; case F_AVER :drawAverage (hw); break; case F_MEDI :drawMedian (hw); break; case F_GAMMA :drawGamma (hw); break; case F_MOSA :drawMosaic (hw); break; case F_DIST :drawDistinct(hw); break; case C_CONT :dlgToneCurve(hw); break; case C_RGB :drawRGB (hw); break; case C_RGB2 :drawRGB2 (hw); break; case E_UNDO :drawUndo (hw); break; case E_STORE :drawMove (hw); break; case E_COPY :changeEMode (hw, E_COPY); break; case E_LINE :changeEMode (hw, E_LINE); break; case E_RECT :changeEMode (hw, E_RECT); break; case E_ELLP :changeEMode (hw, E_ELLP); break; case E_ATTR :figAttr(hw); break; case D_GRAY :drawMono (hw); break; case D_HEXA :drawColor16 (hw); break; case F_EXIT :procExit (hw); return; case F_OPEN :fileOpen (hw); break; case F_SAVE :fileSave (hw); break; } hc=LoadCursor(NULL, IDC_ARROW);SetCursor(hc); } LRESULT CALLBACK WndProc(HWND hw, UINT msg, WPARAM wp, LPARAM lp){ switch(msg){ case WM_DESTROY : DeleteObject(hBitmap);DeleteObject(hMain);;DeleteObject(hdc); DeleteObject(hBuff[0]);DeleteObject(hBuff[1]);DeleteObject(hBuff[2]); DeleteObject(hBM[0]);DeleteObject(hBM[1]);DeleteObject(hBM[2]); procDestroy(); return 0; case WM_CREATE : procCreate (hw, wp, lp); return 0; case WM_LBUTTONDOWN : procLButtonDown (hw, wp, lp); return 0; case WM_LBUTTONUP : procLButtonUp (hw, wp, lp); return 0; case WM_RBUTTONDOWN : procRButtonDown (hw, wp, lp); return 0; case WM_MOUSEMOVE : procMouseMove (hw, wp, lp); return 0; case WM_COMMAND : procCommand (hw, wp, lp); return 0; case WM_PAINT : procPaint (hw, wp, lp); return 0; case WM_HSCROLL : procHScroll (hw, wp, lp); return 0; case WM_SETCURSOR : SetCursor(hc); return 0; } return DefWindowProc(hw, msg, wp, lp); }