GraphicsScreen.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  1. /* GraphicsScreen.cpp
  2. *
  3. * Copyright (C) 1992-2012,2014,2015,2016,2017 Paul Boersma, 2013 Tom Naughton
  4. *
  5. * This code is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or (at
  8. * your option) any later version.
  9. *
  10. * This code is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. * See the GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this work. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include "GraphicsP.h"
  19. #include "Printer.h"
  20. #include "GuiP.h"
  21. #if cairo
  22. #include <cairo/cairo-pdf.h>
  23. static bool _GraphicsCairo_tryToInitializePango () {
  24. return _GraphicsLin_tryToInitializeFonts ();
  25. }
  26. #elif gdi
  27. //#include "winport_on.h"
  28. #include <gdiplus.h>
  29. //#include "winport_off.h"
  30. //using namespace Gdiplus;
  31. static bool _GraphicsWindows_tryToInitializeGdiPlus () {
  32. Gdiplus::GdiplusStartupInput gdiplusStartupInput;
  33. ULONG_PTR gdiplusToken;
  34. GdiplusStartup (& gdiplusToken, & gdiplusStartupInput, nullptr);
  35. return true;
  36. }
  37. #elif quartz
  38. #include "macport_on.h"
  39. static RGBColor theBlackColour = { 0, 0, 0 };
  40. static bool _GraphicsMacintosh_tryToInitializeQuartz () {
  41. return _GraphicsMac_tryToInitializeFonts ();
  42. }
  43. #endif
  44. Thing_implement (GraphicsScreen, Graphics, 0);
  45. void structGraphicsScreen :: v_destroy () noexcept {
  46. #if cairo
  47. #if ALLOW_GDK_DRAWING
  48. if (d_gdkGraphicsContext) {
  49. g_object_unref (d_gdkGraphicsContext);
  50. d_gdkGraphicsContext = nullptr;
  51. }
  52. #endif
  53. if (d_cairoGraphicsContext) {
  54. cairo_destroy (d_cairoGraphicsContext);
  55. d_cairoGraphicsContext = nullptr;
  56. }
  57. if (d_cairoSurface) {
  58. cairo_surface_flush (d_cairoSurface);
  59. if (d_isPng) {
  60. #if 1
  61. cairo_surface_write_to_png (d_cairoSurface, Melder_peek32to8 (d_file. path));
  62. #else
  63. unsigned char *bitmap = cairo_image_surface_get_data (my d_cairoSurface); // peeking into the internal bits
  64. // copy bitmap to PNG structure created with the PNG library
  65. // save the PNG tructure to a file
  66. #endif
  67. }
  68. cairo_surface_destroy (d_cairoSurface);
  69. }
  70. #elif gdi
  71. if (d_gdiGraphicsContext) {
  72. SelectPen (d_gdiGraphicsContext, GetStockPen (BLACK_PEN));
  73. SelectBrush (d_gdiGraphicsContext, GetStockBrush (NULL_BRUSH));
  74. }
  75. if (d_winPen) {
  76. DeleteObject (d_winPen);
  77. d_winPen = nullptr;
  78. }
  79. if (d_winBrush) {
  80. DeleteObject (d_winBrush);
  81. d_winBrush = nullptr;
  82. }
  83. if (d_isPng && d_gdiBitmap) {
  84. trace (U"saving the filled bitmap to a PNG file");
  85. /*
  86. * Deselect the bitmap from the device context (otherwise GetDIBits won't work).
  87. */
  88. //SelectBitmap (d_gdiGraphicsContext, nullptr);
  89. //SelectBitmap (d_gdiGraphicsContext, CreateCompatibleBitmap (nullptr, 1, 1));
  90. BITMAP bitmap;
  91. GetObject (d_gdiBitmap, sizeof (BITMAP), & bitmap);
  92. int width = bitmap. bmWidth, height = bitmap. bmHeight;
  93. //int width = 3600, height = 3600;
  94. trace (U"width ", width, U", height ", height);
  95. /*
  96. * Get the bits from the HBITMAP;
  97. */
  98. struct { BITMAPINFOHEADER header; } bitmapInfo;
  99. bitmapInfo. header.biSize = sizeof (BITMAPINFOHEADER);
  100. bitmapInfo. header.biWidth = width;
  101. bitmapInfo. header.biHeight = height;
  102. bitmapInfo. header.biPlanes = 1;
  103. bitmapInfo. header.biBitCount = 32;
  104. bitmapInfo. header.biCompression = BI_RGB;
  105. bitmapInfo. header.biSizeImage = 0;
  106. bitmapInfo. header.biXPelsPerMeter = 0;
  107. bitmapInfo. header.biYPelsPerMeter = 0;
  108. bitmapInfo. header.biClrUsed = 0;
  109. bitmapInfo. header.biClrImportant = 0;
  110. unsigned char *bits = Melder_calloc (unsigned char, 4 * width * height);
  111. //HANDLE handle = GlobalAlloc (GHND, 4 * width * height);
  112. //unsigned char *bits = (unsigned char *) GlobalLock (handle);
  113. int numberOfLinesScanned = GetDIBits (GetDC (nullptr), d_gdiBitmap, 0, height, bits, (BITMAPINFO *) & bitmapInfo, DIB_RGB_COLORS);
  114. trace (numberOfLinesScanned, U" lines scanned");
  115. trace (U"creating a savable bitmap");
  116. //Gdiplus::Bitmap gdiplusBitmap (width, height, PixelFormat32bppARGB);
  117. Gdiplus::Bitmap gdiplusBitmap ((BITMAPINFO *) & bitmapInfo, bits);
  118. gdiplusBitmap. SetResolution (resolution, resolution);
  119. trace (U"copying the device-independent bits to the savable bitmap.");
  120. /*
  121. for (integer irow = 1; irow <= height; irow ++) {
  122. for (integer icol = 1; icol <= width; icol ++) {
  123. unsigned char blue = *bits ++, green = *bits ++, red = *bits ++, alpha = 255 - *bits ++;
  124. Gdiplus::Color gdiplusColour (alpha, red, green, blue);
  125. gdiplusBitmap. SetPixel (icol - 1, height - irow, gdiplusColour);
  126. }
  127. }
  128. */
  129. trace (U"saving");
  130. UINT numberOfImageEncoders, sizeOfImageEncoderArray;
  131. Gdiplus::GetImageEncodersSize (& numberOfImageEncoders, & sizeOfImageEncoderArray);
  132. Gdiplus::ImageCodecInfo *imageEncoderInfos = Melder_malloc (Gdiplus::ImageCodecInfo, sizeOfImageEncoderArray);
  133. Gdiplus::GetImageEncoders (numberOfImageEncoders, sizeOfImageEncoderArray, imageEncoderInfos);
  134. for (int iencoder = 0; iencoder < numberOfImageEncoders; iencoder ++) {
  135. if (! wcscmp (imageEncoderInfos [iencoder]. MimeType, L"image/png")) {
  136. gdiplusBitmap. Save (Melder_peek32toW (our d_file. path), & imageEncoderInfos [iencoder]. Clsid, nullptr);
  137. }
  138. }
  139. trace (U"cleaning up");
  140. Melder_free (imageEncoderInfos);
  141. //bits -= 4 * width * height;
  142. Melder_free (bits);
  143. //GlobalUnlock (handle);
  144. //GlobalFree (handle);
  145. DeleteObject (d_gdiBitmap);
  146. Melder_assert (d_gdiGraphicsContext);
  147. DeleteDC (d_gdiGraphicsContext); // this was a memory leak before 5.3.83
  148. }
  149. /*
  150. * No ReleaseDC here, because we have not created it ourselves,
  151. * not even with GetDC. Is this a BUG?
  152. */
  153. d_gdiGraphicsContext = nullptr;
  154. #elif quartz
  155. if (! d_macView && ! d_isPng) {
  156. CGContextEndPage (d_macGraphicsContext);
  157. CGContextRelease (d_macGraphicsContext);
  158. }
  159. if (d_isPng && d_macGraphicsContext) {
  160. /*
  161. * Turn the offscreen bitmap into an image.
  162. */
  163. CGImageRef image = CGBitmapContextCreateImage (d_macGraphicsContext);
  164. Melder_assert (image);
  165. //CGContextRelease (d_macGraphicsContext);
  166. /*
  167. * Create a dictionary with resolution properties.
  168. */
  169. CFTypeRef keys [2], values [2];
  170. keys [0] = kCGImagePropertyDPIWidth;
  171. keys [1] = kCGImagePropertyDPIHeight;
  172. float resolution_float = resolution;
  173. values [1] = values [0] = CFNumberCreate (nullptr, kCFNumberFloatType, & resolution_float);
  174. CFDictionaryRef properties = CFDictionaryCreate (nullptr,
  175. (const void **) keys, (const void **) values, 2,
  176. & kCFTypeDictionaryKeyCallBacks, & kCFTypeDictionaryValueCallBacks);
  177. Melder_assert (properties);
  178. /*
  179. */
  180. CFURLRef url = CFURLCreateWithFileSystemPath (nullptr,
  181. (CFStringRef) Melder_peek32toCfstring (d_file. path), kCFURLPOSIXPathStyle, false);
  182. CGImageDestinationRef imageDestination = CGImageDestinationCreateWithURL (url, kUTTypePNG, 1, nullptr);
  183. if (imageDestination) {
  184. CGImageDestinationAddImage (imageDestination, image, properties);
  185. CGImageDestinationFinalize (imageDestination);
  186. CFRelease (imageDestination);
  187. }
  188. CGImageRelease (image);
  189. CFRelease (properties);
  190. CFRelease (url);
  191. }
  192. Melder_free (d_bits);
  193. #endif
  194. trace (U"destroying parent");
  195. GraphicsScreen_Parent :: v_destroy ();
  196. trace (U"exit");
  197. }
  198. void structGraphicsScreen :: v_flushWs () {
  199. #if cairo && gtk
  200. // Ik weet niet of dit is wat het zou moeten zijn ;)
  201. //gdk_window_process_updates (d_window, true); // this "works" but is incorrect because it's not the expose events that have to be carried out
  202. //gdk_window_flush (d_window);
  203. gdk_flush ();
  204. // TODO: een aanroep die de eventuele grafische buffer ledigt,
  205. // zodat de gebruiker de grafica ziet ook al blijft Praat in hetzelfde event zitten
  206. #elif gdi
  207. /*GdiFlush ();*/
  208. #elif quartz
  209. if (d_drawingArea) {
  210. GuiShell shell = d_drawingArea -> d_shell;
  211. Melder_assert (shell);
  212. Melder_assert (shell -> d_cocoaShell);
  213. [shell -> d_cocoaShell flushWindow];
  214. NSEvent *nsEvent = [[d_macView window]
  215. nextEventMatchingMask: NSAnyEventMask
  216. untilDate: [NSDate distantPast]
  217. inMode: NSDefaultRunLoopMode
  218. dequeue: NO
  219. ];
  220. }
  221. #endif
  222. }
  223. void Graphics_flushWs (Graphics me) {
  224. my v_flushWs ();
  225. }
  226. void structGraphicsScreen :: v_clearWs () {
  227. #if cairo && gtk
  228. GdkRectangle rect;
  229. if (our d_x1DC < our d_x2DC) {
  230. rect.x = our d_x1DC;
  231. rect.width = our d_x2DC - our d_x1DC;
  232. } else {
  233. rect.x = our d_x2DC;
  234. rect.width = our d_x1DC - our d_x2DC;
  235. }
  236. if (our d_y1DC < our d_y2DC) {
  237. rect.y = our d_y1DC;
  238. rect.height = our d_y2DC - our d_y1DC;
  239. } else {
  240. rect.y = our d_y2DC;
  241. rect.height = our d_y1DC - our d_y2DC;
  242. }
  243. if (! d_cairoGraphicsContext) {
  244. trace (U"clear and null");
  245. //gdk_window_clear (our window);
  246. //gdk_window_invalidate_rect (our window, & rect, true); // BUG: it seems weird that this is necessary.
  247. } else {
  248. trace (U"clear and not null");
  249. cairo_set_source_rgb (d_cairoGraphicsContext, 1.0, 1.0, 1.0);
  250. cairo_rectangle (d_cairoGraphicsContext, rect.x, rect.y, rect.width, rect.height);
  251. cairo_fill (d_cairoGraphicsContext);
  252. cairo_set_source_rgb (d_cairoGraphicsContext, 0.0, 0.0, 0.0);
  253. }
  254. #elif gdi
  255. RECT rect;
  256. rect. left = rect. top = 0;
  257. rect. right = d_x2DC - d_x1DC;
  258. rect. bottom = d_y2DC - d_y1DC;
  259. FillRect (d_gdiGraphicsContext, & rect, GetStockBrush (WHITE_BRUSH));
  260. /*if (d_winWindow) SendMessage (d_winWindow, WM_ERASEBKGND, (WPARAM) d_gdiGraphicsContext, 0);*/
  261. #elif quartz
  262. GuiCocoaDrawingArea *cocoaDrawingArea = (GuiCocoaDrawingArea *) d_drawingArea -> d_widget;
  263. if (cocoaDrawingArea && ! [cocoaDrawingArea isHiddenOrHasHiddenAncestor]) { // can be called at destruction time
  264. NSRect rect;
  265. if (our d_x1DC < our d_x2DC) {
  266. rect.origin.x = our d_x1DC;
  267. rect.size.width = our d_x2DC - our d_x1DC;
  268. } else {
  269. rect.origin.x = our d_x2DC;
  270. rect.size.width = our d_x1DC - our d_x2DC;
  271. }
  272. if (our d_y1DC < our d_y2DC) {
  273. rect.origin.y = our d_y1DC;
  274. rect.size.height = our d_y2DC - our d_y1DC;
  275. } else {
  276. rect.origin.y = our d_y2DC;
  277. rect.size.height = our d_y1DC - our d_y2DC;
  278. }
  279. [cocoaDrawingArea lockFocus];
  280. CGContextRef context = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort];
  281. CGContextSaveGState (context);
  282. CGContextSetAlpha (context, 1.0);
  283. CGContextSetBlendMode (context, kCGBlendModeNormal);
  284. CGContextSetRGBFillColor (context, 1.0, 1.0, 1.0, 1.0);
  285. //rect.origin.x -= 1000;
  286. //rect.origin.y -= 1000;
  287. //rect.size.width += 2000;
  288. //rect.size.height += 2000;
  289. trace (U"clearing ", rect.origin.x, U" ", rect.origin.y, U" ", rect.size.width, U" ", rect.size.height);
  290. //CGContextTranslateCTM (context, 0, cocoaDrawingArea.bounds.size.height);
  291. //CGContextScaleCTM (context, 1.0, -1.0);
  292. CGContextFillRect (context, rect);
  293. //CGContextSynchronize (context);
  294. CGContextRestoreGState (context);
  295. [cocoaDrawingArea unlockFocus];
  296. //[cocoaDrawingArea setNeedsDisplay: YES];
  297. //[cocoaDrawingArea display];
  298. }
  299. #endif
  300. }
  301. void Graphics_clearWs (Graphics me) {
  302. my v_clearWs ();
  303. }
  304. void structGraphicsScreen :: v_updateWs () {
  305. /*
  306. * A function that invalidates the graphics.
  307. * This function is typically called by the owner of the drawing area
  308. * whenever the data to be displayed in the drawing area has changed;
  309. * the idea is to generate an expose event to which the drawing area will
  310. * respond by redrawing its contents from the (changed) data.
  311. */
  312. #if cairo && gtk
  313. //GdkWindow *window = gtk_widget_get_parent_window (GTK_WIDGET (our d_drawingArea -> d_widget));
  314. GdkRectangle rect;
  315. if (our d_x1DC < our d_x2DC) {
  316. rect.x = our d_x1DC;
  317. rect.width = our d_x2DC - our d_x1DC;
  318. } else {
  319. rect.x = our d_x2DC;
  320. rect.width = our d_x1DC - our d_x2DC;
  321. }
  322. if (our d_y1DC < our d_y2DC) {
  323. rect.y = our d_y1DC;
  324. rect.height = our d_y2DC - our d_y1DC;
  325. } else {
  326. rect.y = our d_y2DC;
  327. rect.height = our d_y1DC - our d_y2DC;
  328. }
  329. if (our d_cairoGraphicsContext && our d_drawingArea) { // update clipping rectangle to new graphics size
  330. cairo_reset_clip (our d_cairoGraphicsContext);
  331. cairo_rectangle (our d_cairoGraphicsContext, rect.x, rect.y, rect.width, rect.height);
  332. cairo_clip (our d_cairoGraphicsContext);
  333. }
  334. #if ALLOW_GDK_DRAWING
  335. gdk_window_clear (our d_window);
  336. #endif
  337. gdk_window_invalidate_rect (our d_window, & rect, true);
  338. //gdk_window_process_updates (our d_window, true);
  339. #elif gdi
  340. //clear (this); // lll
  341. if (our d_winWindow) InvalidateRect (our d_winWindow, nullptr, true);
  342. #elif quartz
  343. NSView *view = our d_macView;
  344. Melder_assert (!! view);
  345. NSRect rect;
  346. if (our d_x1DC < our d_x2DC) {
  347. rect.origin.x = our d_x1DC;
  348. rect.size.width = our d_x2DC - our d_x1DC;
  349. } else {
  350. rect.origin.x = our d_x2DC;
  351. rect.size.width = our d_x1DC - our d_x2DC;
  352. }
  353. if (our d_y1DC < our d_y2DC) {
  354. rect.origin.y = our d_y1DC;
  355. rect.size.height = our d_y2DC - our d_y1DC;
  356. } else {
  357. rect.origin.y = our d_y2DC;
  358. rect.size.height = our d_y1DC - our d_y2DC;
  359. }
  360. //[view setNeedsDisplayInRect: rect];
  361. [view setNeedsDisplay: YES];
  362. #endif
  363. }
  364. void Graphics_updateWs (Graphics me) {
  365. if (me)
  366. my v_updateWs ();
  367. }
  368. void Graphics_beginMovieFrame (Graphics any, Graphics_Colour *p_colour) {
  369. if (any -> classInfo == classGraphicsScreen) {
  370. GraphicsScreen me = (GraphicsScreen) any;
  371. Graphics_clearRecording (me);
  372. Graphics_startRecording (me);
  373. if (p_colour) {
  374. Graphics_setViewport (me, 0.0, 1.0, 0.0, 1.0);
  375. Graphics_setColour (me, *p_colour);
  376. Graphics_setWindow (me, 0.0, 1.0, 0.0, 1.0);
  377. Graphics_fillRectangle (me, 0.0, 1.0, 0.0, 1.0);
  378. Graphics_setColour (me, Graphics_BLACK);
  379. }
  380. }
  381. }
  382. void Graphics_endMovieFrame (Graphics any, double frameDuration) {
  383. if (any -> classInfo == classGraphicsScreen) {
  384. GraphicsScreen me = (GraphicsScreen) any;
  385. Graphics_stopRecording (me);
  386. #if cairo || gdi
  387. my v_flushWs ();
  388. #elif quartz
  389. my v_updateWs ();
  390. GuiShell_drain (my d_drawingArea -> d_shell);
  391. #endif
  392. Melder_sleep (frameDuration);
  393. }
  394. }
  395. static int GraphicsScreen_init (GraphicsScreen me, void *voidDisplay, void *voidWindow) {
  396. /* Fill in new members. */
  397. #if cairo && gtk
  398. my d_display = (GdkDisplay *) gdk_display_get_default ();
  399. _GraphicsScreen_text_init (me);
  400. #if ALLOW_GDK_DRAWING
  401. trace (U"retrieving window");
  402. my d_window = GDK_DRAWABLE (GTK_WIDGET (voidDisplay) -> window);
  403. trace (U"retrieved window");
  404. my d_gdkGraphicsContext = gdk_gc_new (my d_window);
  405. #else
  406. my d_window = gtk_widget_get_window (GTK_WIDGET (voidDisplay));
  407. #endif
  408. my d_cairoGraphicsContext = gdk_cairo_create (my d_window);
  409. #elif gdi
  410. if (my printer) {
  411. my d_gdiGraphicsContext = (HDC) voidWindow;
  412. } else if (voidDisplay) {
  413. my d_gdiGraphicsContext = (HDC) voidDisplay;
  414. my metafile = true;
  415. } else {
  416. my d_winWindow = (HWND) voidWindow;
  417. my d_gdiGraphicsContext = GetDC (my d_winWindow); // window must have a constant display context; see XtInitialize ()
  418. }
  419. Melder_assert (my d_gdiGraphicsContext);
  420. SetBkMode (my d_gdiGraphicsContext, TRANSPARENT); // not the default!
  421. /*
  422. * Create pens and brushes.
  423. */
  424. my d_winPen = CreatePen (PS_SOLID, 0, RGB (0, 0, 0));
  425. my d_winBrush = CreateSolidBrush (RGB (0, 0, 0));
  426. SelectBrush (my d_gdiGraphicsContext, GetStockBrush (NULL_BRUSH));
  427. SetTextAlign (my d_gdiGraphicsContext, TA_LEFT | TA_BASELINE | TA_NOUPDATECP); // baseline is not the default!
  428. _GraphicsScreen_text_init (me);
  429. #elif quartz
  430. (void) voidDisplay;
  431. if (my printer) {
  432. my d_macView = (NSView *) voidWindow; // in case we do view-based printing
  433. //my d_macGraphicsContext = (CGContextRef) voidWindow; // in case we do context-based printing
  434. } else {
  435. my d_macView = (NSView *) voidWindow;
  436. (void) my d_macGraphicsContext; // will be retrieved from Core Graphics with every drawing command!
  437. }
  438. my d_macColour = theBlackColour;
  439. my d_depth = my resolution > 150 ? 1 : 8; /* BUG: replace by true depth (1=black/white) */
  440. _GraphicsScreen_text_init (me);
  441. #endif
  442. return 1;
  443. }
  444. autoGraphics Graphics_create_screen (void *display, void *window, int resolution) {
  445. autoGraphicsScreen me = Thing_new (GraphicsScreen);
  446. my screen = true;
  447. #if cairo
  448. _GraphicsCairo_tryToInitializePango ();
  449. #elif gdi
  450. my d_useGdiplus = _GraphicsWindows_tryToInitializeGdiPlus ();
  451. #elif quartz
  452. _GraphicsMacintosh_tryToInitializeQuartz ();
  453. #endif
  454. my yIsZeroAtTheTop = true;
  455. Graphics_init (me.get(), resolution);
  456. Graphics_setWsViewport (me.get(), 0.0, 100.0, 0.0, 100.0);
  457. GraphicsScreen_init (me.get(), display, window);
  458. return me.move();
  459. }
  460. autoGraphics Graphics_create_screenPrinter (void *display, void *window) {
  461. autoGraphicsScreen me = Thing_new (GraphicsScreen);
  462. my screen = true;
  463. my yIsZeroAtTheTop = true;
  464. my printer = true;
  465. #if cairo
  466. _GraphicsCairo_tryToInitializePango ();
  467. #elif gdi
  468. my d_useGdiplus = _GraphicsWindows_tryToInitializeGdiPlus ();
  469. #elif quartz
  470. _GraphicsMacintosh_tryToInitializeQuartz ();
  471. #endif
  472. Graphics_init (me.get(), thePrinter. resolution);
  473. my paperWidth = (double) thePrinter. paperWidth / thePrinter. resolution;
  474. my paperHeight = (double) thePrinter. paperHeight / thePrinter. resolution;
  475. //NSLog (@"Graphics_create_screenPrinter: %f %f", my paperWidth, my paperHeight);
  476. my d_x1DC = my d_x1DCmin = thePrinter. resolution / 2;
  477. my d_x2DC = my d_x2DCmax = (my paperWidth - 0.5) * thePrinter. resolution;
  478. my d_y1DC = my d_y1DCmin = thePrinter. resolution / 2;
  479. my d_y2DC = my d_y2DCmax = (my paperHeight - 0.5) * thePrinter. resolution;
  480. #if gdi
  481. /*
  482. * Map page coordinates to paper coordinates.
  483. */
  484. my d_x1DC -= GetDeviceCaps ((HDC) window, PHYSICALOFFSETX);
  485. my d_x2DC -= GetDeviceCaps ((HDC) window, PHYSICALOFFSETX);
  486. my d_y1DC -= GetDeviceCaps ((HDC) window, PHYSICALOFFSETY);
  487. my d_y2DC -= GetDeviceCaps ((HDC) window, PHYSICALOFFSETY);
  488. #endif
  489. Graphics_setWsWindow (me.get(), 0, my paperWidth - 1.0, 13.0 - my paperHeight, 12.0);
  490. GraphicsScreen_init (me.get(), display, window);
  491. return me.move();
  492. }
  493. autoGraphics Graphics_create_xmdrawingarea (GuiDrawingArea w) {
  494. trace (U"begin");
  495. autoGraphicsScreen me = Thing_new (GraphicsScreen);
  496. #if cairo && gtk
  497. GtkRequisition realsize;
  498. GtkAllocation allocation;
  499. #elif gdi
  500. Dimension width, height;
  501. #endif
  502. my d_drawingArea = static_cast <GuiDrawingArea> (w); /* Now !!!!!!!!!! */
  503. Melder_assert (my d_drawingArea -> d_widget);
  504. my screen = true;
  505. my yIsZeroAtTheTop = true;
  506. #if cairo
  507. _GraphicsCairo_tryToInitializePango ();
  508. #elif gdi
  509. my d_useGdiplus = _GraphicsWindows_tryToInitializeGdiPlus ();
  510. #elif quartz
  511. _GraphicsMacintosh_tryToInitializeQuartz ();
  512. #endif
  513. #if cairo && gtk
  514. Graphics_init (me.get(), Gui_getResolution (my d_drawingArea -> d_widget));
  515. GraphicsScreen_init (me.get(), GTK_WIDGET (my d_drawingArea -> d_widget), GTK_WIDGET (my d_drawingArea -> d_widget));
  516. #elif gdi
  517. Graphics_init (me.get(), Gui_getResolution (my d_drawingArea -> d_widget));
  518. GraphicsScreen_init (me.get(), XtDisplay (my d_drawingArea -> d_widget), XtWindow (my d_drawingArea -> d_widget));
  519. #elif quartz
  520. Graphics_init (me.get(), Gui_getResolution (nullptr));
  521. GraphicsScreen_init (me.get(), my d_drawingArea -> d_widget, my d_drawingArea -> d_widget);
  522. #endif
  523. #if cairo && gtk
  524. // fb: is really the request meant or rather the actual size, aka allocation?
  525. gtk_widget_size_request (GTK_WIDGET (my d_drawingArea -> d_widget), & realsize);
  526. gtk_widget_get_allocation (GTK_WIDGET (my d_drawingArea -> d_widget), & allocation);
  527. // HIER WAS IK
  528. trace (U"requested ", realsize.width, U" x ", realsize.height, U", allocated ", allocation.width, U" x ", allocation.height);
  529. Graphics_setWsViewport (me.get(), 0.0, realsize.width, 0.0, realsize.height);
  530. #elif gdi
  531. XtVaGetValues (my d_drawingArea -> d_widget, XmNwidth, & width, XmNheight, & height, nullptr);
  532. Graphics_setWsViewport (me.get(), 0.0, width, 0.0, height);
  533. #elif quartz
  534. NSView *view = (NSView *)my d_drawingArea -> d_widget;
  535. NSRect bounds = [view bounds];
  536. Graphics_setWsViewport (me.get(), 0.0, bounds.size.width, 0.0, bounds.size.height);
  537. #endif
  538. return me.move();
  539. }
  540. autoGraphics Graphics_create_pngfile (MelderFile file, int resolution,
  541. double x1inches, double x2inches, double y1inches, double y2inches)
  542. {
  543. autoGraphicsScreen me = Thing_new (GraphicsScreen);
  544. my screen = true;
  545. my yIsZeroAtTheTop = true;
  546. #if cairo
  547. _GraphicsCairo_tryToInitializePango ();
  548. #elif gdi
  549. my d_useGdiplus = _GraphicsWindows_tryToInitializeGdiPlus ();
  550. #elif quartz
  551. _GraphicsMacintosh_tryToInitializeQuartz ();
  552. #endif
  553. Graphics_init (me.get(), resolution);
  554. my d_isPng = true;
  555. my d_file = *file;
  556. my d_x1DC = my d_x1DCmin = 0;
  557. my d_x2DC = my d_x2DCmax = (x2inches - x1inches) * resolution;
  558. my d_y1DC = my d_y1DCmin = 0;
  559. my d_y2DC = my d_y2DCmax = (y2inches - y1inches) * resolution;
  560. Graphics_setWsWindow (me.get(), x1inches, x2inches, y1inches, y2inches);
  561. #if cairo
  562. my d_cairoSurface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
  563. (x2inches - x1inches) * resolution, (y2inches - y1inches) * resolution);
  564. my d_cairoGraphicsContext = cairo_create (my d_cairoSurface);
  565. //cairo_scale (my d_cairoGraphicsContext, 72.0 / resolution, 72.0 / resolution);
  566. /*
  567. * Fill in the whole area with a white background.
  568. */
  569. cairo_set_source_rgb (my d_cairoGraphicsContext, 1.0, 1.0, 1.0);
  570. cairo_rectangle (my d_cairoGraphicsContext, 0, 0, my d_x2DC, my d_y2DC);
  571. cairo_fill (my d_cairoGraphicsContext);
  572. cairo_set_source_rgb (my d_cairoGraphicsContext, 0.0, 0.0, 0.0);
  573. #elif gdi
  574. my metafile = true;
  575. HDC screenDC = GetDC (nullptr);
  576. my d_gdiGraphicsContext = CreateCompatibleDC (screenDC);
  577. trace (U"d_gdiGraphicsContext ", Melder_pointer (my d_gdiGraphicsContext));
  578. Melder_assert (my d_gdiGraphicsContext);
  579. my d_gdiBitmap = CreateCompatibleBitmap (screenDC, (x2inches - x1inches) * resolution, (y2inches - y1inches) * resolution);
  580. trace (U"d_gdiBitmap ", Melder_pointer (my d_gdiBitmap));
  581. Melder_assert (my d_gdiBitmap);
  582. ReleaseDC (nullptr, screenDC);
  583. SelectObject (my d_gdiGraphicsContext, my d_gdiBitmap);
  584. trace (U"bitmap selected into device context");
  585. my resolution = resolution;
  586. SetBkMode (my d_gdiGraphicsContext, TRANSPARENT);
  587. my d_winPen = CreatePen (PS_SOLID, 0, RGB (0, 0, 0));
  588. my d_winBrush = CreateSolidBrush (RGB (0, 0, 0));
  589. SetTextAlign (my d_gdiGraphicsContext, TA_LEFT | TA_BASELINE | TA_NOUPDATECP);
  590. /*
  591. * Fill in the whole area with a white background.
  592. */
  593. SelectPen (my d_gdiGraphicsContext, GetStockPen (NULL_PEN));
  594. SelectBrush (my d_gdiGraphicsContext, GetStockBrush (WHITE_BRUSH));
  595. Rectangle (my d_gdiGraphicsContext, 0, 0, my d_x2DC + 1, my d_y2DC + 1); // plus 1, in order to prevent two black edges
  596. SelectPen (my d_gdiGraphicsContext, GetStockPen (BLACK_PEN));
  597. SelectBrush (my d_gdiGraphicsContext, GetStockBrush (NULL_BRUSH));
  598. #elif quartz
  599. integer width = (x2inches - x1inches) * resolution, height = (y2inches - y1inches) * resolution;
  600. integer stride = width * 4;
  601. stride = (stride + 15) & ~15; // CommonCode/AppDrawing.c: "a multiple of 16 bytes, for best performance"
  602. my d_bits = Melder_malloc (uint8_t, stride * height);
  603. static CGColorSpaceRef colourSpace = nullptr;
  604. if (! colourSpace) {
  605. colourSpace = CGColorSpaceCreateWithName (kCGColorSpaceGenericRGB);
  606. Melder_assert (colourSpace);
  607. }
  608. my d_macGraphicsContext = CGBitmapContextCreate (my d_bits,
  609. width, height,
  610. 8, // bits per component
  611. stride,
  612. colourSpace,
  613. kCGImageAlphaPremultipliedLast);
  614. if (! my d_macGraphicsContext)
  615. Melder_throw (U"Could not create PNG file ", file, U".");
  616. CGRect rect = CGRectMake (0, 0, width, height);
  617. CGContextSetAlpha (my d_macGraphicsContext, 1.0);
  618. CGContextSetBlendMode (my d_macGraphicsContext, kCGBlendModeNormal);
  619. CGContextSetRGBFillColor (my d_macGraphicsContext, 1.0, 1.0, 1.0, 1.0);
  620. CGContextFillRect (my d_macGraphicsContext, rect);
  621. CGContextTranslateCTM (my d_macGraphicsContext, 0, height);
  622. CGContextScaleCTM (my d_macGraphicsContext, 1.0, -1.0);
  623. #endif
  624. return me.move();
  625. }
  626. autoGraphics Graphics_create_pdffile (MelderFile file, int resolution,
  627. double x1inches, double x2inches, double y1inches, double y2inches)
  628. {
  629. autoGraphicsScreen me = Thing_new (GraphicsScreen);
  630. my screen = true;
  631. my yIsZeroAtTheTop = true;
  632. #if cairo
  633. _GraphicsCairo_tryToInitializePango ();
  634. #elif quartz
  635. _GraphicsMacintosh_tryToInitializeQuartz ();
  636. #endif
  637. Graphics_init (me.get(), resolution);
  638. #if cairo
  639. my d_cairoSurface = cairo_pdf_surface_create (Melder_peek32to8 (file -> path),
  640. ( isdefined (x1inches) ? x2inches - x1inches : x2inches ) * 72.0,
  641. ( isdefined (y1inches) ? y2inches - y1inches : y2inches ) * 72.0);
  642. my d_cairoGraphicsContext = cairo_create (my d_cairoSurface);
  643. my d_x1DC = my d_x1DCmin = 0;
  644. my d_x2DC = my d_x2DCmax = ( isdefined (x1inches) ? 7.5 : x2inches ) * resolution;
  645. my d_y1DC = my d_y1DCmin = 0;
  646. my d_y2DC = my d_y2DCmax = ( isdefined (y1inches) ? 11.0 : y2inches ) * resolution;
  647. Graphics_setWsWindow (me.get(),
  648. isdefined (x1inches) ? 0.0 : 0.0, isdefined (x1inches) ? 7.5 : x2inches,
  649. isdefined (y1inches) ? 1.0 : 0.0, isdefined (y1inches) ? 12.0 : y2inches);
  650. cairo_scale (my d_cairoGraphicsContext, 72.0 / resolution, 72.0 / resolution);
  651. #elif quartz
  652. CFURLRef url = CFURLCreateWithFileSystemPath (nullptr, (CFStringRef) Melder_peek32toCfstring (file -> path), kCFURLPOSIXPathStyle, false);
  653. CGRect rect = CGRectMake (0, 0,
  654. ( isdefined (x1inches) ? x2inches - x1inches : x2inches ) * 72.0,
  655. ( isdefined (y1inches) ? y2inches - y1inches : y2inches ) * 72.0); // don't tire PDF viewers with funny origins
  656. CFStringRef key = (CFStringRef) Melder_peek32toCfstring (U"Creator");
  657. CFStringRef value = (CFStringRef) Melder_peek32toCfstring (U"Praat");
  658. CFIndex numberOfValues = 1;
  659. CFDictionaryRef dictionary = CFDictionaryCreate (nullptr, (const void **) & key, (const void **) & value, numberOfValues,
  660. & kCFTypeDictionaryKeyCallBacks, & kCFTypeDictionaryValueCallBacks);
  661. my d_macGraphicsContext = CGPDFContextCreateWithURL (url, & rect, dictionary);
  662. CFRelease (url);
  663. CFRelease (dictionary);
  664. if (! my d_macGraphicsContext)
  665. Melder_throw (U"Could not create PDF file ", file, U".");
  666. my d_x1DC = my d_x1DCmin = 0;
  667. my d_x2DC = my d_x2DCmax = ( isdefined (x1inches) ? 7.5 : x2inches ) * resolution;
  668. my d_y1DC = my d_y1DCmin = 0;
  669. my d_y2DC = my d_y2DCmax = ( isdefined (y1inches) ? 11.0 : y2inches ) * resolution;
  670. Graphics_setWsWindow (me.get(),
  671. ( isdefined (x1inches) ? 0.0 : 0.0 ), ( isdefined (x1inches) ? 7.5 : x2inches ),
  672. ( isdefined (y1inches) ? 1.0 : 0.0 ), ( isdefined (y1inches) ? 12.0 : y2inches ));
  673. CGContextBeginPage (my d_macGraphicsContext, & rect);
  674. CGContextScaleCTM (my d_macGraphicsContext, 72.0 / resolution, 72.0 / resolution);
  675. CGContextTranslateCTM (my d_macGraphicsContext,
  676. ( isdefined (x1inches) ? - x1inches : 0.0 ) * resolution,
  677. ( isdefined (y1inches) ? (12.0 - y1inches) : y2inches ) * resolution);
  678. CGContextScaleCTM (my d_macGraphicsContext, 1.0, -1.0);
  679. #endif
  680. return me.move();
  681. }
  682. autoGraphics Graphics_create_pdf (void *context, int resolution,
  683. double x1inches, double x2inches, double y1inches, double y2inches)
  684. {
  685. autoGraphicsScreen me = Thing_new (GraphicsScreen);
  686. my screen = true;
  687. my yIsZeroAtTheTop = true;
  688. #if quartz
  689. _GraphicsMacintosh_tryToInitializeQuartz ();
  690. #endif
  691. Graphics_init (me.get(), resolution);
  692. #if quartz
  693. my d_macGraphicsContext = static_cast <CGContext *> (context);
  694. CGRect rect = CGRectMake (0, 0, (x2inches - x1inches) * 72, (y2inches - y1inches) * 72); // don't tire PDF viewers with funny origins
  695. my d_x1DC = my d_x1DCmin = 0;
  696. my d_x2DC = my d_x2DCmax = 7.5 * resolution;
  697. my d_y1DC = my d_y1DCmin = 0;
  698. my d_y2DC = my d_y2DCmax = 11.0 * resolution;
  699. Graphics_setWsWindow (me.get(), 0, 7.5, 1.0, 12.0);
  700. Melder_assert (my d_macGraphicsContext);
  701. CGContextBeginPage (my d_macGraphicsContext, & rect);
  702. CGContextScaleCTM (my d_macGraphicsContext, 72.0 / resolution, 72.0 / resolution);
  703. CGContextTranslateCTM (my d_macGraphicsContext, - x1inches * resolution, (12.0 - y1inches) * resolution);
  704. CGContextScaleCTM (my d_macGraphicsContext, 1.0, -1.0);
  705. #endif
  706. return me.move();
  707. }
  708. #if cairo
  709. void *Graphics_x_getCR (Graphics me) {
  710. return ((GraphicsScreen) me) -> d_cairoGraphicsContext;
  711. }
  712. void Graphics_x_setCR (Graphics me, void *cairoGraphicsContext) {
  713. ((GraphicsScreen) me) -> d_cairoGraphicsContext = (cairo_t *) cairoGraphicsContext;
  714. }
  715. #endif
  716. #if quartz
  717. void GraphicsQuartz_initDraw (GraphicsScreen me) {
  718. if (my d_macView) {
  719. [my d_macView lockFocus];
  720. //if (! my printer) {
  721. my d_macGraphicsContext = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort];
  722. //}
  723. Melder_assert (my d_macGraphicsContext);
  724. if (my printer) {
  725. //CGContextTranslateCTM (my d_macGraphicsContext, 0, [my d_macView bounds]. size. height);
  726. //CGContextScaleCTM (my d_macGraphicsContext, 1.0, -1.0);
  727. }
  728. }
  729. }
  730. void GraphicsQuartz_exitDraw (GraphicsScreen me) {
  731. if (my d_macView) {
  732. //CGContextSynchronize (my d_macGraphicsContext); // BUG: should not be needed
  733. [my d_macView unlockFocus];
  734. }
  735. }
  736. #endif
  737. /* End of file GraphicsScreen.cpp */