From bee71ef2673c269db47a4433831720b7ad0fb4e8 Mon Sep 17 00:00:00 2001 From: Ross Esmond Date: Thu, 25 Aug 2022 09:19:17 -0500 Subject: [PATCH] feat: added file type and quality options to rendering panel (#50) The quality setting won't effect PNG, as I believe PNG files have to use for a quality setting. The setting input will then be inert when PNG, the default, is used. There are other design options available, but this is the simplest option that avoids frustration for the user. The image/webp option will not work on Safari, and there is no check for this occurance. The best option would be a proactive error message. Closes #24 --- packages/core/src/Project.ts | 16 ++++++++-- packages/core/src/player/Player.ts | 16 +++++++++- packages/core/src/types/Canvas.ts | 1 + .../ui/src/components/sidebar/Rendering.tsx | 32 ++++++++++++++++++- 4 files changed, 60 insertions(+), 5 deletions(-) diff --git a/packages/core/src/Project.ts b/packages/core/src/Project.ts index a9f1f1d1..a2131562 100644 --- a/packages/core/src/Project.ts +++ b/packages/core/src/Project.ts @@ -1,7 +1,7 @@ import {Scene, SceneDescription} from './scenes'; import {Meta, Metadata} from './Meta'; import {EventDispatcher, ValueDispatcher} from './events'; -import {Size, CanvasColorSpace} from './types'; +import {Size, CanvasColorSpace, CanvasOutputMimeType} from './types'; import {AudioManager} from './media'; import {ifHot} from './utils'; @@ -72,6 +72,14 @@ export class Project { this.updateCanvas(); } + public set fileType(value: CanvasOutputMimeType) { + this._fileType = value; + } + + public set quality(value: number) { + this._quality = value; + } + public set speed(value: number) { this._speed = value; this.reloadAll(); @@ -119,6 +127,8 @@ export class Project { private readonly renderLookup: Record = {}; private _resolutionScale = 1; private _colorSpace: CanvasColorSpace = 'srgb'; + private _fileType: CanvasOutputMimeType = 'image/png'; + private _quality = 1; private _speed = 1; private framesPerSeconds = 30; private readonly sceneLookup: Record = {}; @@ -315,8 +325,8 @@ export class Project { }; hot.send('motion-canvas:export', { frame, - data: this.canvas.toDataURL('image/png'), - mimeType: 'image/png', + data: this.canvas.toDataURL(this._fileType, this._quality), + mimeType: this._fileType, }); }), ); diff --git a/packages/core/src/player/Player.ts b/packages/core/src/player/Player.ts index b446f374..f40ac33f 100644 --- a/packages/core/src/player/Player.ts +++ b/packages/core/src/player/Player.ts @@ -1,6 +1,6 @@ import type {Project} from '../Project'; import {EventDispatcher, ValueDispatcher} from '../events'; -import type {CanvasColorSpace} from '../types'; +import type {CanvasColorSpace, CanvasOutputMimeType} from '../types'; const MAX_AUDIO_DESYNC = 1 / 50; @@ -18,6 +18,8 @@ export interface PlayerState extends Record { fps: number; scale: number; colorSpace: CanvasColorSpace; + fileType: CanvasOutputMimeType; + quality: number; } interface PlayerCommands { @@ -43,6 +45,8 @@ export class Player { fps: 30, scale: 1, colorSpace: 'srgb', + fileType: 'image/png', + quality: 1, }); public get onFrameChanged() { @@ -174,6 +178,16 @@ export class Player { this.project.render(); } + public setFileType(fileType: CanvasOutputMimeType) { + this.project.fileType = fileType; + this.updateState({fileType}); + } + + public setQuality(quality: number) { + this.project.quality = quality; + this.updateState({quality}); + } + public requestPreviousFrame(): void { this.commands.seek = this.frame.current - this.state.current.speed; } diff --git a/packages/core/src/types/Canvas.ts b/packages/core/src/types/Canvas.ts index cf2cbe9d..7ca54d86 100644 --- a/packages/core/src/types/Canvas.ts +++ b/packages/core/src/types/Canvas.ts @@ -1 +1,2 @@ export type CanvasColorSpace = 'srgb' | 'display-p3'; +export type CanvasOutputMimeType = 'image/png' | 'image/jpeg' | 'image/webp'; diff --git a/packages/ui/src/components/sidebar/Rendering.tsx b/packages/ui/src/components/sidebar/Rendering.tsx index b99181dd..cfb4849e 100644 --- a/packages/ui/src/components/sidebar/Rendering.tsx +++ b/packages/ui/src/components/sidebar/Rendering.tsx @@ -2,7 +2,10 @@ import {usePlayerState} from '../../hooks'; import {Button, Group, Input, Label, Select} from '../controls'; import {Pane} from '../tabs'; import {usePlayer} from '../../contexts'; -import type {CanvasColorSpace} from '@motion-canvas/core/lib/types'; +import type { + CanvasColorSpace, + CanvasOutputMimeType, +} from '@motion-canvas/core/lib/types'; export function Rendering() { const player = usePlayer(); @@ -20,6 +23,12 @@ export function Rendering() { {value: 'display-p3', text: 'DCI-P3'}, ]; + const fileTypes = [ + {value: 'image/png', text: 'png'}, + {value: 'image/jpeg', text: 'jpeg'}, + {value: 'image/webp', text: 'webp'}, + ]; + return ( @@ -94,6 +103,27 @@ export function Rendering() { onChange={value => player.setColorSpace(value as CanvasColorSpace)} /> + + + { + const value = parseFloat((event.target as HTMLInputElement).value); + player.setQuality(value); + }} + /> +