Graphics_record.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. /* Graphics_record.cpp
  2. *
  3. * Copyright (C) 1992-2011,2013,2014,2015,2016,2017 Paul Boersma
  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. #define RECORDING_HEADER_LENGTH 2
  20. double * _Graphics_check (Graphics me, integer number) {
  21. static bool messageHasAlreadyBeenShownOnce = false;
  22. double *result = nullptr;
  23. double *record = my record;
  24. integer nrecord = my nrecord;
  25. if (nrecord == 0) {
  26. nrecord = 1000;
  27. try {
  28. record = Melder_malloc (double, 1 + nrecord);
  29. } catch (MelderError) {
  30. if (messageHasAlreadyBeenShownOnce) {
  31. Melder_clearError ();
  32. } else {
  33. messageHasAlreadyBeenShownOnce = true;
  34. Melder_flushError (U"_Graphics_growRecorder: out of memory.\n"
  35. U"This message will not show up on future occasions."); // because of loop danger when redrawing
  36. }
  37. return nullptr;
  38. }
  39. my record = record; my nrecord = nrecord;
  40. }
  41. if (nrecord < my irecord + RECORDING_HEADER_LENGTH + number) {
  42. while (nrecord < my irecord + RECORDING_HEADER_LENGTH + number) nrecord *= 2;
  43. try {
  44. record = (double *) Melder_realloc (record, (1 + nrecord) * (integer) sizeof (double));
  45. } catch (MelderError) {
  46. if (messageHasAlreadyBeenShownOnce) {
  47. Melder_clearError ();
  48. } else {
  49. messageHasAlreadyBeenShownOnce = true;
  50. Melder_flushError (U"_Graphics_growRecorder: out of memory.\n"
  51. U"This message will not show up on future occasions."); // because of loop danger when redrawing
  52. }
  53. return nullptr;
  54. }
  55. my record = record; my nrecord = nrecord;
  56. }
  57. result = my record + my irecord;
  58. my irecord += number + RECORDING_HEADER_LENGTH;
  59. return result;
  60. }
  61. /***** RECORD AND PLAY *****/
  62. bool Graphics_startRecording (Graphics me) {
  63. bool wasRecording = my recording;
  64. my recording = true;
  65. return wasRecording;
  66. }
  67. bool Graphics_stopRecording (Graphics me) {
  68. bool wasRecording = my recording;
  69. my recording = false;
  70. return wasRecording;
  71. }
  72. void Graphics_clearRecording (Graphics me) {
  73. if (my record) {
  74. Melder_free (my record);
  75. my irecord = 0;
  76. my nrecord = 0;
  77. }
  78. }
  79. void Graphics_play (Graphics me, Graphics thee) {
  80. double *p = my record, *endp = p + my irecord;
  81. bool wasRecording = my recording;
  82. if (! p) return;
  83. my recording = false; // temporarily, in case me == thee
  84. while (p < endp) {
  85. #define get (* ++ p)
  86. #define iget (integer) (* ++ p)
  87. #define mget(n) (p += n, p - n)
  88. #define sget(n) ((char *) (p += n, p - n + 1))
  89. int opcode = (int) get;
  90. (void) (integer) get; // ignore number of arguments
  91. switch (opcode) {
  92. case SET_VIEWPORT: {
  93. double x1NDC = get, x2NDC = get, y1NDC = get, y2NDC = get;
  94. Graphics_setViewport (thee, x1NDC, x2NDC, y1NDC, y2NDC);
  95. } break;
  96. case SET_INNER: {
  97. Graphics_setInner (thee);
  98. } break;
  99. case UNSET_INNER: {
  100. Graphics_unsetInner (thee);
  101. } break;
  102. case SET_WINDOW: {
  103. double x1 = get, x2 = get, y1 = get, y2 = get;
  104. Graphics_setWindow (thee, x1, x2, y1, y2);
  105. } break;
  106. case TEXT: {
  107. double x = get, y = get;
  108. integer length = iget;
  109. char *text_utf8 = sget (length);
  110. Graphics_text (thee, x, y, Melder_peek8to32 (text_utf8));
  111. } break;
  112. case POLYLINE: {
  113. integer n = iget;
  114. double *x = mget (n), *y = mget (n);
  115. Graphics_polyline (thee, n, & x [1], & y [1]);
  116. } break;
  117. case LINE: {
  118. double x1 = get, y1 = get, x2 = get, y2 = get;
  119. Graphics_line (thee, x1, y1, x2, y2);
  120. } break;
  121. case ARROW: {
  122. double x1 = get, y1 = get, x2 = get, y2 = get;
  123. Graphics_arrow (thee, x1, y1, x2, y2);
  124. } break;
  125. case FILL_AREA: {
  126. integer n = iget;
  127. double *x = mget (n), *y = mget (n);
  128. Graphics_fillArea (thee, n, & x [1], & y [1]);
  129. } break;
  130. case FUNCTION: {
  131. integer n = iget;
  132. double x1 = get, x2 = get, *y = mget (n);
  133. Graphics_function (thee, y, 1, n, x1, x2);
  134. } break;
  135. case RECTANGLE: {
  136. double x1 = get, x2 = get, y1 = get, y2 = get;
  137. Graphics_rectangle (thee, x1, x2, y1, y2);
  138. } break;
  139. case FILL_RECTANGLE: {
  140. double x1 = get, x2 = get, y1 = get, y2 = get;
  141. Graphics_fillRectangle (thee, x1, x2, y1, y2);
  142. } break;
  143. case CIRCLE: {
  144. double x = get, y = get, r = get;
  145. Graphics_circle (thee, x, y, r);
  146. } break;
  147. case FILL_CIRCLE: {
  148. double x = get, y = get, r = get;
  149. Graphics_fillCircle (thee, x, y, r);
  150. } break;
  151. case ARC: {
  152. double x = get, y = get, r = get, fromAngle = get, toAngle = get;
  153. Graphics_arc (thee, x, y, r, fromAngle, toAngle);
  154. } break;
  155. case ARC_ARROW: {
  156. double x = get, y = get, r = get, fromAngle = get, toAngle = get;
  157. int arrowAtStart = (int) iget, arrowAtEnd = (int) iget;
  158. Graphics_arcArrow (thee, x, y, r, fromAngle, toAngle, arrowAtStart, arrowAtEnd);
  159. } break;
  160. case HIGHLIGHT: {
  161. double x1 = get, x2 = get, y1 = get, y2 = get;
  162. Graphics_highlight (thee, x1, x2, y1, y2);
  163. } break;
  164. case CELL_ARRAY: {
  165. double x1 = get, x2 = get, y1 = get, y2 = get, minimum = get, maximum = get;
  166. integer nrow = iget, ncol = iget;
  167. /*
  168. * We don't copy all the data into a new matrix.
  169. * Instead, we create row pointers z [1..nrow] that point directly into the recorded data.
  170. * This works because the data is a packed array of double, just as Graphics_cellArray expects.
  171. */
  172. double **z = Melder_malloc_f (double *, nrow);
  173. z [0] = p + 1;
  174. for (integer irow = 1; irow < nrow; irow ++) z [irow] = z [irow - 1] + ncol;
  175. p += nrow * ncol;
  176. Graphics_cellArray (thee, z, 0, ncol - 1, x1, x2,
  177. 0, nrow - 1, y1, y2, minimum, maximum);
  178. Melder_free (z);
  179. } break;
  180. case SET_FONT: {
  181. Graphics_setFont (thee, (enum kGraphics_font) get);
  182. } break;
  183. case SET_FONT_SIZE: {
  184. Graphics_setFontSize (thee, (int) get);
  185. } break;
  186. case SET_FONT_STYLE: {
  187. Graphics_setFontStyle (thee, (int) get);
  188. } break;
  189. case SET_TEXT_ALIGNMENT: {
  190. kGraphics_horizontalAlignment hor = (kGraphics_horizontalAlignment) iget;
  191. int vert = (int) iget;
  192. Graphics_setTextAlignment (thee, hor, vert);
  193. } break;
  194. case SET_TEXT_ROTATION: {
  195. Graphics_setTextRotation (thee, get);
  196. } break;
  197. case SET_LINE_TYPE: {
  198. Graphics_setLineType (thee, (int) get);
  199. } break;
  200. case SET_LINE_WIDTH: {
  201. Graphics_setLineWidth (thee, get);
  202. } break;
  203. case SET_STANDARD_COLOUR: { // only used in old Praat picture files
  204. int standardColour = (int) get;
  205. Graphics_Colour colour =
  206. standardColour == 0 ? Graphics_BLACK :
  207. standardColour == 1 ? Graphics_WHITE :
  208. standardColour == 2 ? Graphics_RED :
  209. standardColour == 3 ? Graphics_GREEN :
  210. standardColour == 4 ? Graphics_BLUE :
  211. standardColour == 5 ? Graphics_CYAN :
  212. standardColour == 6 ? Graphics_MAGENTA :
  213. standardColour == 7 ? Graphics_YELLOW :
  214. standardColour == 8 ? Graphics_MAROON :
  215. standardColour == 9 ? Graphics_LIME :
  216. standardColour == 10 ? Graphics_NAVY :
  217. standardColour == 11 ? Graphics_TEAL :
  218. standardColour == 12 ? Graphics_PURPLE :
  219. standardColour == 13 ? Graphics_OLIVE :
  220. standardColour == 14 ? Graphics_PINK :
  221. standardColour == 15 ? Graphics_SILVER :
  222. Graphics_GREY;
  223. Graphics_setColour (thee, colour);
  224. } break;
  225. case SET_GREY: {
  226. Graphics_setGrey (thee, get);
  227. } break;
  228. case MARK_GROUP: {
  229. Graphics_markGroup (thee);
  230. } break;
  231. case ELLIPSE: {
  232. double x1 = get, x2 = get, y1 = get, y2 = get;
  233. Graphics_ellipse (thee, x1, x2, y1, y2);
  234. } break;
  235. case FILL_ELLIPSE: {
  236. double x1 = get, x2 = get, y1 = get, y2 = get;
  237. Graphics_fillEllipse (thee, x1, x2, y1, y2);
  238. } break;
  239. case CIRCLE_MM: {
  240. double x = get, y = get, d = get;
  241. Graphics_circle_mm (thee, x, y, d);
  242. } break;
  243. case FILL_CIRCLE_MM: {
  244. double x = get, y = get, d = get;
  245. Graphics_fillCircle_mm (thee, x, y, d);
  246. } break;
  247. case IMAGE8: {
  248. double x1 = get, x2 = get, y1 = get, y2 = get;
  249. uint8 minimum = (uint8) iget, maximum = (uint8) iget;
  250. integer nrow = iget, ncol = iget;
  251. uint8 **z = NUMmatrix <uint8> (1, nrow, 1, ncol); // BUG memory
  252. for (integer irow = 1; irow <= nrow; irow ++)
  253. for (integer icol = 1; icol <= ncol; icol ++)
  254. z [irow] [icol] = (uint8) iget;
  255. Graphics_image8 (thee, z, 1, ncol, x1, x2, 1, nrow, y1, y2, minimum, maximum);
  256. NUMmatrix_free (z, 1, 1);
  257. } break;
  258. case UNHIGHLIGHT: {
  259. double x1 = get, x2 = get, y1 = get, y2 = get;
  260. Graphics_unhighlight (thee, x1, x2, y1, y2);
  261. } break;
  262. #if motif
  263. case XOR_ON: {
  264. Graphics_Colour colour; colour. red = get, colour. green = get, colour. blue = get;
  265. Graphics_xorOn (thee, colour);
  266. } break;
  267. case XOR_OFF: {
  268. Graphics_xorOff (thee);
  269. } break;
  270. #endif
  271. case RECTANGLE_MM: {
  272. double x = get, y = get, horSide = get, vertSide = get;
  273. Graphics_rectangle_mm (thee, x, y, horSide, vertSide);
  274. } break;
  275. case FILL_RECTANGLE_MM: {
  276. double x = get, y = get, horSide = get, vertSide = get;
  277. Graphics_fillRectangle_mm (thee, x, y, horSide, vertSide);
  278. } break;
  279. case SET_WS_WINDOW: {
  280. double x1NDC = get, x2NDC = get, y1NDC = get, y2NDC = get;
  281. Graphics_setWsWindow (thee, x1NDC, x2NDC, y1NDC, y2NDC);
  282. } break;
  283. case SET_WRAP_WIDTH: {
  284. Graphics_setWrapWidth (thee, get);
  285. } break;
  286. case SET_SECOND_INDENT: {
  287. Graphics_setSecondIndent (thee, get);
  288. } break;
  289. case SET_PERCENT_SIGN_IS_ITALIC: {
  290. Graphics_setPercentSignIsItalic (thee, (bool) get);
  291. } break;
  292. case SET_NUMBER_SIGN_IS_BOLD: {
  293. Graphics_setNumberSignIsBold (thee, (bool) get);
  294. } break;
  295. case SET_CIRCUMFLEX_IS_SUPERSCRIPT: {
  296. Graphics_setCircumflexIsSuperscript (thee, (bool) get);
  297. } break;
  298. case SET_UNDERSCORE_IS_SUBSCRIPT: {
  299. Graphics_setUnderscoreIsSubscript (thee, (bool) get);
  300. } break;
  301. case SET_DOLLAR_SIGN_IS_CODE: {
  302. Graphics_setDollarSignIsCode (thee, (bool) get);
  303. } break;
  304. case SET_AT_SIGN_IS_LINK: {
  305. Graphics_setAtSignIsLink (thee, (bool) get);
  306. } break;
  307. case BUTTON: {
  308. double x1 = get, x2 = get, y1 = get, y2 = get;
  309. Graphics_button (thee, x1, x2, y1, y2);
  310. } break;
  311. case ROUNDED_RECTANGLE: {
  312. double x1 = get, x2 = get, y1 = get, y2 = get, r = get;
  313. Graphics_roundedRectangle (thee, x1, x2, y1, y2, r);
  314. } break;
  315. case FILL_ROUNDED_RECTANGLE: {
  316. double x1 = get, x2 = get, y1 = get, y2 = get, r = get;
  317. Graphics_fillRoundedRectangle (thee, x1, x2, y1, y2, r);
  318. } break;
  319. case FILL_ARC: {
  320. double x = get, y = get, r = get, fromAngle = get, toAngle = get;
  321. Graphics_fillArc (thee, x, y, r, fromAngle, toAngle);
  322. } break;
  323. case INNER_RECTANGLE: {
  324. double x1 = get, x2 = get, y1 = get, y2 = get;
  325. Graphics_innerRectangle (thee, x1, x2, y1, y2);
  326. } break;
  327. case CELL_ARRAY8: {
  328. double x1 = get, x2 = get, y1 = get, y2 = get;
  329. uint8 minimum = (uint8) iget, maximum = (uint8) iget;
  330. integer nrow = iget, ncol = iget;
  331. uint8 **z = NUMmatrix <uint8> (1, nrow, 1, ncol); // BUG memory
  332. for (integer irow = 1; irow <= nrow; irow ++)
  333. for (integer icol = 1; icol <= ncol; icol ++)
  334. z [irow] [icol] = (uint8) iget;
  335. Graphics_cellArray8 (thee, z, 1, ncol, x1, x2, 1, nrow, y1, y2, minimum, maximum);
  336. NUMmatrix_free (z, 1, 1);
  337. } break;
  338. case IMAGE: {
  339. double x1 = get, x2 = get, y1 = get, y2 = get, minimum = get, maximum = get;
  340. integer nrow = iget, ncol = iget;
  341. /*
  342. * We don't copy all the data into a new matrix.
  343. * Instead, we create row pointers z [1..nrow] that point directly into the recorded data.
  344. * This works because the data is a packed array of double, just as Graphics_image expects.
  345. */
  346. double **z = Melder_malloc_f (double *, nrow);
  347. z [0] = p + 1;
  348. for (integer irow = 1; irow < nrow; irow ++) z [irow] = z [irow - 1] + ncol;
  349. p += nrow * ncol;
  350. Graphics_image (thee, z, 0, ncol - 1, x1, x2,
  351. 0, nrow - 1, y1, y2, minimum, maximum);
  352. Melder_free (z);
  353. } break;
  354. case HIGHLIGHT2: {
  355. double x1 = get, x2 = get, y1 = get, y2 = get, innerX1 = get, innerX2 = get, innerY1 = get, innerY2 = get;
  356. Graphics_highlight2 (thee, x1, x2, y1, y2, innerX1, innerX2, innerY1, innerY2);
  357. } break;
  358. case UNHIGHLIGHT2: {
  359. double x1 = get, x2 = get, y1 = get, y2 = get, innerX1 = get, innerX2 = get, innerY1 = get, innerY2 = get;
  360. Graphics_unhighlight2 (thee, x1, x2, y1, y2, innerX1, innerX2, innerY1, innerY2);
  361. } break;
  362. case SET_ARROW_SIZE: {
  363. Graphics_setArrowSize (thee, get);
  364. } break;
  365. case DOUBLE_ARROW: {
  366. double x1 = get, y1 = get, x2 = get, y2 = get;
  367. Graphics_doubleArrow (thee, x1, y1, x2, y2);
  368. } break;
  369. case SET_RGB_COLOUR: {
  370. Graphics_Colour colour;
  371. colour. red = get, colour. green = get, colour. blue = get;
  372. Graphics_setColour (thee, colour);
  373. } break;
  374. case IMAGE_FROM_FILE: {
  375. double x1 = get, x2 = get, y1 = get, y2 = get;
  376. integer length = iget;
  377. char *text_utf8 = sget (length);
  378. Graphics_imageFromFile (thee, Melder_peek8to32 (text_utf8), x1, x2, y1, y2);
  379. } break;
  380. case POLYLINE_CLOSED: {
  381. integer n = iget;
  382. double *x = mget (n), *y = mget (n);
  383. Graphics_polyline_closed (thee, n, & x [1], & y [1]);
  384. } break;
  385. case CELL_ARRAY_COLOUR: {
  386. double x1 = get, x2 = get, y1 = get, y2 = get, minimum = get, maximum = get;
  387. integer nrow = iget, ncol = iget;
  388. /*
  389. * We don't copy all the data into a new matrix.
  390. * Instead, we create row pointers z [1..nrow] that point directly into the recorded data.
  391. * This works because the data is a packed array of double_rgbt, just as Graphics_cellArray_colour expects.
  392. */
  393. double_rgbt **z = Melder_malloc_f (double_rgbt *, nrow);
  394. z [0] = (double_rgbt *) (p + 1);
  395. for (integer irow = 1; irow < nrow; irow ++) z [irow] = z [irow - 1] + ncol;
  396. p += nrow * ncol * 4;
  397. Graphics_cellArray_colour (thee, z, 0, ncol - 1, x1, x2,
  398. 0, nrow - 1, y1, y2, minimum, maximum);
  399. Melder_free (z);
  400. } break;
  401. case IMAGE_COLOUR: {
  402. double x1 = get, x2 = get, y1 = get, y2 = get, minimum = get, maximum = get;
  403. integer nrow = iget, ncol = iget;
  404. /*
  405. * We don't copy all the data into a new matrix.
  406. * Instead, we create row pointers z [1..nrow] that point directly into the recorded data.
  407. * This works because the data is a packed array of double_rgbt, just as Graphics_image_colour expects.
  408. */
  409. double_rgbt **z = Melder_malloc_f (double_rgbt *, nrow);
  410. z [0] = (double_rgbt *) (p + 1);
  411. for (integer irow = 1; irow < nrow; irow ++) z [irow] = z [irow - 1] + ncol;
  412. p += nrow * ncol * 4;
  413. Graphics_image_colour (thee, z, 0, ncol - 1, x1, x2,
  414. 0, nrow - 1, y1, y2, minimum, maximum);
  415. Melder_free (z);
  416. } break;
  417. case SET_COLOUR_SCALE: {
  418. Graphics_setColourScale (thee, (enum kGraphics_colourScale) get);
  419. } break;
  420. case SET_SPECKLE_SIZE: {
  421. Graphics_setSpeckleSize (thee, get);
  422. } break;
  423. case SPECKLE: {
  424. double x = get, y = get;
  425. Graphics_speckle (thee, x, y);
  426. } break;
  427. default:
  428. my recording = wasRecording;
  429. Melder_flushError (U"Graphics_play: unknown opcode (", opcode, U").\n", p [-1], U" ", p [1]);
  430. return;
  431. }
  432. }
  433. my recording = wasRecording;
  434. }
  435. void Graphics_writeRecordings (Graphics me, FILE *f) {
  436. double *p = my record, *endp = p + my irecord;
  437. if (! p) return;
  438. binputi32 (my irecord, f);
  439. while (p < endp) {
  440. #define get (* ++ p)
  441. int opcode = (int) get;
  442. binputr32 ((float) opcode, f);
  443. integer numberOfArguments = (integer) get;
  444. const integer largestIntegerRepresentableAs32BitFloat = 0x00FFFFFF;
  445. if (numberOfArguments > largestIntegerRepresentableAs32BitFloat) {
  446. binputr32 (-1.0, f);
  447. binputi32 (numberOfArguments, f);
  448. //Melder_warning ("This picture is very large!");
  449. } else {
  450. binputr32 ((float) numberOfArguments, f);
  451. }
  452. if (opcode == TEXT) {
  453. binputr32 (get, f); // x
  454. binputr32 (get, f); // y
  455. binputr32 (get, f); // length
  456. Melder_assert (sizeof (double) == 8);
  457. if ((integer) fwrite (++ p, 8, numberOfArguments - 3, f) < numberOfArguments - 3) // text
  458. Melder_throw (U"Error writing graphics recordings.");
  459. p += numberOfArguments - 4;
  460. } else if (opcode == IMAGE_FROM_FILE) {
  461. binputr32 (get, f); // x1
  462. binputr32 (get, f); // x2
  463. binputr32 (get, f); // y1
  464. binputr32 (get, f); // y2
  465. binputr32 (get, f); // length
  466. Melder_assert (sizeof (double) == 8);
  467. if ((integer) fwrite (++ p, 8, numberOfArguments - 5, f) < numberOfArguments - 5) // text
  468. Melder_throw (U"Error writing graphics recordings.");
  469. p += numberOfArguments - 6;
  470. } else {
  471. for (integer i = numberOfArguments; i > 0; i --) binputr32 (get, f);
  472. }
  473. }
  474. }
  475. void Graphics_readRecordings (Graphics me, FILE *f) {
  476. integer old_irecord = my irecord;
  477. integer added_irecord = 0;
  478. double* p = nullptr;
  479. double* endp = nullptr;
  480. integer numberOfArguments = 0;
  481. int opcode = 0;
  482. try {
  483. added_irecord = bingeti32 (f);
  484. p = _Graphics_check (me, added_irecord - RECORDING_HEADER_LENGTH);
  485. if (! p) return;
  486. Melder_assert (my irecord == old_irecord + added_irecord);
  487. endp = p + added_irecord;
  488. while (p < endp) {
  489. opcode = (int) bingetr32 (f);
  490. put (opcode);
  491. numberOfArguments = (integer) bingetr32 (f);
  492. if (numberOfArguments == -1)
  493. numberOfArguments = bingeti32 (f);
  494. put (numberOfArguments);
  495. if (opcode == TEXT) {
  496. put (bingetr32 (f)); // x
  497. put (bingetr32 (f)); // y
  498. put (bingetr32 (f)); // length
  499. if (fread (++ p, 8, (size_t) numberOfArguments - 3, f) < (size_t) numberOfArguments - 3) // text
  500. Melder_throw (U"Error reading graphics recordings.");
  501. p += numberOfArguments - 4;
  502. } else if (opcode == IMAGE_FROM_FILE) {
  503. put (bingetr32 (f)); // x1
  504. put (bingetr32 (f)); // x2
  505. put (bingetr32 (f)); // y1
  506. put (bingetr32 (f)); // y2
  507. put (bingetr32 (f)); // length
  508. if (fread (++ p, 8, (size_t) numberOfArguments - 5, f) < (size_t) numberOfArguments - 5) // text
  509. Melder_throw (U"Error reading graphics recordings.");
  510. p += numberOfArguments - 6;
  511. } else {
  512. for (integer i = numberOfArguments; i > 0; i --)
  513. put (bingetr32 (f));
  514. }
  515. }
  516. } catch (MelderError) {
  517. my irecord = old_irecord;
  518. Melder_throw (U"Error reading graphics record ", added_irecord - (integer) (endp - p),
  519. U" out of ", added_irecord, U".\nOpcode ", opcode, U", args ", numberOfArguments, U".");
  520. }
  521. }
  522. void Graphics_markGroup (Graphics me) {
  523. if (my recording) { op (MARK_GROUP, 0); }
  524. }
  525. void Graphics_undoGroup (Graphics me) {
  526. integer lastMark = 0; // not yet found
  527. integer jrecord = 0;
  528. while (jrecord < my irecord) { // keep looking for marks until the end
  529. int opcode = (int) my record [++ jrecord];
  530. integer number = (integer) my record [++ jrecord];
  531. if (opcode == MARK_GROUP) lastMark = jrecord - 1; // found a mark
  532. jrecord += number;
  533. }
  534. if (jrecord != my irecord) Melder_flushError (U"jrecord != my irecord: ", jrecord, U", ", my irecord);
  535. if (lastMark > 0) // found?
  536. my irecord = lastMark - 1; // forget all graphics from and including the last mark
  537. }
  538. /* End of file Graphics_record.cpp */