[MSPAINT] Refactor loading/saving image file (#2686)

- Add DoLoadImageFile, CreateWhiteDIB, and CMainWindow::ConfirmSave functions.
- Replace LoadDIBFromFile function with DoLoadImageFile.
- Fix the empty file loading.
- Delete UpdateApplicationProperties function.
- Rewrite SaveDIBToFile function.
CORE-16982, CORE-16979
This commit is contained in:
Katayama Hirofumi MZ 2020-04-29 07:44:18 +09:00 committed by GitHub
parent 125020c23f
commit 036206a1c3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 186 additions and 225 deletions

View file

@ -26,6 +26,29 @@ CreateDIBWithProperties(int width, int height)
return CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, NULL, NULL, 0); return CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, NULL, NULL, 0);
} }
HBITMAP
CreateColorDIB(int width, int height, COLORREF rgb)
{
HBITMAP ret = CreateDIBWithProperties(width, height);
if (!ret)
return NULL;
if (rgb)
{
HDC hdc = CreateCompatibleDC(NULL);
HGDIOBJ hbmOld = SelectObject(hdc, ret);
RECT rc;
SetRect(&rc, 0, 0, width, height);
HBRUSH hbr = CreateSolidBrush(rgb);
FillRect(hdc, &rc, hbr);
DeleteObject(hbr);
SelectObject(hdc, hbmOld);
DeleteDC(hdc);
}
return ret;
}
int int
GetDIBWidth(HBITMAP hBitmap) GetDIBWidth(HBITMAP hBitmap)
{ {
@ -42,35 +65,32 @@ GetDIBHeight(HBITMAP hBitmap)
return bm.bmHeight; return bm.bmHeight;
} }
void BOOL SaveDIBToFile(HBITMAP hBitmap, LPTSTR FileName, HDC hDC)
SaveDIBToFile(HBITMAP hBitmap, LPTSTR FileName, HDC hDC, LPSYSTEMTIME time, int *size, int hRes, int vRes)
{ {
CImage img; CImage img;
img.Attach(hBitmap); img.Attach(hBitmap);
img.Save(FileName); // TODO: error handling img.Save(FileName); // TODO: error handling
img.Detach(); img.Detach();
WIN32_FIND_DATA find;
HANDLE hFind = FindFirstFile(FileName, &find);
if (hFind == INVALID_HANDLE_VALUE)
return FALSE;
FindClose(hFind);
// update time and size // update time and size
FILETIME ft;
HANDLE hFile = FileTimeToLocalFileTime(&find.ftLastWriteTime, &ft);
CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); FileTimeToSystemTime(&ft, &fileTime);
if (hFile == INVALID_HANDLE_VALUE) fileSize = find.nFileSizeLow;
return;
if (time)
{
FILETIME ft;
GetFileTime(hFile, NULL, NULL, &ft);
FileTimeToSystemTime(&ft, time);
}
if (size)
*size = GetFileSize(hFile, NULL);
// TODO: update hRes and vRes // TODO: update hRes and vRes
CloseHandle(hFile);
registrySettings.SetMostRecentFile(FileName); registrySettings.SetMostRecentFile(FileName);
isAFile = TRUE;
imageSaved = TRUE;
return TRUE;
} }
void ShowFileLoadError(LPCTSTR name) void ShowFileLoadError(LPCTSTR name)
@ -82,41 +102,105 @@ void ShowFileLoadError(LPCTSTR name)
mainWindow.MessageBox(strText, strProgramName, MB_OK | MB_ICONEXCLAMATION); mainWindow.MessageBox(strText, strProgramName, MB_OK | MB_ICONEXCLAMATION);
} }
void HBITMAP SetBitmapAndInfo(HBITMAP hBitmap, LPCTSTR name, DWORD dwFileSize, BOOL isFile)
LoadDIBFromFile(HBITMAP * hBitmap, LPCTSTR name, LPSYSTEMTIME time, int *size, int *hRes, int *vRes)
{ {
if (hBitmap == NULL)
{
COLORREF white = RGB(255, 255, 255);
hBitmap = CreateColorDIB(registrySettings.BMPWidth,
registrySettings.BMPHeight, white);
if (hBitmap == NULL)
return FALSE;
fileHPPM = fileVPPM = 2834;
ZeroMemory(&fileTime, sizeof(fileTime));
}
else
{
// update PPMs
HDC hScreenDC = GetDC(NULL);
fileHPPM = (int)(GetDeviceCaps(hScreenDC, LOGPIXELSX) * 1000 / 25.4);
fileVPPM = (int)(GetDeviceCaps(hScreenDC, LOGPIXELSY) * 1000 / 25.4);
ReleaseDC(NULL, hScreenDC);
}
// update image
imageModel.Insert(hBitmap);
imageModel.ClearHistory();
// update fileSize
fileSize = dwFileSize;
// update filepathname
if (name && name[0])
GetFullPathName(name, SIZEOF(filepathname), filepathname, NULL);
else
LoadString(hProgInstance, IDS_DEFAULTFILENAME, filepathname, SIZEOF(filepathname));
// set title
CString strTitle;
strTitle.Format(IDS_WINDOWTITLE, PathFindFileName(filepathname));
mainWindow.SetWindowText(strTitle);
// update file info and recent
isAFile = isFile;
if (isAFile)
registrySettings.SetMostRecentFile(filepathname);
imageSaved = TRUE;
return hBitmap;
}
HBITMAP DoLoadImageFile(HWND hwnd, LPCTSTR name, BOOL fIsMainFile)
{
// find the file
WIN32_FIND_DATA find;
HANDLE hFind = FindFirstFile(name, &find);
if (hFind == INVALID_HANDLE_VALUE)
{
// does not exist
CStringW strText;
strText.Format(IDS_LOADERRORTEXT, name);
MessageBoxW(hwnd, strText, NULL, MB_ICONERROR);
return NULL;
}
DWORD dwFileSize = find.nFileSizeLow; // get file size
FindClose(hFind);
// is file empty?
if (dwFileSize == 0)
{
if (fIsMainFile)
{
FILETIME ft;
FileTimeToLocalFileTime(&find.ftLastWriteTime, &ft);
FileTimeToSystemTime(&ft, &fileTime);
return SetBitmapAndInfo(NULL, name, dwFileSize, TRUE);
}
}
// load the image
CImage img; CImage img;
img.Load(name); img.Load(name);
*hBitmap = img.Detach(); HBITMAP hBitmap = img.Detach();
if (!hBitmap) if (hBitmap == NULL)
{ {
ShowFileLoadError(name); // cannot open
return; CStringW strText;
strText.Format(IDS_LOADERRORTEXT, name);
MessageBoxW(hwnd, strText, NULL, MB_ICONERROR);
return NULL;
} }
// update time and size if (fIsMainFile)
HANDLE hFile =
CreateFile(name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
ShowFileLoadError(name);
return;
}
if (time)
{ {
FILETIME ft; FILETIME ft;
GetFileTime(hFile, NULL, NULL, &ft); FileTimeToLocalFileTime(&find.ftLastWriteTime, &ft);
FileTimeToSystemTime(&ft, time); FileTimeToSystemTime(&ft, &fileTime);
SetBitmapAndInfo(hBitmap, name, dwFileSize, TRUE);
} }
if (size)
*size = GetFileSize(hFile, NULL);
HDC hScreenDC = GetDC(NULL); return hBitmap;
*hRes = (int)(GetDeviceCaps(hScreenDC, LOGPIXELSX) * 1000 / 25.4);
*vRes = (int)(GetDeviceCaps(hScreenDC, LOGPIXELSY) * 1000 / 25.4);
ReleaseDC(NULL, hScreenDC);
CloseHandle(hFile);
} }

