dwimg.c 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654
  1. /* Copyright (C) 1996-2004 Ghostgum Software Pty Ltd. All rights reserved.
  2. This software is provided AS-IS with no warranty, either express or
  3. implied.
  4. This software is distributed under license and may not be copied,
  5. modified or distributed except as expressly authorized under the terms
  6. of the license contained in the file LICENSE in this distribution.
  7. For more information about licensing, please refer to
  8. http://www.ghostscript.com/licensing/. For information on
  9. commercial licensing, go to http://www.artifex.com/licensing/ or
  10. contact Artifex Software, Inc., 101 Lucas Valley Road #110,
  11. San Rafael, CA 94903, U.S.A., +1(415)492-9861.
  12. */
  13. /* $Id: dwimg.c,v 1.17 2004/10/28 09:26:11 igor Exp $ */
  14. /* display device image window for Windows */
  15. /* This code supports both single threaded and multithreaded operation */
  16. /* For multithread, access is shared as follows:
  17. * Each image has a Mutex img->hmutex, used for protected access to
  18. * the img->image and its dimensions.
  19. * Main thread can access
  20. * image_find()
  21. * image_new()
  22. * image_delete()
  23. * image_size()
  24. * Main thread must acquire mutex on display_presize() and release
  25. * in display_size() after image_size() is called.
  26. * Main thread must acquire mutex on display_preclose().
  27. *
  28. * Second thread must not access image_find, image_new, image_delete
  29. * or image_size. It must grab mutex before accessing img->image.
  30. */
  31. #define STRICT
  32. #include <windows.h>
  33. #include "stdio_.h"
  34. #include "iapi.h"
  35. #include "dwmain.h"
  36. #include "dwimg.h"
  37. #include "dwreg.h"
  38. #include "gdevdsp.h"
  39. static const char szImgName2[] = "Ghostscript Image";
  40. static const char szTrcName2[] = "Ghostscript Graphical Trace";
  41. /* Forward references */
  42. LRESULT CALLBACK WndImg2Proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
  43. static void register_class(void);
  44. static void draw(IMAGE *img, HDC hdc, int dx, int dy, int wx, int wy,
  45. int sx, int sy);
  46. static HGLOBAL copy_dib(IMAGE *img);
  47. static HPALETTE create_palette(IMAGE *img);
  48. static void create_window(IMAGE *img);
  49. #define M_COPY_CLIP 1
  50. #define M_DEVICEN_GRAY 2 /* show single separation as gray */
  51. #define M_SEPARATION 3 /* 3 to 3+IMG_DEVICEN_MAX-1 */
  52. #define DISPLAY_ERROR (-1) /* return this to Ghostscript on error */
  53. /* Define min and max, but make sure to use the identical definition */
  54. /* to the one that all the compilers seem to have.... */
  55. #ifndef min
  56. # define min(a, b) (((a) < (b)) ? (a) : (b))
  57. #endif
  58. #ifndef max
  59. # define max(a, b) (((a) > (b)) ? (a) : (b))
  60. #endif
  61. /* GUI thread only */
  62. void image_color(unsigned int format, int index,
  63. unsigned char *r, unsigned char *g, unsigned char *b);
  64. void image_convert_line(IMAGE *img, unsigned char *dest, unsigned char *source);
  65. void image_16BGR555_to_24BGR(int width, unsigned char *dest,
  66. unsigned char *source);
  67. void image_16BGR565_to_24BGR(int width, unsigned char *dest,
  68. unsigned char *source);
  69. void image_16RGB555_to_24BGR(int width, unsigned char *dest,
  70. unsigned char *source);
  71. void image_16RGB565_to_24BGR(int width, unsigned char *dest,
  72. unsigned char *source);
  73. void image_4CMYK_to_24BGR(int width, unsigned char *dest,
  74. unsigned char *source, IMAGE_DEVICEN *devicen, int devicen_gray);
  75. void image_32CMYK_to_24BGR(int width, unsigned char *dest,
  76. unsigned char *source, IMAGE_DEVICEN *devicen, int devicen_gray);
  77. void image_devicen_to_24BGR(int width, unsigned char *dest,
  78. unsigned char *source, IMAGE_DEVICEN *devicen, int devicen_gray);
  79. /****************************************************************/
  80. /* These functions are only accessed by the main thread */
  81. IMAGE *first_image = NULL;
  82. /* image_find must only be accessed by main thread */
  83. /* valid for main thread */
  84. IMAGE *
  85. image_find(void *handle, void *device)
  86. {
  87. IMAGE *img;
  88. for (img = first_image; img!=0; img=img->next) {
  89. if ((img->handle == handle) && (img->device == device))
  90. return img;
  91. }
  92. return NULL;
  93. }
  94. /* image_find must only be accessed by main thread */
  95. /* valid for main thread */
  96. IMAGE *
  97. image_new(void *handle, void *device)
  98. {
  99. IMAGE *img = (IMAGE *)malloc(sizeof(IMAGE));
  100. if (img) {
  101. memset(img, 0, sizeof(IMAGE));
  102. /* remember device and handle */
  103. img->handle = handle;
  104. img->device = device;
  105. img->update_tick = 100; /* milliseconds */
  106. img->update_interval = 1; /* 1 tick */
  107. img->update_count = 0;
  108. img->hmutex = INVALID_HANDLE_VALUE;
  109. /* add to list */
  110. img->next = first_image;
  111. first_image = img;
  112. }
  113. return img;
  114. }
  115. /* remove image from linked list */
  116. /* valid for main thread */
  117. void
  118. image_delete(IMAGE *img)
  119. {
  120. /* remove from list */
  121. if (img == first_image) {
  122. first_image = img->next;
  123. }
  124. else {
  125. IMAGE *tmp;
  126. for (tmp = first_image; tmp!=0; tmp=tmp->next) {
  127. if (img == tmp->next)
  128. tmp->next = img->next;
  129. }
  130. }
  131. /* Note: img is freed by image_close, not image_delete */
  132. }
  133. /* resize image */
  134. /* valid for main thread */
  135. int
  136. image_size(IMAGE *img, int new_width, int new_height, int new_raster,
  137. unsigned int new_format, void *pimage)
  138. {
  139. int i;
  140. img->raster = new_raster;
  141. img->format = new_format;
  142. img->image = (unsigned char *)pimage;
  143. /* create a BMP header for the bitmap */
  144. img->bmih.biSize = sizeof(BITMAPINFOHEADER);
  145. img->bmih.biWidth = new_width;
  146. img->bmih.biHeight = new_height;
  147. img->bmih.biPlanes = 1;
  148. /* Reset separations */
  149. for (i=0; i<IMAGE_DEVICEN_MAX; i++) {
  150. img->devicen[i].used = 0;
  151. img->devicen[i].visible = 1;
  152. memset(img->devicen[i].name, 0, sizeof(img->devicen[i].name));
  153. img->devicen[i].cyan = 0;
  154. img->devicen[i].magenta = 0;
  155. img->devicen[i].yellow = 0;
  156. img->devicen[i].black = 0;
  157. }
  158. switch (img->format & DISPLAY_COLORS_MASK) {
  159. case DISPLAY_COLORS_NATIVE:
  160. switch (img->format & DISPLAY_DEPTH_MASK) {
  161. case DISPLAY_DEPTH_1:
  162. img->bmih.biBitCount = 1;
  163. img->bmih.biClrUsed = 2;
  164. img->bmih.biClrImportant = 2;
  165. break;
  166. case DISPLAY_DEPTH_4:
  167. /* Fixed color palette */
  168. img->bmih.biBitCount = 4;
  169. img->bmih.biClrUsed = 16;
  170. img->bmih.biClrImportant = 16;
  171. break;
  172. case DISPLAY_DEPTH_8:
  173. /* Fixed color palette */
  174. img->bmih.biBitCount = 8;
  175. img->bmih.biClrUsed = 96;
  176. img->bmih.biClrImportant = 96;
  177. break;
  178. case DISPLAY_DEPTH_16:
  179. /* RGB bitfields */
  180. /* Bit fields */
  181. if ((img->format & DISPLAY_ENDIAN_MASK)
  182. == DISPLAY_BIGENDIAN) {
  183. /* convert to 24BGR */
  184. img->bmih.biBitCount = 24;
  185. img->bmih.biClrUsed = 0;
  186. img->bmih.biClrImportant = 0;
  187. }
  188. else {
  189. img->bmih.biBitCount = 16;
  190. img->bmih.biClrUsed = 0;
  191. img->bmih.biClrImportant = 0;
  192. }
  193. break;
  194. default:
  195. return DISPLAY_ERROR;
  196. }
  197. break;
  198. case DISPLAY_COLORS_GRAY:
  199. switch (img->format & DISPLAY_DEPTH_MASK) {
  200. case DISPLAY_DEPTH_1:
  201. img->bmih.biBitCount = 1;
  202. img->bmih.biClrUsed = 2;
  203. img->bmih.biClrImportant = 2;
  204. break;
  205. case DISPLAY_DEPTH_4:
  206. /* Fixed gray palette */
  207. img->bmih.biBitCount = 4;
  208. img->bmih.biClrUsed = 16;
  209. img->bmih.biClrImportant = 16;
  210. break;
  211. case DISPLAY_DEPTH_8:
  212. /* Fixed gray palette */
  213. img->bmih.biBitCount = 8;
  214. img->bmih.biClrUsed = 256;
  215. img->bmih.biClrImportant = 256;
  216. break;
  217. default:
  218. return DISPLAY_ERROR;
  219. }
  220. break;
  221. case DISPLAY_COLORS_RGB:
  222. if ((img->format & DISPLAY_DEPTH_MASK) != DISPLAY_DEPTH_8)
  223. return DISPLAY_ERROR;
  224. if (((img->format & DISPLAY_ALPHA_MASK) == DISPLAY_UNUSED_LAST) &&
  225. ((img->format & DISPLAY_ENDIAN_MASK) == DISPLAY_LITTLEENDIAN)) {
  226. /* use bitfields to display this */
  227. img->bmih.biBitCount = 32;
  228. img->bmih.biClrUsed = 0;
  229. img->bmih.biClrImportant = 0;
  230. }
  231. else {
  232. /* either native BGR, or we need to convert it */
  233. img->bmih.biBitCount = 24;
  234. img->bmih.biClrUsed = 0;
  235. img->bmih.biClrImportant = 0;
  236. }
  237. break;
  238. case DISPLAY_COLORS_CMYK:
  239. switch (img->format & DISPLAY_DEPTH_MASK) {
  240. case DISPLAY_DEPTH_1:
  241. case DISPLAY_DEPTH_8:
  242. /* we can convert these formats */
  243. break;
  244. default:
  245. return DISPLAY_ERROR;
  246. }
  247. /* we can't display this natively */
  248. /* we will convert it just before displaying */
  249. img->bmih.biBitCount = 24;
  250. img->bmih.biClrUsed = 0;
  251. img->bmih.biClrImportant = 0;
  252. img->devicen[0].used = 1;
  253. img->devicen[0].cyan = 65535;
  254. /* We already know about the CMYK components */
  255. strncpy(img->devicen[0].name, "Cyan",
  256. sizeof(img->devicen[0].name));
  257. img->devicen[1].used = 1;
  258. img->devicen[1].magenta = 65535;
  259. strncpy(img->devicen[1].name, "Magenta",
  260. sizeof(img->devicen[1].name));
  261. img->devicen[2].used = 1;
  262. img->devicen[2].yellow = 65535;
  263. strncpy(img->devicen[2].name, "Yellow",
  264. sizeof(img->devicen[2].name));
  265. img->devicen[3].used = 1;
  266. img->devicen[3].black = 65535;
  267. strncpy(img->devicen[3].name, "Black",
  268. sizeof(img->devicen[3].name));
  269. break;
  270. case DISPLAY_COLORS_SEPARATION:
  271. /* we can't display this natively */
  272. /* we will convert it just before displaying */
  273. img->bmih.biBitCount = 24;
  274. img->bmih.biClrUsed = 0;
  275. img->bmih.biClrImportant = 0;
  276. break;
  277. }
  278. img->bmih.biCompression = 0;
  279. img->bmih.biSizeImage = 0;
  280. img->bmih.biXPelsPerMeter = 0;
  281. img->bmih.biYPelsPerMeter = 0;
  282. img->bytewidth = ((img->bmih.biWidth * img->bmih.biBitCount + 31 ) & ~31) >> 3;
  283. if (img->palette)
  284. DeleteObject(img->palette);
  285. img->palette = create_palette(img);
  286. return 0;
  287. }
  288. int
  289. image_separation(IMAGE *img,
  290. int comp_num, const char *name,
  291. unsigned short c, unsigned short m,
  292. unsigned short y, unsigned short k)
  293. {
  294. if ((comp_num < 0) || (comp_num > IMAGE_DEVICEN_MAX))
  295. return DISPLAY_ERROR;
  296. img->devicen[comp_num].used = 1;
  297. strncpy(img->devicen[comp_num].name, name,
  298. sizeof(img->devicen[comp_num].name)-1);
  299. img->devicen[comp_num].cyan = c;
  300. img->devicen[comp_num].magenta = m;
  301. img->devicen[comp_num].yellow = y;
  302. img->devicen[comp_num].black = k;
  303. return 0;
  304. }
  305. /****************************************************************/
  306. /* These functions are only accessed by the GUI thread */
  307. /* open window for device and add to list */
  308. void
  309. image_open(IMAGE *img)
  310. {
  311. /* register class */
  312. register_class();
  313. /* open window */
  314. create_window(img);
  315. }
  316. /* close window and remove from list */
  317. void
  318. image_close(IMAGE *img)
  319. {
  320. DestroyWindow(img->hwnd);
  321. img->hwnd = NULL;
  322. if (img->palette)
  323. DeleteObject(img->palette);
  324. img->palette = NULL;
  325. if (img->hBrush)
  326. DeleteObject(img->hBrush);
  327. img->hBrush = NULL;
  328. free(img);
  329. }
  330. void
  331. register_class(void)
  332. {
  333. WNDCLASS wndclass;
  334. HINSTANCE hInstance = GetModuleHandle(NULL);
  335. /* register the window class for graphics */
  336. wndclass.style = CS_HREDRAW | CS_VREDRAW;
  337. wndclass.lpfnWndProc = WndImg2Proc;
  338. wndclass.cbClsExtra = 0;
  339. wndclass.cbWndExtra = sizeof(LONG);
  340. wndclass.hInstance = hInstance;
  341. wndclass.hIcon = LoadIcon(hInstance,(LPSTR)MAKEINTRESOURCE(GSIMAGE_ICON));
  342. wndclass.hCursor = LoadCursor((HINSTANCE)NULL, IDC_ARROW);
  343. wndclass.hbrBackground = NULL; /* we will paint background */
  344. wndclass.lpszMenuName = NULL;
  345. wndclass.lpszClassName = szImgName2;
  346. RegisterClass(&wndclass);
  347. }
  348. void image_separations(IMAGE *img)
  349. {
  350. char buf[64];
  351. int i;
  352. int exist;
  353. int num_visible = 0;
  354. HMENU sysmenu = GetSystemMenu(img->hwnd, FALSE);
  355. if (((img->format & DISPLAY_COLORS_MASK) == DISPLAY_COLORS_CMYK) ||
  356. ((img->format & DISPLAY_COLORS_MASK) == DISPLAY_COLORS_SEPARATION)) {
  357. /* Add menus if needed */
  358. for (i=0; i<IMAGE_DEVICEN_MAX; i++) {
  359. exist = 0;
  360. if (img->devicen[i].menu)
  361. exist = GetMenuString(sysmenu, M_SEPARATION+i,
  362. buf, sizeof(buf)-1, MF_BYCOMMAND) != 0;
  363. if (exist && (strcmp(img->devicen[i].name, buf) != 0)) {
  364. /* remove it because name changed */
  365. RemoveMenu(sysmenu, M_SEPARATION+i, MF_BYCOMMAND);
  366. img->devicen[i].menu = 0;
  367. }
  368. if (img->devicen[i].name[0] && !img->devicen[i].menu) {
  369. AppendMenu(sysmenu, MF_STRING | MF_CHECKED,
  370. M_SEPARATION+i, img->devicen[i].name);
  371. img->devicen[i].menu = 1;
  372. }
  373. if (img->devicen[i].used && img->devicen[i].visible)
  374. num_visible++;
  375. }
  376. EnableMenuItem(sysmenu, M_DEVICEN_GRAY,
  377. MF_BYCOMMAND | ((num_visible <= 1) ? MF_ENABLED : MF_GRAYED));
  378. }
  379. else {
  380. for (i=0; i<IMAGE_DEVICEN_MAX; i++) {
  381. if (img->devicen[i].menu) {
  382. RemoveMenu(sysmenu, M_SEPARATION+i, MF_BYCOMMAND);
  383. img->devicen[i].menu = 0;
  384. }
  385. }
  386. EnableMenuItem(sysmenu, M_DEVICEN_GRAY, MF_BYCOMMAND | MF_GRAYED);
  387. }
  388. }
  389. void sep_menu(IMAGE *img, int component)
  390. {
  391. int i;
  392. int num_visible = 0;
  393. img->devicen[component].visible = !img->devicen[component].visible;
  394. CheckMenuItem(GetSystemMenu(img->hwnd, FALSE),
  395. M_SEPARATION+component,
  396. (img->devicen[component].visible ? MF_CHECKED : MF_UNCHECKED));
  397. for (i=0; i<IMAGE_DEVICEN_MAX; i++)
  398. if (img->devicen[i].used && img->devicen[i].visible)
  399. num_visible++;
  400. EnableMenuItem(GetSystemMenu(img->hwnd, FALSE), M_DEVICEN_GRAY,
  401. MF_BYCOMMAND | ((num_visible <= 1) ? MF_ENABLED : MF_GRAYED));
  402. InvalidateRect(img->hwnd, NULL, 0);
  403. UpdateWindow(img->hwnd);
  404. }
  405. static void
  406. create_window(IMAGE *img)
  407. {
  408. HMENU sysmenu;
  409. LOGBRUSH lb;
  410. char winposbuf[256];
  411. char window_title[256];
  412. int len = sizeof(winposbuf);
  413. /* create background brush */
  414. lb.lbStyle = BS_SOLID;
  415. lb.lbHatch = 0;
  416. lb.lbColor = GetSysColor(COLOR_WINDOW);
  417. if (lb.lbColor = RGB(255,255,255)) /* Don't allow white */
  418. lb.lbColor = GetSysColor(COLOR_MENU);
  419. if (lb.lbColor = RGB(255,255,255)) /* Don't allow white */
  420. lb.lbColor = GetSysColor(COLOR_APPWORKSPACE);
  421. if (lb.lbColor = RGB(255,255,255)) /* Don't allow white */
  422. lb.lbColor = RGB(192,192,192);
  423. img->hBrush = CreateBrushIndirect(&lb);
  424. img->cxClient = img->cyClient = 0;
  425. img->nVscrollPos = img->nVscrollMax = 0;
  426. img->nHscrollPos = img->nHscrollMax = 0;
  427. img->x = img->y = img->cx = img->cy = CW_USEDEFAULT;
  428. if (win_get_reg_value((img->device != NULL ? "Image" : "Tracer"), winposbuf, &len) == 0) {
  429. int x, y, cx, cy;
  430. if (sscanf(winposbuf, "%d %d %d %d", &x, &y, &cx, &cy) == 4) {
  431. img->x = x;
  432. img->y = y;
  433. img->cx = cx;
  434. img->cy = cy;
  435. }
  436. }
  437. strcpy(window_title, (img->device != NULL ? (LPSTR)szImgName2 : (LPSTR)szTrcName2));
  438. { /*
  439. * This section is for debug purpose only.
  440. * It allows to replace window title so that user can identify window
  441. * when multiple instances of the application run in same time.
  442. * Create gs\bin\gswin32.ini or gs\bin\gswin32c.ini and
  443. * put an identifier to there like this :
  444. *
  445. * [Window]
  446. * Title=Current Revision
  447. *
  448. * It is useful to compare images generated with different revisions.
  449. */
  450. char ini_path[MAX_PATH];
  451. DWORD ini_path_length;
  452. ini_path_length = GetModuleFileName(NULL, ini_path, sizeof(ini_path));
  453. if (ini_path_length > 0) {
  454. int i = ini_path_length - 1;
  455. for (; i>=0; i--)
  456. if(ini_path[i] == '.')
  457. break;
  458. if (i < sizeof(ini_path) - 4) {
  459. strcpy(ini_path + i, ".ini");
  460. GetPrivateProfileString("Window", "Title",
  461. (img->device != NULL ? (LPSTR)szImgName2 : (LPSTR)szTrcName2),
  462. window_title, sizeof(window_title), ini_path);
  463. }
  464. }
  465. }
  466. /* create window */
  467. img->hwnd = CreateWindow(szImgName2, window_title,
  468. WS_OVERLAPPEDWINDOW,
  469. img->x, img->y, img->cx, img->cy,
  470. NULL, NULL, GetModuleHandle(NULL), (void *)img);
  471. if (img->device == NULL && img->x != CW_USEDEFAULT &&
  472. img->y != CW_USEDEFAULT &&
  473. img->cx != CW_USEDEFAULT &&
  474. img->cy != CW_USEDEFAULT)
  475. MoveWindow(img->hwnd, img->x, img->y, img->cx, img->cy, FALSE);
  476. ShowWindow(img->hwnd, (img->device != NULL ? SW_SHOWMINNOACTIVE : SW_SHOW));
  477. /* modify the menu to have the new items we want */
  478. sysmenu = GetSystemMenu(img->hwnd, 0); /* get the sysmenu */
  479. AppendMenu(sysmenu, MF_SEPARATOR, 0, NULL);
  480. AppendMenu(sysmenu, MF_STRING, M_COPY_CLIP, "Copy to Clip&board");
  481. AppendMenu(sysmenu, MF_STRING, M_DEVICEN_GRAY, "Show as Gray");
  482. AppendMenu(sysmenu, MF_SEPARATOR, 0, NULL);
  483. image_separations(img);
  484. }
  485. void
  486. image_poll(IMAGE *img)
  487. {
  488. if ((img->bmih.biWidth == 0) || (img->bmih.biHeight == 0))
  489. return;
  490. img->pending_update = 1;
  491. if (img->update_timer == 0) {
  492. img->update_timer = 1;
  493. img->update_count = 0;
  494. SetTimer(img->hwnd, img->update_timer, img->update_tick, NULL);
  495. }
  496. }
  497. /* Redraw the window, making sure that periodic updates don't take too long. */
  498. void
  499. image_update_now(IMAGE *img)
  500. {
  501. SYSTEMTIME t1;
  502. SYSTEMTIME t2;
  503. int delta;
  504. if ( !IsWindow(img->hwnd) ) /* some clod closed the window */
  505. create_window(img);
  506. if ( !IsIconic(img->hwnd) ) { /* redraw window */
  507. GetSystemTime(&t1);
  508. InvalidateRect(img->hwnd, NULL, 1);
  509. UpdateWindow(img->hwnd);
  510. GetSystemTime(&t2);
  511. /* Make sure the update interval is at least 10 times
  512. * what it takes to paint the window
  513. */
  514. delta = (t2.wSecond - t1.wSecond)*1000 +
  515. (t2.wMilliseconds - t1.wMilliseconds);
  516. if (delta < 0)
  517. delta += 60000;
  518. delta = 10 * delta / img->update_tick + 1;
  519. if (delta > img->update_interval)
  520. img->update_interval = delta;
  521. else if ((delta >= 2) &&
  522. (delta < img->update_interval / 4))
  523. img->update_interval = delta/2;
  524. }
  525. img->update_count = 0;
  526. }
  527. void
  528. image_sync(IMAGE *img)
  529. {
  530. if (img->update_timer) {
  531. /* stop timer when nothing is happening */
  532. KillTimer(img->hwnd, img->update_timer);
  533. img->update_timer = 0;
  534. }
  535. img->pending_sync = 0;
  536. image_update_now(img);
  537. image_separations(img);
  538. img->pending_update = 0;
  539. }
  540. void
  541. image_page(IMAGE *img)
  542. {
  543. if (IsIconic(img->hwnd)) /* useless as an Icon so fix it */
  544. ShowWindow(img->hwnd, SW_SHOWNORMAL);
  545. BringWindowToTop(img->hwnd);
  546. image_sync(img);
  547. }
  548. /* GUI thread */
  549. void
  550. image_updatesize(IMAGE *img)
  551. {
  552. RECT rect;
  553. int nSizeType;
  554. image_separations(img);
  555. /* update scroll bars */
  556. if (!IsIconic(img->hwnd)) {
  557. if (IsZoomed(img->hwnd))
  558. nSizeType = SIZE_MAXIMIZED;
  559. else
  560. nSizeType = SIZE_RESTORED;
  561. GetClientRect(img->hwnd, &rect);
  562. SendMessage(img->hwnd, WM_SIZE, nSizeType,
  563. MAKELONG(rect.right, rect.bottom));
  564. }
  565. }
  566. void
  567. image_color(unsigned int format, int index,
  568. unsigned char *r, unsigned char *g, unsigned char *b)
  569. {
  570. switch (format & DISPLAY_COLORS_MASK) {
  571. case DISPLAY_COLORS_NATIVE:
  572. switch (format & DISPLAY_DEPTH_MASK) {
  573. case DISPLAY_DEPTH_1:
  574. *r = *g = *b = (index ? 0 : 255);
  575. break;
  576. case DISPLAY_DEPTH_4:
  577. if (index == 7)
  578. *r = *g = *b = 170;
  579. else if (index == 8)
  580. *r = *g = *b = 85;
  581. else {
  582. int one = index & 8 ? 255 : 128;
  583. *r = (index & 4 ? one : 0);
  584. *g = (index & 2 ? one : 0);
  585. *b = (index & 1 ? one : 0);
  586. }
  587. break;
  588. case DISPLAY_DEPTH_8:
  589. /* palette of 96 colors */
  590. /* 0->63 = 00RRGGBB, 64->95 = 010YYYYY */
  591. if (index < 64) {
  592. int one = 255 / 3;
  593. *r = ((index & 0x30) >> 4) * one;
  594. *g = ((index & 0x0c) >> 2) * one;
  595. *b = (index & 0x03) * one;
  596. }
  597. else {
  598. int val = index & 0x1f;
  599. *r = *g = *b = (val << 3) + (val >> 2);
  600. }
  601. break;
  602. }
  603. break;
  604. case DISPLAY_COLORS_GRAY:
  605. switch (format & DISPLAY_DEPTH_MASK) {
  606. case DISPLAY_DEPTH_1:
  607. *r = *g = *b = (index ? 255 : 0);
  608. break;
  609. case DISPLAY_DEPTH_4:
  610. *r = *g = *b = (unsigned char)((index<<4) + index);
  611. break;
  612. case DISPLAY_DEPTH_8:
  613. *r = *g = *b = (unsigned char)index;
  614. break;
  615. }
  616. break;
  617. }
  618. }
  619. /* convert one line of 16BGR555 to 24BGR */
  620. /* byte0=GGGBBBBB byte1=0RRRRRGG */
  621. void
  622. image_16BGR555_to_24BGR(int width, unsigned char *dest, unsigned char *source)
  623. {
  624. int i;
  625. WORD w;
  626. unsigned char value;
  627. for (i=0; i<width; i++) {
  628. w = source[0] + (source[1] << 8);
  629. value = w & 0x1f; /* blue */
  630. *dest++ = (value << 3) + (value >> 2);
  631. value = (w >> 5) & 0x1f; /* green */
  632. *dest++ = (value << 3) + (value >> 2);
  633. value = (w >> 10) & 0x1f; /* red */
  634. *dest++ = (value << 3) + (value >> 2);
  635. source += 2;
  636. }
  637. }
  638. /* convert one line of 16BGR565 to 24BGR */
  639. /* byte0=GGGBBBBB byte1=RRRRRGGG */
  640. void
  641. image_16BGR565_to_24BGR(int width, unsigned char *dest, unsigned char *source)
  642. {
  643. int i;
  644. WORD w;
  645. unsigned char value;
  646. for (i=0; i<width; i++) {
  647. w = source[0] + (source[1] << 8);
  648. value = w & 0x1f; /* blue */
  649. *dest++ = (value << 3) + (value >> 2);
  650. value = (w >> 5) & 0x3f; /* green */
  651. *dest++ = (value << 2) + (value >> 4);
  652. value = (w >> 11) & 0x1f; /* red */
  653. *dest++ = (value << 3) + (value >> 2);
  654. source += 2;
  655. }
  656. }
  657. /* convert one line of 16RGB555 to 24BGR */
  658. /* byte0=0RRRRRGG byte1=GGGBBBBB */
  659. void
  660. image_16RGB555_to_24BGR(int width, unsigned char *dest, unsigned char *source)
  661. {
  662. int i;
  663. WORD w;
  664. unsigned char value;
  665. for (i=0; i<width; i++) {
  666. w = (source[0] << 8) + source[1];
  667. value = w & 0x1f; /* blue */
  668. *dest++ = (value << 3) + (value >> 2);
  669. value = (w >> 5) & 0x1f; /* green */
  670. *dest++ = (value << 3) + (value >> 2);
  671. value = (w >> 10) & 0x1f; /* red */
  672. *dest++ = (value << 3) + (value >> 2);
  673. source += 2;
  674. }
  675. }
  676. /* convert one line of 16RGB565 to 24BGR */
  677. /* byte0=RRRRRGGG byte1=GGGBBBBB */
  678. void
  679. image_16RGB565_to_24BGR(int width, unsigned char *dest, unsigned char *source)
  680. {
  681. int i;
  682. WORD w;
  683. unsigned char value;
  684. for (i=0; i<width; i++) {
  685. w = (source[0] << 8) + source[1];
  686. value = w & 0x1f; /* blue */
  687. *dest++ = (value << 3) + (value >> 2);
  688. value = (w >> 5) & 0x3f; /* green */
  689. *dest++ = (value << 2) + (value >> 4);
  690. value = (w >> 11) & 0x1f; /* red */
  691. *dest++ = (value << 3) + (value >> 2);
  692. source += 2;
  693. }
  694. }
  695. void
  696. image_4CMYK_to_24BGR(int width, unsigned char *dest, unsigned char *source,
  697. IMAGE_DEVICEN *devicen, int devicen_gray)
  698. {
  699. int i;
  700. int cyan, magenta, yellow, black;
  701. int vc = devicen[0].visible;
  702. int vm = devicen[1].visible;
  703. int vy = devicen[2].visible;
  704. int vk = devicen[3].visible;
  705. int vall = vc && vm && vy && vk;
  706. int show_gray = (vc + vm + vy + vk == 1) && devicen_gray;
  707. int value;
  708. for (i=0; i<width; i++) {
  709. value = source[i/2];
  710. if (i & 0)
  711. value >>= 4;
  712. cyan = ((value >> 3) & 1) * 255;
  713. magenta = ((value >> 2) & 1) * 255;
  714. yellow = ((value >> 1) & 1) * 255;
  715. black = (value & 1) * 255;
  716. if (!vall) {
  717. if (!vc)
  718. cyan = 0;
  719. if (!vm)
  720. magenta = 0;
  721. if (!vy)
  722. yellow = 0;
  723. if (!vk)
  724. black = 0;
  725. if (show_gray) {
  726. black += cyan + magenta + yellow;
  727. cyan = magenta = yellow = 0;
  728. }
  729. }
  730. *dest++ = (255 - yellow) * (255 - black)/255; /* blue */
  731. *dest++ = (255 - magenta) * (255 - black)/255; /* green */
  732. *dest++ = (255 - cyan) * (255 - black)/255; /* red */
  733. }
  734. }
  735. /* convert one line of 32CMYK to 24BGR */
  736. void
  737. image_32CMYK_to_24BGR(int width, unsigned char *dest, unsigned char *source,
  738. IMAGE_DEVICEN *devicen, int devicen_gray)
  739. {
  740. int i;
  741. int cyan, magenta, yellow, black;
  742. int vc = devicen[0].visible;
  743. int vm = devicen[1].visible;
  744. int vy = devicen[2].visible;
  745. int vk = devicen[3].visible;
  746. int vall = vc && vm && vy && vk;
  747. int show_gray = (vc + vm + vy + vk == 1) && devicen_gray;
  748. for (i=0; i<width; i++) {
  749. cyan = source[0];
  750. magenta = source[1];
  751. yellow = source[2];
  752. black = source[3];
  753. if (!vall) {
  754. if (!vc)
  755. cyan = 0;
  756. if (!vm)
  757. magenta = 0;
  758. if (!vy)
  759. yellow = 0;
  760. if (!vk)
  761. black = 0;
  762. if (show_gray) {
  763. black += cyan + magenta + yellow;
  764. cyan = magenta = yellow = 0;
  765. }
  766. }
  767. *dest++ = (255 - yellow) * (255 - black)/255; /* blue */
  768. *dest++ = (255 - magenta) * (255 - black)/255; /* green */
  769. *dest++ = (255 - cyan) * (255 - black)/255; /* red */
  770. source += 4;
  771. }
  772. }
  773. void
  774. image_devicen_to_24BGR(int width, unsigned char *dest, unsigned char *source,
  775. IMAGE_DEVICEN *devicen, int devicen_gray)
  776. {
  777. int i, j;
  778. int cyan, magenta, yellow, black;
  779. int num_comp = 0;
  780. int value;
  781. int num_visible = 0;
  782. int show_gray = 0;
  783. for (j=0; j<IMAGE_DEVICEN_MAX; j++) {
  784. if (devicen[j].used) {
  785. num_comp = j+1;
  786. if (devicen[j].visible)
  787. num_visible++;
  788. }
  789. }
  790. if ((num_visible == 1) && devicen_gray)
  791. show_gray = 1;
  792. for (i=0; i<width; i++) {
  793. cyan = magenta = yellow = black = 0;
  794. for (j=0; j<num_comp; j++) {
  795. if (devicen[j].visible && devicen[j].used) {
  796. value = source[j];
  797. if (show_gray)
  798. black += value;
  799. else {
  800. cyan += value * devicen[j].cyan / 65535;
  801. magenta += value * devicen[j].magenta / 65535;
  802. yellow += value * devicen[j].yellow / 65535;
  803. black += value * devicen[j].black / 65535;
  804. }
  805. }
  806. }
  807. if (cyan > 255)
  808. cyan = 255;
  809. if (magenta > 255)
  810. magenta = 255;
  811. if (yellow > 255)
  812. yellow = 255;
  813. if (black > 255)
  814. black = 255;
  815. *dest++ = (255 - yellow) * (255 - black)/255; /* blue */
  816. *dest++ = (255 - magenta) * (255 - black)/255; /* green */
  817. *dest++ = (255 - cyan) * (255 - black)/255; /* red */
  818. source += 8;
  819. }
  820. }
  821. void
  822. image_convert_line(IMAGE *img, unsigned char *dest, unsigned char *source)
  823. {
  824. unsigned char *d = dest;
  825. unsigned char *s = source;
  826. int width = img->bmih.biWidth;
  827. unsigned int alpha = img->format & DISPLAY_ALPHA_MASK;
  828. BOOL bigendian = (img->format & DISPLAY_ENDIAN_MASK) == DISPLAY_BIGENDIAN;
  829. int i;
  830. switch (img->format & DISPLAY_COLORS_MASK) {
  831. case DISPLAY_COLORS_NATIVE:
  832. if ((img->format & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_16) {
  833. if (bigendian) {
  834. if ((img->format & DISPLAY_555_MASK)
  835. == DISPLAY_NATIVE_555)
  836. image_16RGB555_to_24BGR(img->bmih.biWidth,
  837. dest, source);
  838. else
  839. image_16RGB565_to_24BGR(img->bmih.biWidth,
  840. dest, source);
  841. }
  842. else {
  843. if ((img->format & DISPLAY_555_MASK)
  844. == DISPLAY_NATIVE_555) {
  845. image_16BGR555_to_24BGR(img->bmih.biWidth,
  846. dest, source);
  847. }
  848. else
  849. image_16BGR565_to_24BGR(img->bmih.biWidth,
  850. dest, source);
  851. }
  852. }
  853. break;
  854. case DISPLAY_COLORS_RGB:
  855. if ((img->format & DISPLAY_DEPTH_MASK) != DISPLAY_DEPTH_8)
  856. return;
  857. for (i=0; i<width; i++) {
  858. if ((alpha == DISPLAY_ALPHA_FIRST) ||
  859. (alpha == DISPLAY_UNUSED_FIRST))
  860. s++;
  861. if (bigendian) {
  862. *d++ = s[2];
  863. *d++ = s[1];
  864. *d++ = s[0];
  865. s+=3;
  866. }
  867. else {
  868. *d++ = *s++;
  869. *d++ = *s++;
  870. *d++ = *s++;
  871. }
  872. if ((alpha == DISPLAY_ALPHA_LAST) ||
  873. (alpha == DISPLAY_UNUSED_LAST))
  874. s++;
  875. }
  876. /*
  877. printf("rgb, width=%d alpha=%d d=0x%x s=0x%x\n", width, alpha, (int)d, (int)s);
  878. printf(" d=0x%x s=0x%x\n", (int)d, (int)s);
  879. */
  880. break;
  881. case DISPLAY_COLORS_CMYK:
  882. if ((img->format & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_8)
  883. image_32CMYK_to_24BGR(width, dest, source,
  884. img->devicen, img->devicen_gray);
  885. else if ((img->format & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_1) {
  886. image_4CMYK_to_24BGR(width, dest, source,
  887. img->devicen, img->devicen_gray);
  888. }
  889. else
  890. return;
  891. break;
  892. case DISPLAY_COLORS_SEPARATION:
  893. if ((img->format & DISPLAY_DEPTH_MASK) != DISPLAY_DEPTH_8)
  894. return;
  895. image_devicen_to_24BGR(width, dest, source,
  896. img->devicen, img->devicen_gray);
  897. break;
  898. }
  899. }
  900. /* This makes a copy of the bitmap in global memory, suitable for clipboard */
  901. /* Do not put 16 or 32-bit per pixels on the clipboard because */
  902. /* ClipBook Viewer (NT4) can't display them */
  903. static HGLOBAL
  904. copy_dib(IMAGE *img)
  905. {
  906. int bitsperpixel;
  907. int bytewidth;
  908. int bitmapsize;
  909. int palcount;
  910. HGLOBAL hglobal;
  911. BYTE *pBits;
  912. BYTE *pLine;
  913. BYTE *pDIB;
  914. BITMAPINFOHEADER *pbmih;
  915. RGBQUAD *pColors;
  916. int i;
  917. BOOL directcopy = FALSE;
  918. /* Allocates memory for the clipboard bitmap */
  919. if (img->bmih.biBitCount <= 1)
  920. bitsperpixel = 1;
  921. else if (img->bmih.biBitCount <= 4)
  922. bitsperpixel = 4;
  923. else if (img->bmih.biBitCount <= 8)
  924. bitsperpixel = 8;
  925. else
  926. bitsperpixel = 24;
  927. bytewidth = ((img->bmih.biWidth * bitsperpixel + 31 ) & ~31) >> 3;
  928. bitmapsize = bytewidth * img->bmih.biHeight;
  929. if (bitsperpixel > 8)
  930. palcount = 0; /* 24-bit BGR */
  931. else
  932. palcount = img->bmih.biClrUsed;
  933. hglobal = GlobalAlloc(GHND | GMEM_SHARE, sizeof(BITMAPINFOHEADER)
  934. + sizeof(RGBQUAD) * palcount + bitmapsize);
  935. if (hglobal == (HGLOBAL) NULL)
  936. return (HGLOBAL) NULL;
  937. pDIB = (BYTE *) GlobalLock(hglobal);
  938. if (pDIB == (BYTE *) NULL)
  939. return (HGLOBAL) NULL;
  940. /* initialize the clipboard bitmap */
  941. pbmih = (BITMAPINFOHEADER *) (pDIB);
  942. pColors = (RGBQUAD *) (pDIB + sizeof(BITMAPINFOHEADER));
  943. pBits = (BYTE *) (pDIB + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * palcount);
  944. pbmih->biSize = sizeof(BITMAPINFOHEADER);
  945. pbmih->biWidth = img->bmih.biWidth;
  946. pbmih->biHeight = img->bmih.biHeight;
  947. pbmih->biPlanes = 1;
  948. pbmih->biBitCount = bitsperpixel;
  949. pbmih->biCompression = 0;
  950. pbmih->biSizeImage = 0; /* default */
  951. pbmih->biXPelsPerMeter = 0;
  952. pbmih->biYPelsPerMeter = 0;
  953. pbmih->biClrUsed = palcount;
  954. pbmih->biClrImportant = palcount;
  955. for (i = 0; i < palcount; i++) {
  956. image_color(img->format, i, &pColors[i].rgbRed,
  957. &pColors[i].rgbGreen, &pColors[i].rgbBlue);
  958. pColors[i].rgbReserved = 0;
  959. }
  960. /* find out if the format needs to be converted */
  961. switch (img->format & DISPLAY_COLORS_MASK) {
  962. case DISPLAY_COLORS_NATIVE:
  963. switch (img->format & DISPLAY_DEPTH_MASK) {
  964. case DISPLAY_DEPTH_1:
  965. case DISPLAY_DEPTH_4:
  966. case DISPLAY_DEPTH_8:
  967. directcopy = TRUE;
  968. }
  969. break;
  970. case DISPLAY_COLORS_GRAY:
  971. switch (img->format & DISPLAY_DEPTH_MASK) {
  972. case DISPLAY_DEPTH_1:
  973. case DISPLAY_DEPTH_4:
  974. case DISPLAY_DEPTH_8:
  975. directcopy = TRUE;
  976. }
  977. break;
  978. case DISPLAY_COLORS_RGB:
  979. if (((img->format & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_8) &&
  980. ((img->format & DISPLAY_ALPHA_MASK) == DISPLAY_ALPHA_NONE) &&
  981. ((img->format & DISPLAY_ENDIAN_MASK) == DISPLAY_LITTLEENDIAN))
  982. directcopy = TRUE;
  983. }
  984. pLine = pBits;
  985. if (directcopy) {
  986. for (i = 0; i < img->bmih.biHeight; i++) {
  987. memcpy(pLine, img->image + i * img->raster, bytewidth);
  988. pLine += bytewidth;
  989. }
  990. }
  991. else {
  992. /* we need to convert the format to 24BGR */
  993. for (i = 0; i < img->bmih.biHeight; i++) {
  994. image_convert_line(img, pLine, img->image + i * img->raster);
  995. pLine += bytewidth;
  996. }
  997. }
  998. GlobalUnlock(hglobal);
  999. return hglobal;
  1000. }
  1001. static HPALETTE
  1002. create_palette(IMAGE *img)
  1003. {
  1004. int i;
  1005. int nColors;
  1006. HPALETTE palette = NULL;
  1007. nColors = img->bmih.biClrUsed;
  1008. if (nColors) {
  1009. LPLOGPALETTE logpalette;
  1010. logpalette = (LPLOGPALETTE) malloc(sizeof(LOGPALETTE) +
  1011. nColors * sizeof(PALETTEENTRY));
  1012. if (logpalette == (LPLOGPALETTE) NULL)
  1013. return (HPALETTE)0;
  1014. logpalette->palVersion = 0x300;
  1015. logpalette->palNumEntries = img->bmih.biClrUsed;
  1016. for (i = 0; i < nColors; i++) {
  1017. logpalette->palPalEntry[i].peFlags = 0;
  1018. image_color(img->format, i,
  1019. &logpalette->palPalEntry[i].peRed,
  1020. &logpalette->palPalEntry[i].peGreen,
  1021. &logpalette->palPalEntry[i].peBlue);
  1022. }
  1023. palette = CreatePalette(logpalette);
  1024. free(logpalette);
  1025. }
  1026. return palette;
  1027. }
  1028. /* image window */
  1029. /* All accesses to img->image or dimensions must be protected by mutex */
  1030. LRESULT CALLBACK
  1031. WndImg2Proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  1032. {
  1033. HDC hdc;
  1034. PAINTSTRUCT ps;
  1035. RECT rect;
  1036. int nVscrollInc, nHscrollInc;
  1037. IMAGE *img;
  1038. if (message == WM_CREATE) {
  1039. /* Object is stored in window extra data.
  1040. * Nothing must try to use the object before WM_CREATE
  1041. * initializes it here.
  1042. */
  1043. img = (IMAGE *)(((CREATESTRUCT *)lParam)->lpCreateParams);
  1044. SetWindowLong(hwnd, 0, (LONG)img);
  1045. }
  1046. img = (IMAGE *)GetWindowLong(hwnd, 0);
  1047. switch(message) {
  1048. case WM_SYSCOMMAND:
  1049. /* copy to clipboard */
  1050. if (LOWORD(wParam) == M_COPY_CLIP) {
  1051. HGLOBAL hglobal;
  1052. HPALETTE hpalette;
  1053. if (img->hmutex != INVALID_HANDLE_VALUE)
  1054. WaitForSingleObject(img->hmutex, 120000);
  1055. hglobal = copy_dib(img);
  1056. if (hglobal == (HGLOBAL)NULL) {
  1057. if (img->hmutex != INVALID_HANDLE_VALUE)
  1058. ReleaseMutex(img->hmutex);
  1059. MessageBox(hwnd, "Not enough memory to Copy to Clipboard",
  1060. szImgName2, MB_OK | MB_ICONEXCLAMATION);
  1061. return 0;
  1062. }
  1063. OpenClipboard(hwnd);
  1064. EmptyClipboard();
  1065. SetClipboardData(CF_DIB, hglobal);
  1066. hpalette = create_palette(img);
  1067. if (hpalette)
  1068. SetClipboardData(CF_PALETTE, hpalette);
  1069. CloseClipboard();
  1070. if (img->hmutex != INVALID_HANDLE_VALUE)
  1071. ReleaseMutex(img->hmutex);
  1072. return 0;
  1073. }
  1074. else if ((LOWORD(wParam) >= M_SEPARATION) &&
  1075. (LOWORD(wParam) < M_SEPARATION+IMAGE_DEVICEN_MAX)) {
  1076. sep_menu(img, LOWORD(wParam) - M_SEPARATION);
  1077. }
  1078. else if (LOWORD(wParam) == M_DEVICEN_GRAY) {
  1079. img->devicen_gray = !img->devicen_gray;
  1080. CheckMenuItem(GetSystemMenu(img->hwnd, FALSE), M_DEVICEN_GRAY,
  1081. (img->devicen_gray ? MF_CHECKED : MF_UNCHECKED));
  1082. InvalidateRect(img->hwnd, NULL, 0);
  1083. UpdateWindow(img->hwnd);
  1084. }
  1085. break;
  1086. case WM_CREATE:
  1087. /* enable drag-drop */
  1088. DragAcceptFiles(hwnd, TRUE);
  1089. break;
  1090. case WM_MOVE:
  1091. if (!IsIconic(hwnd) && !IsZoomed(hwnd)) {
  1092. GetWindowRect(hwnd, &rect);
  1093. img->x = rect.left;
  1094. img->y = rect.top;
  1095. }
  1096. break;
  1097. case WM_SIZE:
  1098. if (wParam == SIZE_MINIMIZED)
  1099. return(0);
  1100. /* remember current window size */
  1101. if (wParam != SIZE_MAXIMIZED) {
  1102. GetWindowRect(hwnd, &rect);
  1103. img->cx = rect.right - rect.left;
  1104. img->cy = rect.bottom - rect.top;
  1105. img->x = rect.left;
  1106. img->y = rect.top;
  1107. }
  1108. if (img->hmutex != INVALID_HANDLE_VALUE)
  1109. WaitForSingleObject(img->hmutex, 120000);
  1110. img->cyClient = HIWORD(lParam);
  1111. img->cxClient = LOWORD(lParam);
  1112. img->cyAdjust = min(img->bmih.biHeight, img->cyClient) - img->cyClient;
  1113. img->cyClient += img->cyAdjust;
  1114. img->nVscrollMax = max(0, img->bmih.biHeight - img->cyClient);
  1115. img->nVscrollPos = min(img->nVscrollPos, img->nVscrollMax);
  1116. SetScrollRange(hwnd, SB_VERT, 0, img->nVscrollMax, FALSE);
  1117. SetScrollPos(hwnd, SB_VERT, img->nVscrollPos, TRUE);
  1118. img->cxAdjust = min(img->bmih.biWidth, img->cxClient) - img->cxClient;
  1119. img->cxClient += img->cxAdjust;
  1120. img->nHscrollMax = max(0, img->bmih.biWidth - img->cxClient);
  1121. img->nHscrollPos = min(img->nHscrollPos, img->nHscrollMax);
  1122. SetScrollRange(hwnd, SB_HORZ, 0, img->nHscrollMax, FALSE);
  1123. SetScrollPos(hwnd, SB_HORZ, img->nHscrollPos, TRUE);
  1124. if ((wParam==SIZENORMAL)
  1125. && (img->cxAdjust!=0 || img->cyAdjust!=0)) {
  1126. GetWindowRect(GetParent(hwnd),&rect);
  1127. MoveWindow(GetParent(hwnd),rect.left,rect.top,
  1128. rect.right-rect.left+img->cxAdjust,
  1129. rect.bottom-rect.top+img->cyAdjust, TRUE);
  1130. img->cxAdjust = img->cyAdjust = 0;
  1131. }
  1132. if (img->hmutex != INVALID_HANDLE_VALUE)
  1133. ReleaseMutex(img->hmutex);
  1134. return(0);
  1135. case WM_VSCROLL:
  1136. switch(LOWORD(wParam)) {
  1137. case SB_TOP:
  1138. nVscrollInc = -img->nVscrollPos;
  1139. break;
  1140. case SB_BOTTOM:
  1141. nVscrollInc = img->nVscrollMax - img->nVscrollPos;
  1142. break;
  1143. case SB_LINEUP:
  1144. nVscrollInc = -img->cyClient/16;
  1145. break;
  1146. case SB_LINEDOWN:
  1147. nVscrollInc = img->cyClient/16;
  1148. break;
  1149. case SB_PAGEUP:
  1150. nVscrollInc = min(-1,-img->cyClient);
  1151. break;
  1152. case SB_PAGEDOWN:
  1153. nVscrollInc = max(1,img->cyClient);
  1154. break;
  1155. case SB_THUMBTRACK:
  1156. case SB_THUMBPOSITION:
  1157. nVscrollInc = HIWORD(wParam) - img->nVscrollPos;
  1158. break;
  1159. default:
  1160. nVscrollInc = 0;
  1161. }
  1162. if ((nVscrollInc = max(-img->nVscrollPos,
  1163. min(nVscrollInc, img->nVscrollMax - img->nVscrollPos)))!=0) {
  1164. img->nVscrollPos += nVscrollInc;
  1165. ScrollWindow(hwnd,0,-nVscrollInc,NULL,NULL);
  1166. SetScrollPos(hwnd,SB_VERT,img->nVscrollPos,TRUE);
  1167. UpdateWindow(hwnd);
  1168. }
  1169. return(0);
  1170. case WM_HSCROLL:
  1171. switch(LOWORD(wParam)) {
  1172. case SB_LINEUP:
  1173. nHscrollInc = -img->cxClient/16;
  1174. break;
  1175. case SB_LINEDOWN:
  1176. nHscrollInc = img->cyClient/16;
  1177. break;
  1178. case SB_PAGEUP:
  1179. nHscrollInc = min(-1,-img->cxClient);
  1180. break;
  1181. case SB_PAGEDOWN:
  1182. nHscrollInc = max(1,img->cxClient);
  1183. break;
  1184. case SB_THUMBTRACK:
  1185. case SB_THUMBPOSITION:
  1186. nHscrollInc = HIWORD(wParam) - img->nHscrollPos;
  1187. break;
  1188. default:
  1189. nHscrollInc = 0;
  1190. }
  1191. if ((nHscrollInc = max(-img->nHscrollPos,
  1192. min(nHscrollInc, img->nHscrollMax - img->nHscrollPos)))!=0) {
  1193. img->nHscrollPos += nHscrollInc;
  1194. ScrollWindow(hwnd,-nHscrollInc,0,NULL,NULL);
  1195. SetScrollPos(hwnd,SB_HORZ,img->nHscrollPos,TRUE);
  1196. UpdateWindow(hwnd);
  1197. }
  1198. return(0);
  1199. case WM_KEYDOWN:
  1200. switch(LOWORD(wParam)) {
  1201. case VK_HOME:
  1202. SendMessage(hwnd,WM_VSCROLL,SB_TOP,0L);
  1203. break;
  1204. case VK_END:
  1205. SendMessage(hwnd,WM_VSCROLL,SB_BOTTOM,0L);
  1206. break;
  1207. case VK_PRIOR:
  1208. SendMessage(hwnd,WM_VSCROLL,SB_PAGEUP,0L);
  1209. break;
  1210. case VK_NEXT:
  1211. SendMessage(hwnd,WM_VSCROLL,SB_PAGEDOWN,0L);
  1212. break;
  1213. case VK_UP:
  1214. SendMessage(hwnd,WM_VSCROLL,SB_LINEUP,0L);
  1215. break;
  1216. case VK_DOWN:
  1217. SendMessage(hwnd,WM_VSCROLL,SB_LINEDOWN,0L);
  1218. break;
  1219. case VK_LEFT:
  1220. SendMessage(hwnd,WM_HSCROLL,SB_PAGEUP,0L);
  1221. break;
  1222. case VK_RIGHT:
  1223. SendMessage(hwnd,WM_HSCROLL,SB_PAGEDOWN,0L);
  1224. break;
  1225. case VK_RETURN:
  1226. if (hwndtext)
  1227. BringWindowToTop(hwndtext);
  1228. break;
  1229. }
  1230. return(0);
  1231. case WM_CHAR:
  1232. /* send on all characters to text window */
  1233. if (hwndtext)
  1234. SendMessage(hwndtext, message, wParam, lParam);
  1235. else {
  1236. /* assume we have a console */
  1237. INPUT_RECORD ir;
  1238. HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
  1239. DWORD dwWritten = 0;
  1240. DWORD cks = 0;
  1241. ir.EventType = KEY_EVENT;
  1242. ir.Event.KeyEvent.bKeyDown = TRUE;
  1243. ir.Event.KeyEvent.wRepeatCount = lParam & 0xffff;
  1244. ir.Event.KeyEvent.wVirtualKeyCode = VkKeyScan((TCHAR)wParam) & 0xff;
  1245. ir.Event.KeyEvent.wVirtualScanCode =
  1246. (lParam >> 16) & 0xff;
  1247. ir.Event.KeyEvent.uChar.AsciiChar = wParam;
  1248. if (GetKeyState(VK_CAPITAL))
  1249. cks |= CAPSLOCK_ON;
  1250. /* ENHANCED_KEY unimplemented */
  1251. if (GetKeyState(VK_LMENU))
  1252. cks |= LEFT_ALT_PRESSED;
  1253. if (GetKeyState(VK_LCONTROL))
  1254. cks |= LEFT_CTRL_PRESSED;
  1255. if (GetKeyState(VK_NUMLOCK))
  1256. cks |= NUMLOCK_ON;
  1257. if (GetKeyState(VK_RMENU))
  1258. cks |= RIGHT_ALT_PRESSED;
  1259. if (GetKeyState(VK_RCONTROL))
  1260. cks |= RIGHT_CTRL_PRESSED;
  1261. if (GetKeyState(VK_SCROLL))
  1262. cks |= SCROLLLOCK_ON;
  1263. if (GetKeyState(VK_SHIFT))
  1264. cks |= SHIFT_PRESSED;
  1265. ir.Event.KeyEvent.dwControlKeyState = cks;
  1266. if (ir.Event.KeyEvent.uChar.AsciiChar == 3)
  1267. GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0L);
  1268. else if (hStdin != INVALID_HANDLE_VALUE)
  1269. WriteConsoleInput(hStdin, &ir, 1, &dwWritten);
  1270. }
  1271. return 0;
  1272. case WM_TIMER:
  1273. img->update_count++;
  1274. if (img->update_count >= img->update_interval)
  1275. image_update_now(img);
  1276. return 0;
  1277. case WM_PAINT:
  1278. {
  1279. int sx,sy,wx,wy,dx,dy;
  1280. RECT fillrect;
  1281. hdc = BeginPaint(hwnd, &ps);
  1282. if (img->hmutex != INVALID_HANDLE_VALUE)
  1283. WaitForSingleObject(img->hmutex, 120000);
  1284. SetMapMode(hdc, MM_TEXT);
  1285. SetBkMode(hdc,OPAQUE);
  1286. rect = ps.rcPaint;
  1287. dx = rect.left; /* destination */
  1288. dy = rect.top;
  1289. wx = rect.right-rect.left; /* width */
  1290. wy = rect.bottom-rect.top;
  1291. sx = rect.left; /* source */
  1292. sy = rect.top;
  1293. sx += img->nHscrollPos; /* scrollbars */
  1294. sy += img->nVscrollPos;
  1295. if (sx+wx > img->bmih.biWidth)
  1296. wx = img->bmih.biWidth - sx;
  1297. if (sy+wy > img->bmih.biHeight)
  1298. wy = img->bmih.biHeight - sy;
  1299. draw(img, hdc, dx, dy, wx, wy, sx, sy);
  1300. /* fill areas around page */
  1301. if (rect.right > img->bmih.biWidth) {
  1302. fillrect.top = rect.top;
  1303. fillrect.left = img->bmih.biWidth;
  1304. fillrect.bottom = rect.bottom;
  1305. fillrect.right = rect.right;
  1306. FillRect(hdc, &fillrect, img->hBrush);
  1307. }
  1308. if (rect.bottom > img->bmih.biHeight) {
  1309. fillrect.top = img->bmih.biHeight;
  1310. fillrect.left = rect.left;
  1311. fillrect.bottom = rect.bottom;
  1312. fillrect.right = rect.right;
  1313. FillRect(hdc, &fillrect, img->hBrush);
  1314. }
  1315. if (img->hmutex != INVALID_HANDLE_VALUE)
  1316. ReleaseMutex(img->hmutex);
  1317. EndPaint(hwnd, &ps);
  1318. return 0;
  1319. }
  1320. case WM_DROPFILES:
  1321. if (hwndtext)
  1322. SendMessage(hwndtext, message, wParam, lParam);
  1323. else {
  1324. char szFile[256];
  1325. int i, cFiles;
  1326. const char *p;
  1327. const char *szDragPre = "\r(";
  1328. const char *szDragPost = ") run\r";
  1329. HDROP hdrop = (HDROP)wParam;
  1330. cFiles = DragQueryFile(hdrop, (UINT)(-1), (LPSTR)NULL, 0);
  1331. for (i=0; i<cFiles; i++) {
  1332. DragQueryFile(hdrop, i, szFile, 80);
  1333. for (p=szDragPre; *p; p++)
  1334. SendMessage(hwnd,WM_CHAR,*p,1L);
  1335. for (p=szFile; *p; p++) {
  1336. if (*p == '\\')
  1337. SendMessage(hwnd,WM_CHAR,'/',1L);
  1338. else
  1339. SendMessage(hwnd,WM_CHAR,*p,1L);
  1340. }
  1341. for (p=szDragPost; *p; p++)
  1342. SendMessage(hwnd,WM_CHAR,*p,1L);
  1343. }
  1344. DragFinish(hdrop);
  1345. }
  1346. break;
  1347. case WM_DESTROY:
  1348. { /* Save the text window size */
  1349. char winposbuf[64];
  1350. sprintf(winposbuf, "%d %d %d %d", img->x, img->y,
  1351. img->cx, img->cy);
  1352. win_set_reg_value((img->device != NULL ? "Image" : "Tracer"), winposbuf);
  1353. }
  1354. DragAcceptFiles(hwnd, FALSE);
  1355. break;
  1356. }
  1357. return DefWindowProc(hwnd, message, wParam, lParam);
  1358. }
  1359. /* Repaint a section of the window. */
  1360. static void
  1361. draw(IMAGE *img, HDC hdc, int dx, int dy, int wx, int wy,
  1362. int sx, int sy)
  1363. {
  1364. HPALETTE oldpalette;
  1365. struct bmi_s {
  1366. BITMAPINFOHEADER h;
  1367. unsigned short pal_index[256];
  1368. } bmi;
  1369. int i;
  1370. UINT which_colors;
  1371. unsigned char *line = NULL;
  1372. long ny;
  1373. unsigned char *bits;
  1374. BOOL directcopy = FALSE;
  1375. if (img->device == NULL)
  1376. return;
  1377. memset(&bmi.h, 0, sizeof(bmi.h));
  1378. bmi.h.biSize = sizeof(bmi.h);
  1379. bmi.h.biWidth = img->bmih.biWidth;
  1380. bmi.h.biHeight = wy;
  1381. bmi.h.biPlanes = 1;
  1382. bmi.h.biBitCount = img->bmih.biBitCount;
  1383. bmi.h.biCompression = 0;
  1384. bmi.h.biSizeImage = 0; /* default */
  1385. bmi.h.biXPelsPerMeter = 0; /* default */
  1386. bmi.h.biYPelsPerMeter = 0; /* default */
  1387. bmi.h.biClrUsed = img->bmih.biClrUsed;
  1388. bmi.h.biClrImportant = img->bmih.biClrImportant;
  1389. if (img->bmih.biClrUsed) {
  1390. /* palette colors */
  1391. for (i = 0; i < img->bmih.biClrUsed; i++)
  1392. bmi.pal_index[i] = i;
  1393. which_colors = DIB_PAL_COLORS;
  1394. }
  1395. else if (bmi.h.biBitCount == 16) {
  1396. DWORD* bmi_colors = (DWORD*)(&bmi.pal_index[0]);
  1397. bmi.h.biCompression = BI_BITFIELDS;
  1398. which_colors = DIB_RGB_COLORS;
  1399. if ((img->format & DISPLAY_555_MASK) == DISPLAY_NATIVE_555) {
  1400. /* 5-5-5 RGB mode */
  1401. bmi_colors[0] = 0x7c00;
  1402. bmi_colors[1] = 0x03e0;
  1403. bmi_colors[2] = 0x001f;
  1404. }
  1405. else {
  1406. /* 5-6-5 RGB mode */
  1407. bmi_colors[0] = 0xf800;
  1408. bmi_colors[1] = 0x07e0;
  1409. bmi_colors[2] = 0x001f;
  1410. }
  1411. }
  1412. else if (bmi.h.biBitCount == 32) {
  1413. unsigned int alpha = img->format & DISPLAY_ALPHA_MASK;
  1414. DWORD* bmi_colors = (DWORD*)(&bmi.pal_index[0]);
  1415. bmi.h.biCompression = BI_BITFIELDS;
  1416. which_colors = DIB_RGB_COLORS;
  1417. if ((img->format & DISPLAY_ENDIAN_MASK) == DISPLAY_BIGENDIAN) {
  1418. if ((alpha == DISPLAY_ALPHA_FIRST) ||
  1419. (alpha == DISPLAY_UNUSED_FIRST)) {
  1420. /* Mac mode */
  1421. bmi_colors[0] = 0x0000ff00;
  1422. bmi_colors[1] = 0x00ff0000;
  1423. bmi_colors[2] = 0xff000000;
  1424. }
  1425. else {
  1426. bmi_colors[0] = 0x000000ff;
  1427. bmi_colors[1] = 0x0000ff00;
  1428. bmi_colors[2] = 0x00ff0000;
  1429. }
  1430. }
  1431. else {
  1432. if ((alpha == DISPLAY_ALPHA_FIRST) ||
  1433. (alpha == DISPLAY_UNUSED_FIRST)) {
  1434. /* ignore alpha */
  1435. bmi_colors[0] = 0xff000000;
  1436. bmi_colors[1] = 0x00ff0000;
  1437. bmi_colors[2] = 0x0000ff00;
  1438. }
  1439. else {
  1440. /* Windows mode */
  1441. /* ignore alpha */
  1442. bmi_colors[0] = 0x00ff0000;
  1443. bmi_colors[1] = 0x0000ff00;
  1444. bmi_colors[2] = 0x000000ff;
  1445. }
  1446. }
  1447. } else {
  1448. bmi.h.biClrUsed = 0;
  1449. bmi.h.biClrImportant = 0;
  1450. which_colors = DIB_RGB_COLORS;
  1451. }
  1452. if (img->raster <= 0)
  1453. return;
  1454. if (img->bytewidth <= 0)
  1455. return;
  1456. /* Determine if the format is native and we can do a direct copy */
  1457. switch (img->format & DISPLAY_COLORS_MASK) {
  1458. case DISPLAY_COLORS_NATIVE:
  1459. switch (img->format & DISPLAY_DEPTH_MASK) {
  1460. case DISPLAY_DEPTH_1:
  1461. case DISPLAY_DEPTH_4:
  1462. case DISPLAY_DEPTH_8:
  1463. directcopy = TRUE;
  1464. break;
  1465. case DISPLAY_DEPTH_16:
  1466. if ((img->format & DISPLAY_ENDIAN_MASK)
  1467. == DISPLAY_LITTLEENDIAN)
  1468. directcopy = TRUE;
  1469. break;
  1470. }
  1471. break;
  1472. case DISPLAY_COLORS_GRAY:
  1473. switch (img->format & DISPLAY_DEPTH_MASK) {
  1474. case DISPLAY_DEPTH_1:
  1475. case DISPLAY_DEPTH_4:
  1476. case DISPLAY_DEPTH_8:
  1477. directcopy = TRUE;
  1478. }
  1479. break;
  1480. case DISPLAY_COLORS_RGB:
  1481. if (((img->format & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_8) &&
  1482. ((img->format & DISPLAY_ENDIAN_MASK) == DISPLAY_LITTLEENDIAN) &&
  1483. ((img->format & DISPLAY_ALPHA_MASK) == DISPLAY_ALPHA_NONE))
  1484. directcopy = TRUE; /* BGR24 */
  1485. if (((img->format & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_8) &&
  1486. ((img->format & DISPLAY_ENDIAN_MASK) == DISPLAY_LITTLEENDIAN) &&
  1487. ((img->format & DISPLAY_ALPHA_MASK) == DISPLAY_UNUSED_LAST))
  1488. directcopy = TRUE; /* 32-bit */
  1489. break;
  1490. }
  1491. if (which_colors == DIB_PAL_COLORS) {
  1492. oldpalette = SelectPalette(hdc, img->palette, FALSE);
  1493. RealizePalette(hdc);
  1494. }
  1495. /*
  1496. * Windows apparently limits the size of a single transfer
  1497. * to 2 Mb, which can be exceeded on 24-bit displays.
  1498. */
  1499. ny = 2000000 / img->raster;
  1500. if (img->raster != img->bytewidth) /* not 32-bit architecture */
  1501. ny = 1;
  1502. /* If color format not native, convert it line by line */
  1503. /* This is slow, but these formats aren't normally used */
  1504. if (!directcopy) {
  1505. ny = 1;
  1506. line = (unsigned char *)malloc(img->bytewidth);
  1507. if (line == NULL)
  1508. return;
  1509. }
  1510. for (; wy; dy += ny, wy -= ny, sy += ny) {
  1511. ny = min(ny, wy);
  1512. if (directcopy) {
  1513. bits = img->image + img->raster * (img->bmih.biHeight - (sy + ny));
  1514. }
  1515. else {
  1516. image_convert_line(img, line,
  1517. img->image + img->raster * (img->bmih.biHeight - (sy + ny)));
  1518. bits = line;
  1519. }
  1520. SetDIBitsToDevice(hdc, dx, dy, wx, ny, sx, 0, 0, ny, bits,
  1521. (BITMAPINFO *) & bmi, which_colors);
  1522. }
  1523. if (which_colors == DIB_PAL_COLORS)
  1524. SelectPalette(hdc, oldpalette, FALSE);
  1525. if (line)
  1526. free(line);
  1527. }