Skip to content

Commit

Permalink
feat: Allow user to choose if we need to build a ZIP file
Browse files Browse the repository at this point in the history
  • Loading branch information
Maxou44 committed Dec 22, 2024
1 parent 0c3531e commit 3f5fb9b
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 35 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@brick-a-brack/eagle-animation",
"description": "EagleAnimation is an awesome, modern, free and open-source animation software",
"version": "2.10.0",
"version": "2.10.1",
"private": false,
"author": {
"name": "Brick à Brack",
Expand Down
65 changes: 42 additions & 23 deletions src/renderer/actions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ export const Actions = {
return null;
},
APP_CAPABILITIES: async () => {
const capabilities = ['EXPORT_VIDEO', 'EXPORT_VIDEO_H264', 'EXPORT_VIDEO_VP8', 'EXPORT_VIDEO_PRORES', 'EXPORT_FRAMES'];
const capabilities = ['EXPORT_VIDEO', 'EXPORT_VIDEO_H264', 'EXPORT_VIDEO_VP8', 'EXPORT_VIDEO_PRORES', 'EXPORT_FRAMES', 'EXPORT_FRAMES_ZIP'];

// Firefox don't support photo mode
if (!isFirefox()) {
Expand All @@ -173,38 +173,34 @@ export const Actions = {

return capabilities;
},
EXPORT_SELECT_PATH: async () => {
try {
if ('showDirectoryPicker' in self) {
const dirHandle = await window.showDirectoryPicker();
currentDirectory = await dirHandle.getDirectoryHandle('frames', {
create: true,
});
EXPORT_SELECT_PATH: async (evt, { compress_as_zip = false }) => {
currentDirectory = null;
if (!compress_as_zip) {
try {
if ('showDirectoryPicker' in self) {
const dirHandle = await window.showDirectoryPicker();
currentDirectory = await dirHandle.getDirectoryHandle('frames', {
create: true,
});
return currentDirectory ? true : null;
}
} catch (err) {
currentDirectory = false;
return null;
}
} catch (err) {
currentDirectory = null;
}
return true;
},
EXPORT_BUFFER: async (evt, { buffer_id, buffer }) => {
await createBuffer(buffer_id, buffer);
},
EXPORT: async (evt, { project_id, track_id, mode = 'video', format = 'h264', frames = [], custom_output_framerate = false, custom_output_framerate_number = 10 }) => {
EXPORT: async (evt, { project_id, track_id, mode = 'video', format = 'h264', frames = [], custom_output_framerate = false, compress_as_zip = false, custom_output_framerate_number = 10 }) => {
const trackId = Number(track_id);
const project = await getProject(project_id);

// Frames export
if (mode === 'frames') {
// Use FileSystem API (Chromium only)
if (currentDirectory) {
for (let i = 0; i < frames.length; i++) {
const frame = frames[i];
const buffer = await getBuffer(frame.buffer_id);
const fileHandle = await currentDirectory.getFileHandle(`frame-${frame.index.toString().padStart(6, '0')}.${frame.extension}`, { create: true });
const writable = await fileHandle.createWritable();
await writable.write(buffer);
await writable.close();
}
currentDirectory = null;
} else {
if (compress_as_zip) {
// Fallback on regular ZIP
const zip = new JSZip();
for (let i = 0; i < frames.length; i++) {
Expand All @@ -215,6 +211,29 @@ export const Actions = {
zip.generateAsync({ type: 'blob' }).then((content) => {
saveAs(content, 'frames.zip');
});
} else if (currentDirectory !== null) {
// Use FileSystem API (Chromium only)
if (currentDirectory !== false) {
for (let i = 0; i < frames.length; i++) {
const frame = frames[i];
const buffer = await getBuffer(frame.buffer_id);
const fileHandle = await currentDirectory.getFileHandle(`frame-${frame.index.toString().padStart(6, '0')}.${frame.extension}`, { create: true });
const writable = await fileHandle.createWritable();
await writable.write(buffer);
await writable.close();
}
}
currentDirectory = null;
} else {
let blob = null;
for (let i = 0; i < frames.length; i++) {
const frame = frames[i];
const buffer = await getBuffer(frame.buffer_id);
const filename = `frame-${frame.index.toString().padStart(6, '0')}.${frame.extension}`;
blob = new Blob([buffer], { type: `image/${frame?.extension?.replace('jpg', 'jpeg') || 'jpeg'}` });
saveAs(blob, filename);
blob = null;
}
}
}

Expand Down
31 changes: 20 additions & 11 deletions src/renderer/views/Export.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ const Export = ({ t }) => {
customOutputFramerate: false,
customOutputFramerateNumber: 60,
matchAspectRatio: true,
compressAsZip: false
},
});

Expand Down Expand Up @@ -199,17 +200,18 @@ const Export = ({ t }) => {
data.mode === 'send'
? null
: await window.EA('EXPORT_SELECT_PATH', {
type: data.mode === 'video' ? 'FILE' : 'FOLDER',
format: data.format,
translations: {
EXPORT_FRAMES: t('Export animation frames'),
EXPORT_VIDEO: t('Export as video'),
DEFAULT_FILE_NAME: t('video'),
EXT_NAME: t('Video file'),
},
});

// Cancel on Electron, web version send '' as path
type: data.mode === 'video' ? 'FILE' : 'FOLDER',
format: data.format,
translations: {
EXPORT_FRAMES: t('Export animation frames'),
EXPORT_VIDEO: t('Export as video'),
DEFAULT_FILE_NAME: t('video'),
EXT_NAME: t('Video file'),
},
compress_as_zip: data.mode === 'frames' ? (data.compressAsZip && appCapabilities.includes('EXPORT_FRAMES_ZIP')) : false,
});

// Cancel if result is null, (dialog closed)
if (data.mode !== 'send' && outputPath === null) {
setIsInfosOpened(false);
setIsExporting(false);
Expand Down Expand Up @@ -252,6 +254,7 @@ const Export = ({ t }) => {
track_id: track,
event_key: settings.EVENT_KEY,
public_code: data.mode === 'send' ? newCode : undefined,
compress_as_zip: data.mode === 'frames' ? (data.compressAsZip && appCapabilities.includes('EXPORT_FRAMES_ZIP')) : false,
});

setIsExporting(false);
Expand Down Expand Up @@ -342,6 +345,12 @@ const Export = ({ t }) => {
</FormGroup>
)}

{['frames'].includes(watch('mode')) && appCapabilities.includes('EXPORT_FRAMES_ZIP') && (
<FormGroup label={t('ZIP')} description={t('Export frames in a ZIP file')}>
<Switch register={register('compressAsZip')} />
</FormGroup>
)}

<div style={{ display: 'flex', justifyContent: 'center' }}>
<ActionCard title={t('Export')} action={handleSubmit(handleExport)} sizeAuto secondary disabled={isInfosOpened} />
</div>
Expand Down

0 comments on commit 3f5fb9b

Please sign in to comment.