Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

810 lines
20 KiB

  1. //
  2. // Simple test program for imaging library
  3. //
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <stdarg.h>
  7. #include <windows.h>
  8. #include <objbase.h>
  9. #include <urlmon.h>
  10. #include <commdlg.h>
  11. #include <math.h>
  12. #include <gdiplus.h>
  13. #include <gdiplusflat.h>
  14. using namespace Gdiplus;
  15. #include "../gpinit.inc"
  16. #define k_DefaultWidth 720
  17. #define k_DefaultHeight 480
  18. #define THUMBSIZE 120
  19. #define MAX_FILENAME 1000
  20. CHAR* g_pcProgramName = NULL; // program name
  21. HINSTANCE g_hAppInstance; // handle to the application instance
  22. HWND g_hwndMain; // handle to application's main window
  23. int g_iTotalNumOfImages;
  24. int lastS;
  25. int numX;
  26. int g_iNumFileNames;
  27. Image** g_ppThumbImages;
  28. CHAR** g_ppcInputFilenames;
  29. RECT g_ThumbRect;
  30. BOOL g_fVerbose = FALSE;
  31. BOOL g_fHighQualityThumb = FALSE;
  32. #define ERREXIT(args) { printf args; exit(-1); }
  33. #define VERBOSE(args) printf args
  34. //
  35. // Helper class to convert ANSI strings to Unicode strings
  36. //
  37. inline BOOL
  38. UnicodeToAnsiStr(
  39. const WCHAR* unicodeStr,
  40. CHAR* ansiStr,
  41. INT ansiSize
  42. )
  43. {
  44. return WideCharToMultiByte(CP_ACP, 0, unicodeStr, -1, ansiStr, ansiSize,
  45. NULL, NULL) > 0;
  46. }
  47. inline BOOL
  48. AnsiToUnicodeStr(
  49. const CHAR* ansiStr,
  50. WCHAR* unicodeStr,
  51. INT unicodeSize
  52. )
  53. {
  54. return MultiByteToWideChar(CP_ACP, 0, ansiStr, -1, unicodeStr,
  55. unicodeSize) > 0;
  56. }
  57. class UnicodeStrFromAnsi
  58. {
  59. public:
  60. UnicodeStrFromAnsi(const CHAR* ansiStr)
  61. {
  62. if (ansiStr == NULL)
  63. {
  64. valid = TRUE;
  65. unicodeStr = NULL;
  66. }
  67. else
  68. {
  69. // NOTE: we only handle strings with length < MAX_PATH.
  70. valid = AnsiToUnicodeStr(ansiStr, buf, MAX_PATH);
  71. unicodeStr = valid ? buf : NULL;
  72. }
  73. }
  74. BOOL IsValid() const
  75. {
  76. return valid;
  77. }
  78. operator WCHAR*()
  79. {
  80. return unicodeStr;
  81. }
  82. private:
  83. BOOL valid;
  84. WCHAR* unicodeStr;
  85. WCHAR buf[MAX_PATH];
  86. };
  87. //
  88. // Create thumbnails for the specified list of files
  89. //
  90. VOID
  91. DrawThumbnails(
  92. const RECT rect,
  93. HDC hdc
  94. )
  95. {
  96. if ( (rect.bottom - rect.top <= 0) || (rect.right - rect.left <= 0) )
  97. {
  98. return;
  99. }
  100. // Figure out how many rows and columns we need to divide in order to put
  101. // "g_iTotalNumOfImages" images within the fixed size "rect"
  102. // Basically "iNumColumns" * "iNumRows" should >= "g_iTotalNumOfImages"
  103. int iWindowWidth = rect.right - rect.left;
  104. int iWindowHeight = rect.bottom - rect.top;
  105. int iSum = 1;
  106. while ( ((iWindowWidth / iSum) * (iWindowHeight / iSum))
  107. >= g_iTotalNumOfImages )
  108. {
  109. iSum++;
  110. }
  111. iSum--;
  112. int iNumColumns = iWindowWidth / iSum;
  113. int iNumRows = iWindowHeight / iSum;
  114. lastS = iSum; // Reset the global
  115. numX = iNumColumns; // Reset the global
  116. Graphics* pGraphics = new Graphics(g_hwndMain);
  117. int x = 0;
  118. int y = 0;
  119. for ( int i = 0; i < g_iTotalNumOfImages; i++ )
  120. {
  121. if ( NULL == g_ppThumbImages[i] )
  122. {
  123. // Bad image. But we still leave the position for it so that it can
  124. // be easily noticed
  125. x++;
  126. if (x >= iNumColumns)
  127. {
  128. x = 0;
  129. y++;
  130. }
  131. continue;
  132. }
  133. // Copy thumbnail bitmap image data to offscreen memory DC
  134. int tx;
  135. int ty;
  136. SizeF size;
  137. g_ppThumbImages[i]->GetPhysicalDimension(&size);
  138. float dAspect = size.Width / size.Height;
  139. RECT r;
  140. if ( dAspect > 1 )
  141. {
  142. tx = iSum;
  143. ty = (int)(iSum / dAspect);
  144. int d = (iSum - ty) / 2;
  145. r.left = x * iSum;
  146. r.top = y * iSum + d;
  147. r.right = x * iSum + tx;
  148. r.bottom = y * iSum + ty + d;
  149. }
  150. else
  151. {
  152. ty = iSum;
  153. tx = (int)(iSum * dAspect);
  154. int d = (iSum - tx) / 2;
  155. r.left = x * iSum + d;
  156. r.top = y * iSum;
  157. r.right = x * iSum + tx + d;
  158. r.bottom = y * iSum + ty;
  159. }
  160. if ( g_fHighQualityThumb == FALSE )
  161. {
  162. Rect dstRect(r.left, r.top, tx, ty);
  163. pGraphics->DrawImage(g_ppThumbImages[i],
  164. dstRect,
  165. 0,
  166. 0,
  167. (UINT)g_ppThumbImages[i]->GetWidth(),
  168. (UINT)g_ppThumbImages[i]->GetHeight(),
  169. UnitPixel,
  170. NULL,
  171. NULL,
  172. NULL);
  173. }
  174. else
  175. {
  176. // Generate high quality thumbnail based on required size
  177. Bitmap* dstBmp = new Bitmap(tx, ty, PixelFormat32bppPARGB);
  178. Graphics* gdst = new Graphics(dstBmp);
  179. // Ask the source image for it's size.
  180. int width = g_ppThumbImages[i]->GetWidth();
  181. int height = g_ppThumbImages[i]->GetHeight();
  182. // Compute the optimal scale factor without changing the aspect ratio
  183. float scalex = (float)width / tx;
  184. float scaley = (float)height / ty;
  185. float scale = min(scalex, scaley);
  186. Rect dstRect(0, 0, tx, ty);
  187. // Set the resampling quality to the bicubic filter
  188. gdst->SetInterpolationMode(InterpolationModeHighQualityBicubic);
  189. // Set the compositing quality to copy source pixels rather than
  190. // alpha blending. This will preserve any alpha in the source image.
  191. gdst->SetCompositingMode(CompositingModeSourceCopy);
  192. ImageAttributes imgAttr;
  193. imgAttr.SetWrapMode(WrapModeTileFlipXY);
  194. // Draw the source image onto the destination with the correct scale
  195. // and quality settings.
  196. GpStatus status = gdst->DrawImage(g_ppThumbImages[i],
  197. dstRect,
  198. 0,
  199. 0,
  200. INT((tx * scale) + 0.5),
  201. INT((ty * scale) + 0.5),
  202. UnitPixel,
  203. &imgAttr);
  204. if( status != Ok )
  205. {
  206. printf("Error drawing the image\n");
  207. continue;
  208. }
  209. // Draw the result onto the screen
  210. Rect drawDstRect(r.left, r.top, tx, ty);
  211. pGraphics->DrawImage(dstBmp,
  212. drawDstRect,
  213. 0,
  214. 0,
  215. (UINT)dstBmp->GetWidth(),
  216. (UINT)dstBmp->GetHeight(),
  217. UnitPixel,
  218. NULL,
  219. NULL,
  220. NULL);
  221. delete dstBmp;
  222. delete gdst;
  223. }
  224. x++;
  225. if (x >= iNumColumns)
  226. {
  227. x = 0;
  228. y++;
  229. }
  230. }// Loop through all the thumbnail images to draw
  231. delete pGraphics;
  232. }
  233. //
  234. // Handle window repaint event
  235. //
  236. VOID
  237. DoPaint(
  238. HWND hwnd
  239. )
  240. {
  241. HDC hdc;
  242. PAINTSTRUCT ps;
  243. RECT rect;
  244. hdc = BeginPaint(hwnd, &ps);
  245. GetClientRect(hwnd, &rect);
  246. const RECT r = {rect.left, rect.top, rect.right, rect.bottom};
  247. DrawThumbnails(r, hdc);
  248. EndPaint(hwnd, &ps);
  249. }// DoPaint()
  250. //
  251. // Window callback procedure
  252. //
  253. LRESULT CALLBACK
  254. MyWindowProc(
  255. HWND hwnd,
  256. UINT uMsg,
  257. WPARAM wParam,
  258. LPARAM lParam
  259. )
  260. {
  261. int index=0;
  262. switch (uMsg)
  263. {
  264. case WM_PAINT:
  265. DoPaint(hwnd);
  266. break;
  267. case WM_DESTROY:
  268. PostQuitMessage(0);
  269. break;
  270. case WM_LBUTTONDBLCLK:
  271. if (lastS == 0)
  272. {
  273. lastS = 1;
  274. }
  275. index = (HIWORD(lParam) / lastS) * numX + (LOWORD(lParam) / lastS);
  276. if (index < g_iNumFileNames)
  277. {
  278. char cmdLine[MAX_FILENAME];
  279. strcpy(cmdLine, "frametest ");
  280. strcat(cmdLine, g_ppcInputFilenames[index]);
  281. WinExec(cmdLine, SW_SHOWNORMAL);
  282. }
  283. break;
  284. case WM_SIZE:
  285. SendMessage(g_hwndMain, WM_ERASEBKGND, WPARAM(GetDC(g_hwndMain)), NULL);
  286. InvalidateRect(g_hwndMain, NULL, FALSE);
  287. break;
  288. default:
  289. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  290. }
  291. return 0;
  292. }
  293. //
  294. // Create main application window
  295. //
  296. #define MYWNDCLASSNAME "ThumbTst"
  297. VOID
  298. CreateMainWindow(
  299. VOID
  300. )
  301. {
  302. // Use a hatch brush as background so that we can get transparent info
  303. // from the source image
  304. HBRUSH hBrush = CreateHatchBrush(HS_HORIZONTAL,
  305. RGB(0, 200, 0));
  306. // Register window class
  307. WNDCLASS wndClass =
  308. {
  309. CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS,
  310. MyWindowProc,
  311. 0,
  312. 0,
  313. g_hAppInstance,
  314. LoadIcon(NULL, IDI_APPLICATION),
  315. LoadCursor(NULL, IDC_ARROW),
  316. hBrush,
  317. NULL,
  318. MYWNDCLASSNAME
  319. };
  320. RegisterClass(&wndClass);
  321. // Calculate default window size
  322. INT iWidth = g_ThumbRect.right + 2 * GetSystemMetrics(SM_CXFRAME);
  323. INT iHeight = g_ThumbRect.bottom
  324. + 2 * GetSystemMetrics(SM_CYFRAME)
  325. + GetSystemMetrics(SM_CYCAPTION);
  326. // Create application window
  327. g_hwndMain = CreateWindow(MYWNDCLASSNAME,
  328. MYWNDCLASSNAME,
  329. WS_OVERLAPPEDWINDOW | WS_VISIBLE,
  330. CW_USEDEFAULT,
  331. CW_USEDEFAULT,
  332. iWidth,
  333. iHeight,
  334. NULL,
  335. NULL,
  336. g_hAppInstance,
  337. NULL);
  338. }// CreateMainWindow()
  339. void
  340. DisplayImageInfo(
  341. Image* pImage
  342. )
  343. {
  344. UINT uiImagePixelFormat = pImage->GetPixelFormat();
  345. UINT uiImageFlags = pImage->GetFlags();
  346. VERBOSE(("Width = %d\n", pImage->GetWidth()));
  347. VERBOSE(("Width = %d\n", pImage->GetHeight()));
  348. // Pixel format
  349. switch ( uiImagePixelFormat )
  350. {
  351. case PixelFormat1bppIndexed:
  352. VERBOSE(("Color depth: 1 BPP INDEXED\n"));
  353. break;
  354. case PixelFormat4bppIndexed:
  355. VERBOSE(("Color depth: 4 BPP INDEXED\n"));
  356. break;
  357. case PixelFormat8bppIndexed:
  358. VERBOSE(("Color depth: 8 BPP INDEXED\n"));
  359. break;
  360. case PixelFormat16bppGrayScale:
  361. VERBOSE(("Color depth: 16 BPP GRAY SCALE\n"));
  362. break;
  363. case PixelFormat16bppRGB555:
  364. VERBOSE(("Color depth: 16 BPP RGB 555\n"));
  365. break;
  366. case PixelFormat16bppRGB565:
  367. VERBOSE(("Color depth: 16 BPP RGB 565\n"));
  368. break;
  369. case PixelFormat16bppARGB1555:
  370. VERBOSE(("Color depth: 16 BPP ARGB 1555\n"));
  371. break;
  372. case PixelFormat24bppRGB:
  373. VERBOSE(("Color depth: 24 BPP RGB\n"));
  374. break;
  375. case PixelFormat32bppARGB:
  376. VERBOSE(("Color depth: 32 BPP ARGB\n"));
  377. break;
  378. case PixelFormat32bppPARGB:
  379. VERBOSE(("Color depth: 32 BPP PARGB\n"));
  380. break;
  381. case PixelFormat48bppRGB:
  382. VERBOSE(("Color depth: 48 BPP PARGB\n"));
  383. case PixelFormat64bppARGB:
  384. VERBOSE(("Color depth: 64 BPP ARGB\n"));
  385. break;
  386. case PixelFormat64bppPARGB:
  387. VERBOSE(("Color depth: 64 BPP PARGB\n"));
  388. break;
  389. default:
  390. VERBOSE(("Unknown color depth\n"));
  391. break;
  392. }// Color format
  393. // Physical dimension info
  394. VERBOSE(("X DPI (dots per inch) = %f\n",pImage->GetHorizontalResolution()));
  395. VERBOSE(("Y DPI (dots per inch) = %f\n",pImage->GetVerticalResolution()));
  396. // Pixel size
  397. if ( uiImageFlags & ImageFlagsHasRealPixelSize )
  398. {
  399. VERBOSE(("---The pixel size info is from the original image\n"));
  400. }
  401. else
  402. {
  403. VERBOSE(("---The pixel size info is NOT from the original image\n"));
  404. }
  405. // DPI info
  406. if ( uiImageFlags & ImageFlagsHasRealPixelSize )
  407. {
  408. VERBOSE(("---The pixel size info is from the original image\n"));
  409. }
  410. else
  411. {
  412. VERBOSE(("---The pixel size info is NOT from the original image\n"));
  413. }
  414. // Transparency info
  415. if ( uiImageFlags & ImageFlagsHasAlpha )
  416. {
  417. VERBOSE(("This image contains alpha pixels\n"));
  418. if ( uiImageFlags & ImageFlagsHasTranslucent )
  419. {
  420. VERBOSE(("---It has non-0 and 1 alpha pixels (TRANSLUCENT)\n"));
  421. }
  422. }
  423. else
  424. {
  425. VERBOSE(("This image does not contain alpha pixels\n"));
  426. }
  427. // Display color space
  428. if ( uiImageFlags & ImageFlagsColorSpaceRGB )
  429. {
  430. VERBOSE(("This image is in RGB color space\n"));
  431. }
  432. else if ( uiImageFlags & ImageFlagsColorSpaceCMYK )
  433. {
  434. VERBOSE(("This image is in CMYK color space\n"));
  435. }
  436. else if ( uiImageFlags & ImageFlagsColorSpaceGRAY )
  437. {
  438. VERBOSE(("This image is a gray scale image\n"));
  439. }
  440. else if ( uiImageFlags & ImageFlagsColorSpaceYCCK )
  441. {
  442. VERBOSE(("This image is in YCCK color space\n"));
  443. }
  444. else if ( uiImageFlags & ImageFlagsColorSpaceYCBCR )
  445. {
  446. VERBOSE(("This image is in YCBCR color space\n"));
  447. }
  448. }// DisplayImageInfo()
  449. //
  450. // Create thumbnails for the specified list of files
  451. //
  452. VOID
  453. CreateThumbnails(
  454. CHAR** ppcFilenames
  455. )
  456. {
  457. // Generate thumbnails
  458. UINT uiTimer;
  459. if ( g_fVerbose == TRUE )
  460. {
  461. uiTimer = GetTickCount();
  462. }
  463. g_ppThumbImages = new Image*[g_iTotalNumOfImages];
  464. Image* pSrcImage = NULL;
  465. // Loop through all the images and generate thumbnail
  466. for ( int i = 0; i < g_iTotalNumOfImages; i++ )
  467. {
  468. g_ppThumbImages[i] = NULL;
  469. // Get a Unicode file name
  470. UnicodeStrFromAnsi namestr(ppcFilenames[i]);
  471. VERBOSE(("Loading - %s\n", ppcFilenames[i]));
  472. if ( namestr.IsValid() == FALSE )
  473. {
  474. VERBOSE(("Couldn't open image file: %s\n", ppcFilenames[i]));
  475. continue;
  476. }
  477. else if ( g_fHighQualityThumb == FALSE )
  478. {
  479. pSrcImage = new Image(namestr, TRUE);
  480. if ( (pSrcImage == NULL) || (pSrcImage->GetLastStatus() != Ok) )
  481. {
  482. VERBOSE(("Couldn't open image file: %s\n", ppcFilenames[i]));
  483. if ( pSrcImage != NULL )
  484. {
  485. delete pSrcImage;
  486. pSrcImage = NULL;
  487. }
  488. continue;
  489. }
  490. if ( g_fVerbose == TRUE )
  491. {
  492. DisplayImageInfo(pSrcImage);
  493. }
  494. // Get build in thumbnail image if there is one. Otherwise, GDI+
  495. // will generate one for us
  496. g_ppThumbImages[i] = pSrcImage->GetThumbnailImage(0, 0, NULL, NULL);
  497. delete pSrcImage;
  498. pSrcImage = NULL;
  499. }
  500. else
  501. {
  502. // High quality thumbnail images. We don't generate it here
  503. g_ppThumbImages[i] = new Image(namestr, TRUE);
  504. if ( g_ppThumbImages[i] == NULL )
  505. {
  506. VERBOSE(("Couldn't open image file: %s\n", ppcFilenames[i]));
  507. continue;
  508. }
  509. if ( g_fVerbose == TRUE )
  510. {
  511. DisplayImageInfo(g_ppThumbImages[i]);
  512. }
  513. }
  514. }// Loop through all the images
  515. if ( g_fVerbose == TRUE )
  516. {
  517. uiTimer = GetTickCount() - uiTimer;
  518. VERBOSE(("Generate %d thumbnails in %dmsec\n", g_iTotalNumOfImages,
  519. uiTimer));
  520. }
  521. }// CreateThumbnails
  522. void
  523. USAGE()
  524. {
  525. printf("******************************************************\n");
  526. printf("Usage: thumbtst [-?] [-v] ImageFileNames\n");
  527. printf("-v Verbose image information output\n");
  528. printf("-h Generate higher quality thumbnail\n");
  529. printf("-? Print this usage message\n");
  530. printf("ImageFileNames Files to be opened\n\n");
  531. printf("Sample usage:\n");
  532. char myChar = '\\';
  533. printf(" thumbtst.exe c:%cpublic%c*.jpg\n", myChar, myChar);
  534. }// USAGE()
  535. char html_header[1024] = "<html>\n<head>\n <title>My Fun Photo Album</title>\n</head>\n</html>\0";
  536. void
  537. OutputHTML()
  538. {
  539. FILE* hFile = fopen("mytest.html", "w");
  540. if ( hFile == NULL )
  541. {
  542. return;
  543. }
  544. fprintf(hFile, "%s", html_header);
  545. fclose(hFile);
  546. }// OutputHTML()
  547. void
  548. ValidateArguments(
  549. int argc,
  550. char* argv[]
  551. )
  552. {
  553. g_pcProgramName = *argv++;
  554. argc--;
  555. g_hAppInstance = GetModuleHandle(NULL);
  556. while ( argc > 0 )
  557. {
  558. if ( strcmp(*argv, "-v") == 0 )
  559. {
  560. argc--;
  561. argv++;
  562. g_fVerbose = TRUE;
  563. }
  564. else if ( strcmp(*argv, "-h") == 0 )
  565. {
  566. argc--;
  567. argv++;
  568. g_fHighQualityThumb = TRUE;
  569. }
  570. else if ( strcmp(*argv, "-?") == 0 )
  571. {
  572. USAGE();
  573. exit(1);
  574. }
  575. else
  576. {
  577. // Get the pointer to image file list
  578. g_ppcInputFilenames = argv;
  579. g_iNumFileNames = argc;
  580. // Total number of images
  581. // Note: if you do "thumbtst.exe c:\temp\*.jpg", this argc is
  582. // actually the total number of images in that dir. While in argv,
  583. // it points to each image under that dir
  584. g_iTotalNumOfImages = argc;
  585. return;
  586. }
  587. }// while (argc > 0 )
  588. if ( argc == 0 )
  589. {
  590. USAGE();
  591. exit(1);
  592. }
  593. return;
  594. }// ValidateArguments()
  595. //
  596. // Main program entrypoint
  597. //
  598. INT _cdecl
  599. main(
  600. INT argc,
  601. CHAR** argv
  602. )
  603. {
  604. ValidateArguments(argc, argv);
  605. g_ThumbRect.left = 0;
  606. g_ThumbRect.top = 0;
  607. g_ThumbRect.right = k_DefaultWidth;
  608. g_ThumbRect.bottom = k_DefaultHeight;
  609. // Generate thumbnail images and store it in g_ppThumbImages
  610. CreateThumbnails(g_ppcInputFilenames);
  611. // Create the main application window
  612. CreateMainWindow();
  613. // OutputHTML();
  614. // Main message loop
  615. MSG msg;
  616. while (GetMessage(&msg, NULL, 0, 0))
  617. {
  618. TranslateMessage(&msg);
  619. DispatchMessage(&msg);
  620. }
  621. // Clean up
  622. // Note: above while loop won't finish until we don't have any messages
  623. for ( int i = 0; i < g_iTotalNumOfImages; i++ )
  624. {
  625. if ( NULL != g_ppThumbImages[i] )
  626. {
  627. delete g_ppThumbImages[i];
  628. }
  629. }
  630. delete [] g_ppThumbImages;
  631. return (INT)(msg.wParam);
  632. }// main()