View file

@ -9,14 +9,16 @@
#pragma once #pragma once
HBITMAP CreateDIBWithProperties(int width, int height); HBITMAP CreateDIBWithProperties(int width, int height);
HBITMAP CreateColorDIB(int width, int height, COLORREF rgb);
int GetDIBWidth(HBITMAP hbm); int GetDIBWidth(HBITMAP hbm);
int GetDIBHeight(HBITMAP hbm); int GetDIBHeight(HBITMAP hbm);
void SaveDIBToFile(HBITMAP hBitmap, LPTSTR FileName, HDC hDC, LPSYSTEMTIME time, int *size, int hRes, BOOL SaveDIBToFile(HBITMAP hBitmap, LPTSTR FileName, HDC hDC);
int vRes);
void LoadDIBFromFile(HBITMAP *hBitmap, LPCTSTR name, LPSYSTEMTIME time, int *size, int *hRes, int *vRes); HBITMAP DoLoadImageFile(HWND hwnd, LPCTSTR name, BOOL fIsMainFile);
void ShowFileLoadError(LPCTSTR name); void ShowFileLoadError(LPCTSTR name);
HBITMAP SetBitmapAndInfo(HBITMAP hBitmap, LPCTSTR name, DWORD dwFileSize, BOOL isFile);

