utils.ts 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. import {
  2. exportToCanvas as _exportToCanvas,
  3. exportToSvg as _exportToSvg,
  4. } from "../scene/export";
  5. import { getDefaultAppState } from "../appState";
  6. import { AppState, BinaryFiles } from "../types";
  7. import { ExcalidrawElement, NonDeleted } from "../element/types";
  8. import { getNonDeletedElements } from "../element";
  9. import { restore } from "../data/restore";
  10. import { MIME_TYPES } from "../constants";
  11. type ExportOpts = {
  12. elements: readonly NonDeleted<ExcalidrawElement>[];
  13. appState?: Partial<Omit<AppState, "offsetTop" | "offsetLeft">>;
  14. files: BinaryFiles | null;
  15. maxWidthOrHeight?: number;
  16. getDimensions?: (
  17. width: number,
  18. height: number,
  19. ) => { width: number; height: number; scale?: number };
  20. };
  21. export const exportToCanvas = ({
  22. elements,
  23. appState,
  24. files,
  25. maxWidthOrHeight,
  26. getDimensions,
  27. }: ExportOpts) => {
  28. const { elements: restoredElements, appState: restoredAppState } = restore(
  29. { elements, appState },
  30. null,
  31. null,
  32. );
  33. const { exportBackground, viewBackgroundColor } = restoredAppState;
  34. return _exportToCanvas(
  35. getNonDeletedElements(restoredElements),
  36. { ...restoredAppState, offsetTop: 0, offsetLeft: 0, width: 0, height: 0 },
  37. files || {},
  38. { exportBackground, viewBackgroundColor },
  39. (width: number, height: number) => {
  40. const canvas = document.createElement("canvas");
  41. if (maxWidthOrHeight) {
  42. if (typeof getDimensions === "function") {
  43. console.warn(
  44. "`getDimensions()` is ignored when `maxWidthOrHeight` is supplied.",
  45. );
  46. }
  47. const max = Math.max(width, height);
  48. const scale = maxWidthOrHeight / max;
  49. canvas.width = width * scale;
  50. canvas.height = height * scale;
  51. return {
  52. canvas,
  53. scale,
  54. };
  55. }
  56. const ret = getDimensions?.(width, height) || { width, height };
  57. canvas.width = ret.width;
  58. canvas.height = ret.height;
  59. return {
  60. canvas,
  61. scale: ret.scale ?? 1,
  62. };
  63. },
  64. );
  65. };
  66. export const exportToBlob = async (
  67. opts: ExportOpts & {
  68. mimeType?: string;
  69. quality?: number;
  70. },
  71. ): Promise<Blob | null> => {
  72. let { mimeType = MIME_TYPES.png, quality } = opts;
  73. if (mimeType === MIME_TYPES.png && typeof quality === "number") {
  74. console.warn(`"quality" will be ignored for "${MIME_TYPES.png}" mimeType`);
  75. }
  76. // typo in MIME type (should be "jpeg")
  77. if (mimeType === "image/jpg") {
  78. mimeType = MIME_TYPES.jpg;
  79. }
  80. if (mimeType === MIME_TYPES.jpg && !opts.appState?.exportBackground) {
  81. console.warn(
  82. `Defaulting "exportBackground" to "true" for "${MIME_TYPES.jpg}" mimeType`,
  83. );
  84. opts = {
  85. ...opts,
  86. appState: { ...opts.appState, exportBackground: true },
  87. };
  88. }
  89. const canvas = await exportToCanvas(opts);
  90. quality = quality ? quality : /image\/jpe?g/.test(mimeType) ? 0.92 : 0.8;
  91. return new Promise((resolve) => {
  92. canvas.toBlob(
  93. (blob: Blob | null) => {
  94. resolve(blob);
  95. },
  96. mimeType,
  97. quality,
  98. );
  99. });
  100. };
  101. export const exportToSvg = async ({
  102. elements,
  103. appState = getDefaultAppState(),
  104. files = {},
  105. exportPadding,
  106. }: Omit<ExportOpts, "getDimensions"> & {
  107. exportPadding?: number;
  108. }): Promise<SVGSVGElement> => {
  109. const { elements: restoredElements, appState: restoredAppState } = restore(
  110. { elements, appState },
  111. null,
  112. null,
  113. );
  114. return _exportToSvg(
  115. getNonDeletedElements(restoredElements),
  116. {
  117. ...restoredAppState,
  118. exportPadding,
  119. },
  120. files,
  121. );
  122. };
  123. export { serializeAsJSON, serializeLibraryAsJSON } from "../data/json";
  124. export { loadFromBlob, loadLibraryFromBlob } from "../data/blob";
  125. export { getFreeDrawSvgPath } from "../renderer/renderElement";