Export negative offset bug fixes
This commit is contained in:
@@ -135,7 +135,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted } from 'vue';
|
import { ref, onMounted, toRef } from 'vue';
|
||||||
import FileUploader from './components/FileUploader.vue';
|
import FileUploader from './components/FileUploader.vue';
|
||||||
import SpriteCanvas from './components/SpriteCanvas.vue';
|
import SpriteCanvas from './components/SpriteCanvas.vue';
|
||||||
import Modal from './components/utilities/Modal.vue';
|
import Modal from './components/utilities/Modal.vue';
|
||||||
@@ -147,11 +147,13 @@
|
|||||||
import DarkModeToggle from './components/utilities/DarkModeToggle.vue';
|
import DarkModeToggle from './components/utilities/DarkModeToggle.vue';
|
||||||
import { useSprites } from './composables/useSprites';
|
import { useSprites } from './composables/useSprites';
|
||||||
import { useExport } from './composables/useExport';
|
import { useExport } from './composables/useExport';
|
||||||
|
import { useSettingsStore } from './stores/useSettingsStore';
|
||||||
import type { SpriteFile } from './types/sprites';
|
import type { SpriteFile } from './types/sprites';
|
||||||
|
|
||||||
|
const settingsStore = useSettingsStore();
|
||||||
const { sprites, columns, updateSpritePosition, updateSpriteCell, removeSprite, replaceSprite, addSprite, addSpriteWithResize, processImageFiles, alignSprites } = useSprites();
|
const { sprites, columns, updateSpritePosition, updateSpriteCell, removeSprite, replaceSprite, addSprite, addSpriteWithResize, processImageFiles, alignSprites } = useSprites();
|
||||||
|
|
||||||
const { downloadSpritesheet, exportSpritesheetJSON, importSpritesheetJSON, downloadAsGif, downloadAsZip } = useExport(sprites, columns);
|
const { downloadSpritesheet, exportSpritesheetJSON, importSpritesheetJSON, downloadAsGif, downloadAsZip } = useExport(sprites, columns, toRef(settingsStore, 'negativeSpacingEnabled'));
|
||||||
const isPreviewModalOpen = ref(false);
|
const isPreviewModalOpen = ref(false);
|
||||||
const isHelpModalOpen = ref(false);
|
const isHelpModalOpen = ref(false);
|
||||||
const isFeedbackModalOpen = ref(false);
|
const isFeedbackModalOpen = ref(false);
|
||||||
|
|||||||
@@ -5,7 +5,18 @@ import JSZip from 'jszip';
|
|||||||
import type { Sprite } from '../types/sprites';
|
import type { Sprite } from '../types/sprites';
|
||||||
import { getMaxDimensions } from './useSprites';
|
import { getMaxDimensions } from './useSprites';
|
||||||
|
|
||||||
export const useExport = (sprites: Ref<Sprite[]>, columns: Ref<number>) => {
|
export const useExport = (sprites: Ref<Sprite[]>, columns: Ref<number>, negativeSpacingEnabled: Ref<boolean>) => {
|
||||||
|
// Calculate negative spacing based on sprite dimensions
|
||||||
|
const calculateNegativeSpacing = (): number => {
|
||||||
|
if (!negativeSpacingEnabled.value || sprites.value.length === 0) return 0;
|
||||||
|
|
||||||
|
const { maxWidth, maxHeight } = getMaxDimensions(sprites.value);
|
||||||
|
const minWidth = Math.min(...sprites.value.map(s => s.width));
|
||||||
|
const minHeight = Math.min(...sprites.value.map(s => s.height));
|
||||||
|
const widthDiff = maxWidth - minWidth;
|
||||||
|
const heightDiff = maxHeight - minHeight;
|
||||||
|
return Math.max(widthDiff, heightDiff);
|
||||||
|
};
|
||||||
const downloadSpritesheet = () => {
|
const downloadSpritesheet = () => {
|
||||||
if (!sprites.value.length) {
|
if (!sprites.value.length) {
|
||||||
alert('Please upload or import sprites before downloading the spritesheet.');
|
alert('Please upload or import sprites before downloading the spritesheet.');
|
||||||
@@ -13,22 +24,25 @@ export const useExport = (sprites: Ref<Sprite[]>, columns: Ref<number>) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { maxWidth, maxHeight } = getMaxDimensions(sprites.value);
|
const { maxWidth, maxHeight } = getMaxDimensions(sprites.value);
|
||||||
|
const negativeSpacing = calculateNegativeSpacing();
|
||||||
|
const cellWidth = maxWidth + negativeSpacing;
|
||||||
|
const cellHeight = maxHeight + negativeSpacing;
|
||||||
const rows = Math.ceil(sprites.value.length / columns.value);
|
const rows = Math.ceil(sprites.value.length / columns.value);
|
||||||
|
|
||||||
const canvas = document.createElement('canvas');
|
const canvas = document.createElement('canvas');
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
if (!ctx) return;
|
if (!ctx) return;
|
||||||
|
|
||||||
canvas.width = maxWidth * columns.value;
|
canvas.width = cellWidth * columns.value;
|
||||||
canvas.height = maxHeight * rows;
|
canvas.height = cellHeight * rows;
|
||||||
ctx.imageSmoothingEnabled = false;
|
ctx.imageSmoothingEnabled = false;
|
||||||
|
|
||||||
sprites.value.forEach((sprite, index) => {
|
sprites.value.forEach((sprite, index) => {
|
||||||
const col = index % columns.value;
|
const col = index % columns.value;
|
||||||
const row = Math.floor(index / columns.value);
|
const row = Math.floor(index / columns.value);
|
||||||
const cellX = Math.floor(col * maxWidth);
|
const cellX = Math.floor(col * cellWidth);
|
||||||
const cellY = Math.floor(row * maxHeight);
|
const cellY = Math.floor(row * cellHeight);
|
||||||
ctx.drawImage(sprite.img, Math.floor(cellX + sprite.x), Math.floor(cellY + sprite.y));
|
ctx.drawImage(sprite.img, Math.floor(cellX + negativeSpacing + sprite.x), Math.floor(cellY + negativeSpacing + sprite.y));
|
||||||
});
|
});
|
||||||
|
|
||||||
const link = document.createElement('a');
|
const link = document.createElement('a');
|
||||||
@@ -133,20 +147,23 @@ export const useExport = (sprites: Ref<Sprite[]>, columns: Ref<number>) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { maxWidth, maxHeight } = getMaxDimensions(sprites.value);
|
const { maxWidth, maxHeight } = getMaxDimensions(sprites.value);
|
||||||
|
const negativeSpacing = calculateNegativeSpacing();
|
||||||
|
const cellWidth = maxWidth + negativeSpacing;
|
||||||
|
const cellHeight = maxHeight + negativeSpacing;
|
||||||
const canvas = document.createElement('canvas');
|
const canvas = document.createElement('canvas');
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
if (!ctx) return;
|
if (!ctx) return;
|
||||||
canvas.width = maxWidth;
|
canvas.width = cellWidth;
|
||||||
canvas.height = maxHeight;
|
canvas.height = cellHeight;
|
||||||
ctx.imageSmoothingEnabled = false;
|
ctx.imageSmoothingEnabled = false;
|
||||||
|
|
||||||
const gif = new GIF({ workers: 2, quality: 10, width: maxWidth, height: maxHeight, workerScript: gifWorkerUrl });
|
const gif = new GIF({ workers: 2, quality: 10, width: cellWidth, height: cellHeight, workerScript: gifWorkerUrl });
|
||||||
|
|
||||||
sprites.value.forEach(sprite => {
|
sprites.value.forEach(sprite => {
|
||||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
ctx.fillStyle = '#f9fafb';
|
ctx.fillStyle = '#f9fafb';
|
||||||
ctx.fillRect(0, 0, maxWidth, maxHeight);
|
ctx.fillRect(0, 0, cellWidth, cellHeight);
|
||||||
ctx.drawImage(sprite.img, Math.floor(sprite.x), Math.floor(sprite.y));
|
ctx.drawImage(sprite.img, Math.floor(negativeSpacing + sprite.x), Math.floor(negativeSpacing + sprite.y));
|
||||||
gif.addFrame(ctx, { copy: true, delay: 1000 / fps });
|
gif.addFrame(ctx, { copy: true, delay: 1000 / fps });
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -170,18 +187,21 @@ export const useExport = (sprites: Ref<Sprite[]>, columns: Ref<number>) => {
|
|||||||
|
|
||||||
const zip = new JSZip();
|
const zip = new JSZip();
|
||||||
const { maxWidth, maxHeight } = getMaxDimensions(sprites.value);
|
const { maxWidth, maxHeight } = getMaxDimensions(sprites.value);
|
||||||
|
const negativeSpacing = calculateNegativeSpacing();
|
||||||
|
const cellWidth = maxWidth + negativeSpacing;
|
||||||
|
const cellHeight = maxHeight + negativeSpacing;
|
||||||
const canvas = document.createElement('canvas');
|
const canvas = document.createElement('canvas');
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
if (!ctx) return;
|
if (!ctx) return;
|
||||||
canvas.width = maxWidth;
|
canvas.width = cellWidth;
|
||||||
canvas.height = maxHeight;
|
canvas.height = cellHeight;
|
||||||
ctx.imageSmoothingEnabled = false;
|
ctx.imageSmoothingEnabled = false;
|
||||||
|
|
||||||
sprites.value.forEach((sprite, index) => {
|
sprites.value.forEach((sprite, index) => {
|
||||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
ctx.fillStyle = '#f9fafb';
|
ctx.fillStyle = '#f9fafb';
|
||||||
ctx.fillRect(0, 0, maxWidth, maxHeight);
|
ctx.fillRect(0, 0, cellWidth, cellHeight);
|
||||||
ctx.drawImage(sprite.img, Math.floor(sprite.x), Math.floor(sprite.y));
|
ctx.drawImage(sprite.img, Math.floor(negativeSpacing + sprite.x), Math.floor(negativeSpacing + sprite.y));
|
||||||
const dataURL = canvas.toDataURL('image/png');
|
const dataURL = canvas.toDataURL('image/png');
|
||||||
const binary = atob(dataURL.split(',')[1]);
|
const binary = atob(dataURL.split(',')[1]);
|
||||||
const buf = new ArrayBuffer(binary.length);
|
const buf = new ArrayBuffer(binary.length);
|
||||||
|
|||||||
Reference in New Issue
Block a user