View file

@ -53,6 +53,7 @@ extern HINSTANCE hProgInstance;
extern TCHAR filepathname[1000]; extern TCHAR filepathname[1000];
extern BOOL isAFile; extern BOOL isAFile;
extern BOOL imageSaved;
extern int fileSize; extern int fileSize;
extern int fileHPPM; extern int fileHPPM;
extern int fileVPPM; extern int fileVPPM;

View file

@ -161,8 +161,7 @@ void ImageModel::Crop(int nWidth, int nHeight, int nOffsetX, int nOffsetY)
void ImageModel::SaveImage(LPTSTR lpFileName) void ImageModel::SaveImage(LPTSTR lpFileName)
{ {
SaveDIBToFile(hBms[currInd], lpFileName, hDrawingDC, &fileTime, &fileSize, fileHPPM, fileVPPM); SaveDIBToFile(hBms[currInd], lpFileName, hDrawingDC);
imageSaved = TRUE;
} }
BOOL ImageModel::IsImageSaved() BOOL ImageModel::IsImageSaved()

View file

@ -21,8 +21,6 @@ private:
int undoSteps; int undoSteps;
int redoSteps; int redoSteps;
public: public:
BOOL imageSaved;
ImageModel(); ImageModel();
void CopyPrevious(void); void CopyPrevious(void);
void Undo(void); void Undo(void);

View file

@ -51,6 +51,7 @@ HINSTANCE hProgInstance;
TCHAR filepathname[1000]; TCHAR filepathname[1000];
BOOL isAFile = FALSE; BOOL isAFile = FALSE;
BOOL imageSaved = FALSE;
int fileSize; int fileSize;
int fileHPPM = 2834; int fileHPPM = 2834;
int fileVPPM = 2834; int fileVPPM = 2834;
@ -252,67 +253,7 @@ _tWinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPTSTR lpszArgument
if (__argc >= 2) if (__argc >= 2)
{ {
WIN32_FIND_DATAW find; DoLoadImageFile(mainWindow, __targv[1], TRUE);
HANDLE hFind = FindFirstFileW(__targv[1], &find);
if (hFind != INVALID_HANDLE_VALUE)
{
FindClose(hFind);
// check the file size
if (find.nFileSizeHigh || find.nFileSizeLow)
{
// load it now
HBITMAP bmNew = NULL;
LoadDIBFromFile(&bmNew, __targv[1], &fileTime, &fileSize, &fileHPPM, &fileVPPM);
if (bmNew)
{
// valid bitmap file
GetFullPathName(__targv[1], SIZEOF(filepathname), filepathname, NULL);
imageModel.Insert(bmNew);
CPath pathFileName(filepathname);
pathFileName.StripPath();
CString strTitle;
strTitle.Format(IDS_WINDOWTITLE, (LPCTSTR)pathFileName);
mainWindow.SetWindowText(strTitle);
imageModel.ClearHistory();
isAFile = TRUE;
registrySettings.SetMostRecentFile(filepathname);
}
else
{
// cannot open and not empty
CStringW strText;
strText.Format(IDS_LOADERRORTEXT, __targv[1]);
MessageBoxW(NULL, strText, NULL, MB_ICONERROR);
}
}
else
{
// open the empty file
GetFullPathName(__targv[1], SIZEOF(filepathname), filepathname, NULL);
CPath pathFileName(filepathname);
pathFileName.StripPath();
CString strTitle;
strTitle.Format(IDS_WINDOWTITLE, (LPCTSTR)pathFileName);
mainWindow.SetWindowText(strTitle);
imageModel.ClearHistory();
isAFile = TRUE;
registrySettings.SetMostRecentFile(filepathname);
}
}
else
{
// does not exist
CStringW strText;
strText.Format(IDS_LOADERRORTEXT, __targv[1]);
MessageBoxW(NULL, strText, NULL, MB_ICONERROR);
}
} }
/* initializing the CHOOSECOLOR structure for use with ChooseColor */ /* initializing the CHOOSECOLOR structure for use with ChooseColor */

View file

