From 0ea3d9842cada5cb12749845a644e71ffcd23379 Mon Sep 17 00:00:00 2001 From: Katayama Hirofumi MZ Date: Sat, 1 Nov 2008 23:31:02 +0900 Subject: [PATCH] [15/19] mspaint: Add [Open] and [Save As] --- programs/mspaint/bitmap.c | 201 +++++++++++++++++++++++++++++++++++++++++++++ programs/mspaint/main.h | 2 + programs/mspaint/paint.c | 105 +++++++++++++++++++++++- 3 files changed, 305 insertions(+), 3 deletions(-) diff --git a/programs/mspaint/bitmap.c b/programs/mspaint/bitmap.c index 2c44f34..f346c3b 100644 --- a/programs/mspaint/bitmap.c +++ b/programs/mspaint/bitmap.c @@ -23,6 +23,207 @@ #include #include "resource.h" +#define WIDTHBYTES(x) (((x) + 31) / 32 * 4) + +typedef struct tagBITMAPINFOEX +{ + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[256]; +} BITMAPINFOEX, FAR * LPBITMAPINFOEX; + +HBITMAP BM_Load(LPCWSTR pszFileName) +{ + HANDLE hFile; + BITMAPFILEHEADER bf; + BITMAPINFOEX bi; + DWORD cb, cbImage; + DWORD dwError; + LPVOID pBits, pBits2; + HDC hDC, hMemDC; + HBITMAP hbm; +#ifndef LR_LOADREALSIZE +#define LR_LOADREALSIZE 128 +#endif + hbm = (HBITMAP)LoadImageW(NULL, pszFileName, IMAGE_BITMAP, 0, 0, + LR_LOADFROMFILE | LR_LOADREALSIZE | LR_CREATEDIBSECTION); + if (hbm != NULL) + return hbm; + + hFile = CreateFileW(pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) + return NULL; + + if (!ReadFile(hFile, &bf, sizeof(BITMAPFILEHEADER), &cb, NULL)) + { + dwError = GetLastError(); + CloseHandle(NULL); + SetLastError(dwError); + return NULL; + } + + pBits = NULL; + dwError = 0; + if (bf.bfType == 0x4D42 && bf.bfReserved1 == 0 && bf.bfReserved2 == 0 && + bf.bfSize > bf.bfOffBits && bf.bfOffBits > sizeof(BITMAPFILEHEADER) && + bf.bfOffBits <= sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOEX)) + { + cbImage = bf.bfSize - bf.bfOffBits; + pBits = HeapAlloc(GetProcessHeap(), 0, cbImage); + if (pBits != NULL) + { + if (ReadFile(hFile, &bi, bf.bfOffBits - + sizeof(BITMAPFILEHEADER), &cb, NULL) && + ReadFile(hFile, pBits, cbImage, &cb, NULL)) + { + ; + } + else + { + dwError = GetLastError(); + HeapFree(GetProcessHeap(), 0, pBits); + pBits = NULL; + } + } + else + dwError = GetLastError(); + } + else + dwError = -STRING_INVALID_BM; + + CloseHandle(hFile); + + if (pBits == NULL) + { + SetLastError(dwError); + return NULL; + } + + hbm = NULL; + dwError = 0; + hDC = GetDC(NULL); + if (hDC != NULL) + { + hMemDC = CreateCompatibleDC(hDC); + if (hMemDC != NULL) + { + hbm = CreateDIBSection(hMemDC, (BITMAPINFO*)&bi, DIB_RGB_COLORS, + &pBits2, NULL, 0); + if (hbm != NULL) + { + if (SetDIBits(hMemDC, hbm, 0, abs(bi.bmiHeader.biHeight), + pBits, (BITMAPINFO*)&bi, DIB_RGB_COLORS)) + { + ; + } + else + { + dwError = GetLastError(); + DeleteObject(hbm); + hbm = NULL; + } + } + else + dwError = GetLastError(); + + DeleteDC(hMemDC); + } + else + dwError = GetLastError(); + + ReleaseDC(NULL, hDC); + } + else + dwError = GetLastError(); + + HeapFree(GetProcessHeap(), 0, pBits); + SetLastError(dwError); + + return hbm; +} + +BOOL BM_Save(LPCWSTR pszFileName, HBITMAP hbm) +{ + BOOL f; + DWORD dwError; + BITMAPFILEHEADER bf; + BITMAPINFOEX bi; + DWORD cb; + DWORD cColors, cbColors; + HDC hDC; + HANDLE hFile; + LPVOID pBits; + BITMAP bm; + BITMAPINFOHEADER *pbmih = &bi.bmiHeader; + + if (!GetObject(hbm, sizeof(BITMAP), &bm)) + return FALSE; + + ZeroMemory(pbmih, sizeof(BITMAPINFOHEADER)); + pbmih->biSize = sizeof(BITMAPINFOHEADER); + pbmih->biWidth = bm.bmWidth; + pbmih->biHeight = bm.bmHeight; + pbmih->biPlanes = 1; + pbmih->biBitCount = bm.bmBitsPixel; + pbmih->biCompression = BI_RGB; + pbmih->biSizeImage = bm.bmWidthBytes * bm.bmHeight; + + if (bm.bmBitsPixel < 16) + cColors = 1 << bm.bmBitsPixel; + else + cColors = 0; + cbColors = cColors * sizeof(RGBQUAD); + + bf.bfType = 0x4d42; + bf.bfReserved1 = 0; + bf.bfReserved2 = 0; + cb = sizeof(BITMAPFILEHEADER) + pbmih->biSize + cbColors; + bf.bfOffBits = cb; + bf.bfSize = cb + pbmih->biSizeImage; + + pBits = HeapAlloc(GetProcessHeap(), 0, pbmih->biSizeImage); + if (pBits == NULL) + return FALSE; + + f = FALSE; + dwError = 0; + hDC = GetDC(NULL); + if (hDC != NULL) + { + if (GetDIBits(hDC, hbm, 0, bm.bmHeight, pBits, (BITMAPINFO*)&bi, + DIB_RGB_COLORS)) + { + hFile = CreateFileW(pszFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | + FILE_FLAG_WRITE_THROUGH, NULL); + if (hFile != INVALID_HANDLE_VALUE) + { + f = WriteFile(hFile, &bf, sizeof(BITMAPFILEHEADER), &cb, NULL) && + WriteFile(hFile, &bi, sizeof(BITMAPINFOHEADER), &cb, NULL) && + WriteFile(hFile, &bi.bmiColors, cbColors, &cb, NULL) && + WriteFile(hFile, pBits, pbmih->biSizeImage, &cb, NULL); + if (!f) + dwError = GetLastError(); + CloseHandle(hFile); + + if (!f) + DeleteFileW(pszFileName); + } + else + dwError = GetLastError(); + } + else + dwError = GetLastError(); + ReleaseDC(NULL, hDC); + } + else + dwError = GetLastError(); + + HeapFree(GetProcessHeap(), 0, pBits); + SetLastError(dwError); + return f; +} + HBITMAP BM_Create(SIZE siz) { BITMAPINFO bi; diff --git a/programs/mspaint/main.h b/programs/mspaint/main.h index 1ac816c..57bda1c 100644 --- a/programs/mspaint/main.h +++ b/programs/mspaint/main.h @@ -153,6 +153,8 @@ VOID Canvas_Rotate180Degree(HWND hWnd); VOID Canvas_Rotate270Degree(HWND hWnd); /* bitmap.c */ +HBITMAP BM_Load(LPCWSTR pszFileName); +BOOL BM_Save(LPCWSTR pszFileName, HBITMAP hbm); HBITMAP BM_Create(SIZE siz); HBITMAP BM_CreateResized(HWND hWnd, SIZE sizNew, HBITMAP hbm, SIZE siz); HBITMAP BM_CreateStretched(HWND hWnd, SIZE sizNew, HBITMAP hbm, SIZE siz); diff --git a/programs/mspaint/paint.c b/programs/mspaint/paint.c index a89a0a1..fdf2b36 100644 --- a/programs/mspaint/paint.c +++ b/programs/mspaint/paint.c @@ -153,6 +153,10 @@ BOOL FileExists(LPCWSTR szFileName) static VOID DoSaveFile(VOID) { + /* FIXME: Support different BPP */ + /* FIXME: Support GIF, JPEG, PNG files */ + if (BM_Save(Globals.szFileName, Globals.hbmImage)) + Globals.fModified = FALSE; } /** @@ -193,6 +197,47 @@ BOOL DoCloseFile(void) void DoOpenFile(LPCWSTR pszFileName) { + HANDLE hFile; + BOOL fEmpty; + DWORD filesize; + BITMAP bm; + + if (!DoCloseFile()) + return; + + if (!FileExists(pszFileName)) + { + AlertFileNotFound(pszFileName); + return; + } + + /* FIXME: Support PCX, ICO, GIF, JPEG, PNG files */ + fEmpty = TRUE; + hFile = CreateFile(pszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + filesize = GetFileSize(hFile, NULL); + if (filesize != 0) + { + fEmpty = FALSE; + } + CloseHandle(hFile); + + if (!fEmpty) + { + if (Globals.hbmImage != NULL) + DeleteObject(Globals.hbmImage); + Globals.hbmImage = BM_Load(pszFileName); + GetObject(Globals.hbmImage, sizeof(BITMAP), &bm); + Globals.sizImage.cx = bm.bmWidth; + Globals.sizImage.cy = bm.bmHeight; + } + + SetFileName(pszFileName); + UpdateWindowCaption(); + Globals.xScrollPos = Globals.yScrollPos = 0; + PostMessage(Globals.hCanvasWnd, WM_SIZE, 0, 0); + InvalidateRect(Globals.hCanvasWnd, NULL, TRUE); + UpdateWindow(Globals.hCanvasWnd); } VOID PAINT_FileNew(VOID) @@ -239,18 +284,72 @@ VOID PAINT_FileNew(VOID) VOID PAINT_FileOpen(VOID) { - NotSupportedYet(); + OPENFILENAME ofn; + WCHAR szFileName[MAX_PATH]; + WCHAR szDir[MAX_PATH]; + static const WCHAR szDefaultExt[] = { 'b','m','p',0 }; + static const WCHAR bmp_files[] = { '*','.','b','m','p',0 }; + + ZeroMemory(&ofn, sizeof(ofn)); + + GetCurrentDirectory(MAX_PATH, szDir); + lstrcpy(szFileName, bmp_files); + + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = Globals.hMainWnd; + ofn.hInstance = Globals.hInstance; + ofn.lpstrFilter = Globals.szFilter; + ofn.lpstrFile = szFileName; + ofn.nMaxFile = MAX_PATH; + ofn.lpstrInitialDir = szDir; + ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | + OFN_HIDEREADONLY; + ofn.lpstrDefExt = szDefaultExt; + + if (GetOpenFileName(&ofn)) + DoOpenFile(szFileName); } BOOL PAINT_FileSave(VOID) { - NotSupportedYet(); + if (Globals.szFileName[0] == '\0') + return PAINT_FileSaveAs(); + else + DoSaveFile(); return TRUE; } BOOL PAINT_FileSaveAs(VOID) { - NotSupportedYet(); + OPENFILENAME ofn; + WCHAR szPath[MAX_PATH]; + WCHAR szDir[MAX_PATH]; + static const WCHAR szDefaultExt[] = { 'b','m','p',0 }; + static const WCHAR bmp_files[] = { '*','.','b','m','p',0 }; + + ZeroMemory(&ofn, sizeof(ofn)); + + GetCurrentDirectory(MAX_PATH, szDir); + lstrcpy(szPath, bmp_files); + + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = Globals.hMainWnd; + ofn.hInstance = Globals.hInstance; + ofn.lpstrFilter = Globals.szFilter; + ofn.lpstrFile = szPath; + ofn.nMaxFile = MAX_PATH; + ofn.lpstrInitialDir = szDir; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | + OFN_HIDEREADONLY; + ofn.lpstrDefExt = szDefaultExt; + + if (GetSaveFileName(&ofn)) + { + SetFileName(szPath); + UpdateWindowCaption(); + DoSaveFile(); + return TRUE; + } return FALSE; } -- 1.6.0.2