#include <windows.h>
#include <stdio.h>
#include <io.h>
#include <ctime>
#include <ctype.h>
#include <gdiplus/gdiplus.h>
#pragma comment (lib, "gdiplus.lib")
#include "resource.h"
int cx, cy;
int cell, cells=20, cellOff;
int shiftStep;
bool load=true;
bool noRest=false;
bool blur_on=false;
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
int gFunsterStil;
HWND hwnd, hwndB;HINSTANCE gThisInstance;
MSG messages;WNDCLASSEX wincl;RECT Rect;
HDC hDC;
COLORREF txtCol=RGB (255, 255, 255);
COLORREF txtColG=RGB (175, 175, 175);
COLORREF bkCol=RGB (100, 100, 100);
HBRUSH bg=CreateSolidBrush (bkCol);
HBRUSH bgB=CreateSolidBrush (txtCol);
HPEN pen=CreatePen (PS_SOLID, 1, bkCol);
HFONT hFont;
PAINTSTRUCT PaintStruct;
char szClassName []="WindowsApp";
char title []=" PicViewer";
char url [_MAX_PATH], pDir [_MAX_PATH], pF [50000] [256];
int url_l=0;
int pFc=0, pFn=-1;
int infoOn=0;
int px, py, pl, pt, pla=0, pta=0;
float pxs, pys;
int stepX=0, stepY=0, stepN=0;
int cFrames;
bool slide=false;
bool full=false;
const unsigned int TIMER_SLIDE=1, TIMER_MESS=2, TIMER_CUR=5;
char mess [256];
bool messOn=false;
bool ctrl=false;
bool shift=false;
bool copyDirIs=false;
int hideCur=0;
ULONG_PTR gdiplusToken;
Gdiplus::Graphics * gDC;
Gdiplus::Image * imagesH;
POINT mypoint;
void messPrint ()
{
hDC=GetDC (hwnd);
SelectObject (hDC, pen);
SelectObject (hDC, bg);
Rectangle(hDC, 0, 0, cx, cy);
SelectObject (hDC, hFont);
SetBkColor (hDC, bkCol);
SetTextColor (hDC, txtCol);
SetRect (&Rect, 0, 0, cx, cy);
DrawText (hDC, mess, strlen (mess), &Rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
ReleaseDC (hwnd, hDC);
}
void messPrintP ()
{
messPrint ();
messOn=true;
SetTimer (hwnd, TIMER_MESS, 2500, NULL);
}
void picture (bool reload=false)
{
bool fileIs=true;
if (reload==true)
{
FILE * file;
file=fopen (url, "r");
if (file==NULL)
fileIs=false;
fclose (file);
if (fileIs==true)
{
delete imagesH;
WCHAR ts [256];
MultiByteToWideChar (CP_ACP, 0, url, -1, ts, 256);
imagesH=new Gdiplus::Image (ts, true);
px=imagesH->GetWidth ();
}
}
if (fileIs==true && px>0)
{
cFrames=imagesH->GetFrameCount (&Gdiplus::FrameDimensionTime);
hDC=GetDC (hwnd);
SelectObject (hDC, pen);
SelectObject (hDC, bg);
Rectangle (hDC, 0, 0, cx+1, cy+1);
if (reload==true)
py=imagesH->GetHeight ();
if ((px>cx || py>cy) && full==false)
{
if ((float)px/(float)cx>(float)py/(float)cy)
{
pxs=cx+1;
pys=py/((float)px/(float)(cx+1));
}
else
{
pys=cy+1;
pxs=px/((float)py/(float)(cy+1));
}
}
else
{
if (stepN!=0)
{
if (cx>cy)
stepX=cy/5;
else
stepX=cx/5;
stepY=stepX;
if (px>py)
stepY*=(float)py/(float)px;
else
stepX*=(float)px/(float)py;
pxs=px+stepX*stepN;
pys=py+stepY*stepN;
}
else
{
pxs=px;
pys=py;
}
}
pl=(cx-pxs)/2;
pt=(cy-pys)/2;
gDC=new Gdiplus::Graphics (hDC);
gDC->SetPageUnit(Gdiplus::UnitPixel);
gDC->SetCompositingMode(Gdiplus::CompositingModeSourceCopy);
gDC->SetCompositingQuality(Gdiplus::CompositingQualityAssumeLinear);
gDC->SetPixelOffsetMode(Gdiplus::PixelOffsetModeHighQuality);
gDC->SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
gDC->SetInterpolationMode(Gdiplus::InterpolationModeHighQualityBicubic);
Gdiplus::RectF bounds(pl+pla, pt+pta, pxs, pys);
Gdiplus::ImageAttributes attr;
attr.SetWrapMode(Gdiplus::WrapModeTile);
gDC->DrawImage (imagesH, bounds, 0, 0, px, py, Gdiplus::UnitPixel, &attr);
DeleteObject (&attr);
DeleteObject (&bounds);
ReleaseDC (hwnd, hDC);
}
else
{
char name [256];
memset (name, 0, 256);
int i, i2, c=0;
for (i=strlen (url)-1; i>0; i--)
{
if (url [i]=='\\')
break;
}
for (i2=i+1; i2<strlen (url); i2++)
{
name [c]=url [i2];
c++;
}
if (fileIs==true)
sprintf (mess, "Файл \"%s\" не распознан", name);
else
sprintf (mess, "Файл \"%s\" не найден", name);
messPrint ();
}
}
void info ()
{
int i, lines, line=1;
char txtL [32] [256];
if (infoOn==3)
{
if (cFrames>1)
{
char txtLa [] [256]={"Файл: ", "Дата: ", "Длина: ", "Размер: ", "Кадры: ", "Место: "};
lines=sizeof (txtLa)/256;
for (i=0; i<lines; i++)
memcpy (txtL [i*2], txtLa [i], 256);
}
else
{
char txtLa [] [256]={"Файл: ", "Дата: ", "Длина: ", "Размер: ", "Место: "};
lines=sizeof (txtLa)/256;
for (i=0; i<lines; i++)
memcpy (txtL [i*2], txtLa [i], 256);
}
if (pFn==-1)
sprintf (txtL [line*2-1], "не найден");
else
memcpy (txtL [line*2-1], pF [pFn], 256);
line++;
WIN32_FIND_DATA FindFileData;
HANDLE hf;
FILETIME creationTime;
SYSTEMTIME sysTime;
hf=FindFirstFile (url, &FindFileData);
if (hf!=INVALID_HANDLE_VALUE)
{
creationTime=FindFileData.ftLastWriteTime;
FileTimeToSystemTime (&creationTime, &sysTime);
char month [] [10]={"января", "февраля", "марта", "апреля", "мая", "июня", "июля", "августа", "сентября", "октября", "ноября", "декабря"};
sprintf (txtL [line*2-1], "%d %s %d", sysTime.wDay, month [sysTime.wMonth-1], sysTime.wYear);
}
line++;
FILE * file;
int size;
file=fopen (url, "r");
if (file!=NULL)
{
fseek (file, 0, SEEK_END); size=ftell (file); }
fclose (file);
if (size<1024)
sprintf (txtL [line*2-1], "%d байт", size);
else if (size<1024*1024)
sprintf (txtL [line*2-1], "%d Кб", size/1024);
else if (size<1024*1024*1024)
{
int d=size*10/(1024*1024)-size/(1024*1024)*10;
if (d!=0)
sprintf (txtL [line*2-1], "%d,%d Мб", size/(1024*1024), d);
else
sprintf (txtL [line*2-1], "%d Мб", size/(1024*1024));
}
line++;
sprintf (txtL [line*2-1], "%d x %d", px, py);
line++;
if (cFrames>1)
{
sprintf (txtL [line*2-1], "%d", cFrames);
line++;
}
if (pFn==-1)
sprintf (txtL [line*2-1], "? / %d");
else
sprintf (txtL [line*2-1], "%d / %d", pFn+1, pFc);
}
else
{
char txtLa [] [256]={
"Просмотр: ", "(ctrl +) влево, вправо",
"К началу, в конец: ", "ctrl + home / end",
"Слайд-шоу: ", "enter",
"Поворот: ", "вверх, вниз",
"Полный размер: ", "пробел",
"Увеличить, уменьшить: ", "плюс, минус",
"Сдвиг: ", "shift + клавиши-стрелки",
"Копия: ", "c",
"О файле: ", "i",
"Справка: ", "f1, h",
"Выход: ", "esc"
};
lines=sizeof (txtLa)/256/2;
for (i=0; i<lines*2; i++)
memcpy (txtL [i], txtLa [i], 256);
}
char txtA [256];
sprintf (txtA, "PicViewer 2015-20 %c Маркичев Д. И. ", 169);
char txtB [256]={"Нажмите любую клавишу для возврата... "};
hDC=GetDC (hwnd);
SelectObject (hDC, pen);
SelectObject (hDC, bg);
Rectangle(hDC, 0, 0, cx, cy);
SetBkColor (hDC, bkCol);
SetTextColor (hDC, txtCol);
SelectObject (hDC, hFont);
for (i=0; i<lines; i++)
{
SetRect (&Rect, 0, cellOff+cell*((cells-lines)/2+i), cx/2, cellOff+cell*((cells-lines)/2+i+1));
DrawText (hDC, txtL [i*2], strlen (txtL [i*2]), &Rect, DT_SINGLELINE | DT_RIGHT | DT_VCENTER);
}
SetTextColor (hDC, txtColG);
for (i=0; i<lines; i++)
{
SetRect (&Rect, cx/2, cellOff+cell*((cells-lines)/2+i), cx, cellOff+cell*((cells-lines)/2+i+1));
DrawText (hDC, txtL [i*2+1], strlen (txtL [i*2+1]), &Rect, DT_SINGLELINE | DT_LEFT | DT_VCENTER);
}
SetRect (&Rect, cx/2, cellOff+cell*(cells-2), cx, cellOff+cell*(cells-1));
if (infoOn!=1)
DrawText (hDC, txtB, strlen (txtB), &Rect, DT_SINGLELINE | DT_RIGHT | DT_VCENTER);
else
DrawText (hDC, txtA, strlen (txtA), &Rect, DT_SINGLELINE | DT_RIGHT | DT_VCENTER);
ReleaseDC (hwnd, hDC);
}
void screenSet ()
{
cx=(LONG)::GetSystemMetrics( SM_CXSCREEN );
cy=(LONG)::GetSystemMetrics( SM_CYSCREEN );
DeleteObject (hFont);
if (cx>cy)
{
shiftStep=cy/5;
hFont=CreateFont (cy/30, 0, 0, 0, FW_EXTRABOLD, false, false, false, RUSSIAN_CHARSET, false, false, ANTIALIASED_QUALITY, false, "Arial");
cell=cy/cells;
cellOff=0;
}
else
{
shiftStep=cx/5;
hFont=CreateFont (cx/30, 0, 0, 0, FW_EXTRABOLD, false, false, false, RUSSIAN_CHARSET, false, false, ANTIALIASED_QUALITY, false, "Arial");
cell=cx/cells;
cellOff=(cy-cx)/2;
}
}
void screenUp ()
{
noRest=true;
hwndB = CreateWindowEx (
0, szClassName, title, WS_POPUP,
-1,
-1,
cx+2, cy+2, HWND_DESKTOP, NULL, gThisInstance, NULL );
ShowWindow (hwndB, gFunsterStil);
ShowWindow (hwnd, 0);
hwnd=hwndB;
noRest=false;
}
void copyPic ()
{
if (copyDirIs==false)
{
char copyDir [_MAX_PATH];
sprintf (copyDir, "%s%s", pDir, "PicViewer");
mkdir (copyDir);
copyDirIs=true;
}
char copyFile [_MAX_PATH];
sprintf (copyFile, "%s%s%s", pDir, "PicViewer\\", pF [pFn]);
bool r=CopyFile (url, copyFile, false);
if (r)
{
sprintf (mess, "Файл скопирован: \"PicViewer\\%s\"", pF [pFn]);
messPrintP ();
}
else
{
sprintf (mess, "Ошибка при копировании файла");
messPrintP ();
}
}
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nFunsterStil)
{
gThisInstance=hThisInstance;
gFunsterStil=nFunsterStil;
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup (&gdiplusToken, &gdiplusStartupInput, NULL);
wincl.hInstance=hThisInstance;
wincl.lpszClassName=szClassName;
wincl.lpfnWndProc=WindowProcedure; wincl.style=CS_DBLCLKS; wincl.cbSize=sizeof (WNDCLASSEX);
wincl.hIcon=LoadIcon (hThisInstance, MAKEINTRESOURCE(ID_PIC));
wincl.hIconSm=LoadIcon (hThisInstance, MAKEINTRESOURCE(ID_PIC));
wincl.hCursor=LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName=NULL; wincl.cbClsExtra=0; wincl.cbWndExtra=0; wincl.hbrBackground=bg;
if (!RegisterClassEx (&wincl))
return 0;
screenSet ();
hwnd = CreateWindowEx (
0, szClassName, title, WS_POPUP,
-1,
-1,
cx+2, cy+2, HWND_DESKTOP, NULL, gThisInstance, NULL );
ShowWindow (hwnd, gFunsterStil);
SetTimer (hwnd, TIMER_CUR, 500, NULL);
int i, c=0;
bool qt2=false;
memset (url, 0, _MAX_PATH);
for (c=0; c<_MAX_PATH; c++)
{
if (lpszArgument [c]==34)
qt2=true;
else if (lpszArgument [c]==0)
break;
}
if (c>2)
{
if (qt2==true)
{
for (i=0; i<c-2; i++)
url [i]=lpszArgument [i+1];
url_l=c-2;
}
else
{
for (i=0; i<c; i++)
url [i]=lpszArgument [i];
url_l=c;
}
}
if (strlen (url)>3)
picture (true);
else
{
infoOn=1;
info ();
}
char pFile [256];
int pD_l=0;
memset (pDir, 0, _MAX_PATH);
memset (pFile, 0, 256);
for (i=url_l-1; i>=0 && pD_l==0; i--)
{
if (url [i]=='\\')
pD_l=i+1;
}
memcpy (pDir, url, pD_l);
for (i=pD_l; i<url_l; i++)
pFile [i-pD_l]=url [i];
char pExt [] [5]={"gif", "jpg", "jpeg", "jpe", "jfif", "png", "tif", "tiff", "ico", "bmp"};
WIN32_FIND_DATA FindFileData;
HANDLE hf;
char pPath [_MAX_PATH];
memset (pPath, 0, _MAX_PATH);
sprintf (pPath, "%s%s", pDir, "*.*");
hf=FindFirstFile (pPath, &FindFileData);
if (hf!=INVALID_HANDLE_VALUE)
{
i=0;
int i2, l=0, l2;
while (true)
{
if (FindFileData.dwFileAttributes!=FILE_ATTRIBUTE_DIRECTORY)
{
l=strlen (FindFileData.cFileName);
if (!strcmp (FindFileData.cFileName, pFile))
{
pFn=pFc;
sprintf (pF [pFc], "%s", FindFileData.cFileName);
pFc++;
}
else
{
for (i=0; i<sizeof (pExt)/5; i++)
{
l2=strlen (pExt [i]);
c=0;
for (i2=0; i2<l2; i2++)
{
if (FindFileData.cFileName [l-l2+i2]==pExt [i] [i2] || FindFileData.cFileName [l-l2+i2]==toupper (pExt [i] [i2]))
c++;
}
if (c==l2)
{
sprintf (pF [pFc], "%s", FindFileData.cFileName);
pFc++;
}
}
}
}
if (FindNextFile(hf, &FindFileData)==0 || pFc>=50000-1)
break;
}
}
while (GetMessage (&messages, NULL, 0, 0))
{
TranslateMessage (&messages);
DispatchMessage (&messages);
}
return messages.wParam;
}
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_KEYDOWN:
if (hideCur>=10)
{
ShowCursor (false);
hideCur=0;
}
if (infoOn>1)
{
infoOn=0;
picture ();
break;
}
if (slide==true)
{
KillTimer (hwnd, TIMER_SLIDE);
slide=false;
sprintf (mess, "Слайд-шоу выключено");
messPrintP ();
break;
}
if (messOn==true)
{
KillTimer (hwnd, TIMER_MESS);
messOn=false;
picture ();
break;
}
if (wParam==VK_ESCAPE)
{
Gdiplus::GdiplusShutdown (gdiplusToken);
PostQuitMessage (0); break;
}
else if (infoOn==1)
break;
if (wParam==VK_F1 || wParam==72)
{
if (infoOn==0)
{
infoOn=2;
info ();
}
}
switch (wParam)
{
case 73:
if (infoOn==0)
{
infoOn=3;
info ();
}
break;
case 67:
copyPic ();
break;
case VK_CONTROL:
ctrl=true;
break;
case VK_SHIFT:
shift=true;
break;
case VK_LEFT:
if (shift==true)
{
if (pl+pla<0 && px>0)
{
pla+=shiftStep;
if (pl+pla>0)
pla=-pl;
picture ();
}
}
else if (((pFn>0 || pFn==-1) && pFc>0 && ctrl==false) || (pFn>pFc/25-1 && pFc>100 && ctrl==true))
{
pla=0;
pta=0;
infoOn=0;
if (ctrl==true)
pFn-=pFc/25;
else if (pFn==-1)
pFn=0;
else
pFn--;
memset (url, 0, _MAX_PATH);
sprintf (url, "%s%s", pDir, pF [pFn]);
picture (true);
}
break;
case VK_RIGHT:
if (shift==true)
{
if (pl+pla+pxs>cx && px>0)
{
pla-=shiftStep;
if (pl+pla+pxs<cx)
pla=cx-(pl+pxs);
picture ();
}
}
else if ((pFn<pFc-1 && ctrl==false) || (pFn<pFc-pFc/25-1 && pFc>100 && ctrl==true))
{
pla=0;
pta=0;
infoOn=0;
if (ctrl==true)
pFn+=pFc/25;
else
pFn++;
memset (url, 0, _MAX_PATH);
sprintf (url, "%s%s", pDir, pF [pFn]);
picture (true);
}
break;
case VK_UP:
if (shift==true)
{
if (pt+pta<0 && px>0)
{
pta+=shiftStep;
if (pt+pta>0)
pta=-pt;
picture ();
}
}
break;
case VK_DOWN:
if (shift==true)
{
if (pt+pta+pys>cy && px>0)
{
pta-=shiftStep;
if (pt+pta+pys<cy)
pta=cy-(pt+pys);
picture ();
}
}
break;
case VK_HOME:
if ((pFn>0 || pFn==-1) && pFc>0 && ctrl)
{
pla=0;
pta=0;
infoOn=0;
pFn=0;
memset (url, 0, _MAX_PATH);
sprintf (url, "%s%s", pDir, pF [pFn]);
picture (true);
}
break;
case VK_END:
if (pFn<pFc-1 && ctrl)
{
pla=0;
pta=0;
infoOn=0;
pFn=pFc-1;
memset (url, 0, _MAX_PATH);
sprintf (url, "%s%s", pDir, pF [pFn]);
picture (true);
}
break;
case VK_RETURN:
if (pFc>1)
{
pla=0;
pta=0;
infoOn=0;
sprintf (mess, "Включено слайд-шоу");
messPrint ();
slide=true;
SetTimer (hwnd, TIMER_SLIDE, 5000, NULL);
}
else
{
sprintf (mess, "Недостаточно изображений");
messPrint ();
messOn=true;
SetTimer (hwnd, TIMER_MESS, 2500, NULL);
}
break;
case VK_SPACE:
if (full==false)
full=true;
else if (full==true)
full=false;
if (px>cx || py>cy)
{
pla=0;
pta=0;
picture ();
}
break;
}
if ((wParam==VK_UP || wParam==188) && shift==false && px>0)
{
pla=0;
pta=0;
imagesH->RotateFlip (Gdiplus::Rotate270FlipNone);
int t=px;
px=py;
py=t;
picture ();
}
if ((wParam==VK_DOWN || wParam==190) && shift==false && px>0)
{
pla=0;
pta=0;
imagesH->RotateFlip (Gdiplus::Rotate90FlipNone);
int t=px;
px=py;
py=t;
picture ();
}
if (wParam==107 || wParam==187)
{
if (stepN<7 && px>0 && !(full==false && (px>cx || py>cy)))
{
pla=0;
pta=0;
stepN++;
picture ();
}
}
if (wParam==109 || wParam==189)
{
if (stepN>0 && px>0 && !(full==false && (px>cx || py>cy)))
{
pla=0;
pta=0;
stepN--;
picture ();
}
}
break;
case WM_KEYUP:
switch (wParam)
{
case VK_CONTROL:
ctrl=false;
break;
case VK_SHIFT:
shift=false;
break;
}
break;
case WM_TIMER:
switch (wParam)
{
case TIMER_SLIDE:
if (pFn<pFc-1)
pFn++;
else
pFn=0;
memset (url, 0, _MAX_PATH);
sprintf (url, "%s%s", pDir, pF [pFn]);
picture (true);
break;
case TIMER_MESS:
KillTimer (hwnd, TIMER_MESS);
messOn=false;
picture ();
break;
case TIMER_CUR:
KillTimer (hwnd, TIMER_CUR);
GetCursorPos (&mypoint);
SetCursorPos (mypoint.x, mypoint.y);
ShowCursor (false);
break;
}
break;
case WM_SIZE:
switch (wParam)
{
case SIZE_RESTORED:
if (noRest==true)
break;
if (load==false)
{
screenSet ();
screenUp ();
}
break;
}
break;
case WM_MOUSEMOVE:
hideCur++;
if (hideCur==10)
ShowCursor (true);
break;
case WM_KILLFOCUS:
blur_on=true;
break;
case WM_SETFOCUS:
blur_on=false;
break;
case WM_PAINT:
BeginPaint (hwnd, &PaintStruct);
if (!load)
{
if (infoOn!=0)
info ();
else
picture ();
}
else
load=false;
EndPaint (hwnd, &PaintStruct);
break;
case WM_DESTROY:
Gdiplus::GdiplusShutdown (gdiplusToken);
PostQuitMessage (0); break;
default: return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}