@ -102,21 +102,6 @@ void CMainWindow::saveImage(BOOL overwrite)
} }
} }
void CMainWindow::UpdateApplicationProperties(HBITMAP bitmap, LPCTSTR newfilepathname)
{
imageModel.Insert(bitmap);
CopyMemory(filepathname, newfilepathname, sizeof(filepathname));
CPath pathFileName(newfilepathname);
pathFileName.StripPath();
CString strTitle;
strTitle.Format(IDS_WINDOWTITLE, (LPCTSTR)pathFileName);
SetWindowText(strTitle);
imageModel.ClearHistory();
isAFile = TRUE;
registrySettings.SetMostRecentFile(newfilepathname);
}
void CMainWindow::InsertSelectionFromHBITMAP(HBITMAP bitmap, HWND window) void CMainWindow::InsertSelectionFromHBITMAP(HBITMAP bitmap, HWND window)
{ {
int width = GetDIBWidth(bitmap); int width = GetDIBWidth(bitmap);
@ -174,17 +159,14 @@ void CMainWindow::InsertSelectionFromHBITMAP(HBITMAP bitmap, HWND window)
LRESULT CMainWindow::OnDropFiles(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) LRESULT CMainWindow::OnDropFiles(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{ {
HDROP drophandle;
TCHAR droppedfile[MAX_PATH]; TCHAR droppedfile[MAX_PATH];
HBITMAP bmNew = NULL;
drophandle = (HDROP)wParam; HDROP hDrop = (HDROP)wParam;
DragQueryFile(drophandle, 0, droppedfile, SIZEOF(droppedfile)); DragQueryFile(hDrop, 0, droppedfile, SIZEOF(droppedfile));
DragFinish(drophandle); DragFinish(hDrop);
LoadDIBFromFile(&bmNew, droppedfile, &fileTime, &fileSize, &fileHPPM, &fileVPPM);
if (bmNew != NULL) ConfirmSave() && DoLoadImageFile(m_hWnd, droppedfile, TRUE);
{
UpdateApplicationProperties(bmNew, droppedfile);
}
return 0; return 0;
} }
@ -202,29 +184,34 @@ LRESULT CMainWindow::OnDestroy(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
return 0; return 0;
} }
BOOL CMainWindow::ConfirmSave()
{
if (imageModel.IsImageSaved())
return TRUE;
CString strProgramName;
strProgramName.LoadString(IDS_PROGRAMNAME);
CString strSavePromptText;
strSavePromptText.Format(IDS_SAVEPROMPTTEXT, PathFindFileName(filepathname));
switch (MessageBox(strSavePromptText, strProgramName, MB_YESNOCANCEL | MB_ICONQUESTION))
{
case IDYES:
saveImage(TRUE);
return imageModel.IsImageSaved();
case IDNO:
return TRUE;
case IDCANCEL:
return FALSE;
}
return TRUE;
}
LRESULT CMainWindow::OnClose(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) LRESULT CMainWindow::OnClose(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{ {
if (!imageModel.IsImageSaved()) if (ConfirmSave())
{
CString strProgramName;
strProgramName.LoadString(IDS_PROGRAMNAME);
CPath pathFileName(filepathname);
pathFileName.StripPath();
CString strSavePromptText;
strSavePromptText.Format(IDS_SAVEPROMPTTEXT, (LPCTSTR)pathFileName);
switch (MessageBox(strSavePromptText, strProgramName, MB_YESNOCANCEL | MB_ICONQUESTION))
{
case IDNO:
DestroyWindow();
break;
case IDYES:
saveImage(FALSE);
if (imageModel.IsImageSaved())
DestroyWindow();
break;
}
}
else
{ {
DestroyWindow(); DestroyWindow();
} }
@ -404,45 +391,15 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
SendMessage(WM_CLOSE, wParam, lParam); SendMessage(WM_CLOSE, wParam, lParam);
break; break;
case IDM_FILENEW: case IDM_FILENEW:
{ if (ConfirmSave())
BOOL reset = TRUE;
if (!imageModel.IsImageSaved())
{ {
CString strProgramName; SetBitmapAndInfo(NULL, NULL, 0, FALSE);
strProgramName.LoadString(IDS_PROGRAMNAME);
CPath pathFileName(filepathname);
pathFileName.StripPath();
CString strSavePromptText;
strSavePromptText.Format(IDS_SAVEPROMPTTEXT, (LPCTSTR)pathFileName);
switch (MessageBox(strSavePromptText, strProgramName, MB_YESNOCANCEL | MB_ICONQUESTION))
{
case IDNO:
imageModel.imageSaved = TRUE; //TODO: move to ImageModel
break;
case IDYES:
saveImage(FALSE);
break;
case IDCANCEL:
reset = FALSE;
break;
}
}
if (reset && imageModel.IsImageSaved()) //TODO: move to ImageModel
{
imageModel.Clear();
imageModel.ClearHistory();
} }
break; break;
}
case IDM_FILEOPEN: case IDM_FILEOPEN:
if (GetOpenFileName(&ofn) != 0) if (ConfirmSave() && GetOpenFileName(&ofn))
{ {
HBITMAP bmNew = NULL; DoLoadImageFile(m_hWnd, ofn.lpstrFile, TRUE);
LoadDIBFromFile(&bmNew, ofn.lpstrFile, &fileTime, &fileSize, &fileHPPM, &fileVPPM);
if (bmNew != NULL)
{
UpdateApplicationProperties(bmNew, ofn.lpstrFile);
}
} }
break; break;
case IDM_FILESAVE: case IDM_FILESAVE:
@ -494,42 +451,22 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
break; break;
case IDM_FILE1: case IDM_FILE1:
{ {
HBITMAP bmNew = NULL; ConfirmSave() && DoLoadImageFile(m_hWnd, registrySettings.strFile1, TRUE);
LoadDIBFromFile(&bmNew, registrySettings.strFile1, &fileTime, &fileSize, &fileHPPM, &fileVPPM);
if (bmNew != NULL)
{
UpdateApplicationProperties(bmNew, registrySettings.strFile1);
}
break; break;
} }
case IDM_FILE2: case IDM_FILE2:
{ {
HBITMAP bmNew = NULL; ConfirmSave() && DoLoadImageFile(m_hWnd, registrySettings.strFile2, TRUE);
LoadDIBFromFile(&bmNew, registrySettings.strFile2, &fileTime, &fileSize, &fileHPPM, &fileVPPM);
if (bmNew != NULL)
{
UpdateApplicationProperties(bmNew, registrySettings.strFile2);
}
break; break;
} }
case IDM_FILE3: case IDM_FILE3:
{ {
HBITMAP bmNew = NULL; ConfirmSave() && DoLoadImageFile(m_hWnd, registrySettings.strFile3, TRUE);
LoadDIBFromFile(&bmNew, registrySettings.strFile3, &fileTime, &fileSize, &fileHPPM, &fileVPPM);
if (bmNew != NULL)
{
UpdateApplicationProperties(bmNew, registrySettings.strFile3);
}
break; break;
} }
case IDM_FILE4: case IDM_FILE4:
{ {
HBITMAP bmNew = NULL; ConfirmSave() && DoLoadImageFile(m_hWnd, registrySettings.strFile4, TRUE);
LoadDIBFromFile(&bmNew, registrySettings.strFile4, &fileTime, &fileSize, &fileHPPM, &fileVPPM);
if (bmNew != NULL)
{
UpdateApplicationProperties(bmNew, registrySettings.strFile4);
}
break; break;
} }
case IDM_EDITUNDO: case IDM_EDITUNDO:
@ -578,18 +515,17 @@ LRESULT CMainWindow::OnCommand(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bH
break; break;
} }
case IDM_EDITCOPYTO: case IDM_EDITCOPYTO:
if (GetSaveFileName(&ofn) != 0) if (GetSaveFileName(&ofn))
SaveDIBToFile(selectionModel.GetBitmap(), ofn.lpstrFile, imageModel.GetDC(), NULL, NULL, fileHPPM, fileVPPM); SaveDIBToFile(selectionModel.GetBitmap(), ofn.lpstrFile, imageModel.GetDC());
break; break;
case IDM_EDITPASTEFROM: case IDM_EDITPASTEFROM:
if (GetOpenFileName(&ofn) != 0) if (GetOpenFileName(&ofn))
{ {
HBITMAP bmNew = NULL; HBITMAP hbmNew = DoLoadImageFile(m_hWnd, ofn.lpstrFile, FALSE);
LoadDIBFromFile(&bmNew, ofn.lpstrFile, &fileTime, &fileSize, &fileHPPM, &fileVPPM); if (hbmNew)
if (bmNew != NULL)
{ {
InsertSelectionFromHBITMAP(bmNew, m_hWnd); InsertSelectionFromHBITMAP(hbmNew, m_hWnd);
DeleteObject(bmNew); DeleteObject(hbmNew);
} }
} }
break; break;

View file

@ -42,6 +42,6 @@ public:
void alignChildrenToMainWindow(); void alignChildrenToMainWindow();
void saveImage(BOOL overwrite); void saveImage(BOOL overwrite);
void UpdateApplicationProperties(HBITMAP bitmap, LPCTSTR newfilepathname);
void InsertSelectionFromHBITMAP(HBITMAP bitmap, HWND window); void InsertSelectionFromHBITMAP(HBITMAP bitmap, HWND window);
BOOL ConfirmSave();
}; };