diff --git a/_locales/de_DE.json b/_locales/de_DE.json index ac09909..b6185fc 100644 --- a/_locales/de_DE.json +++ b/_locales/de_DE.json @@ -21,15 +21,18 @@ "thumbnail": "Als aktuelles Vorschaubild setzen", "thumbnailTitle": "Aktuellen Frame als benutzerdefiniertes 400×400-Vorschaubild dieses Elements setzen", "animatedThumbnailTitle": "Animiertes Vorschaubild erzeugen", - "animatedThumbnailNote": "Das aktuelle Vorschaubild wird ersetzt und kann vom Plugin nicht wiederhergestellt werden. Bei langen Animationen wird die Bildrate automatisch reduziert, um die Dateigröße zu begrenzen.", + "animatedThumbnailAttention": "Achtung:", + "animatedThumbnailNote": "Das erzeugte Vorschaubild ersetzt das vorhandene. Dieser Vorgang kann nicht rückgängig gemacht werden und ", + "animatedThumbnailDanger": "das ursprüngliche Vorschaubild kann nicht wiederhergestellt werden", + "animatedThumbnailSizeNote": ". Damit Animationsdaten nicht zu groß werden, wird die Datei unter die eingestellte Größe reduziert.", "animatedFormat": "Ausgabeformat", "animatedRange": "Animationsbereich", "animatedStart": "Start", "animatedEnd": "Ende", "framesUnit": "Frames", "animatedQuality": "Vorschaubildqualität", - "animatedMaxSize": "Dateigrößenlimit", - "animatedInvalidSize": "Geben Sie eine ganze Zahl zwischen 50 und 10240 KB ein", + "animatedMaxSize": "Vorschaubildgröße", + "animatedInvalidSize": "Geben Sie eine ganze Zahl zwischen 10 und 1024 KB ein", "animatedCompressing": "Animiertes Vorschaubild wird komprimiert {current}/{total}…", "animatedWebpUnavailable": "Diese Umgebung kann WebP nicht kodieren. Bitte APNG auswählen.", "animatedCannotFit": "Die Animation kann nicht auf {target} KB reduziert werden (mindestens etwa {actual} KB). Erhöhen Sie das Limit oder verkürzen Sie den Framebereich.", diff --git a/_locales/en.json b/_locales/en.json index 12b3bb3..2fb2505 100644 --- a/_locales/en.json +++ b/_locales/en.json @@ -21,15 +21,18 @@ "thumbnail": "Set current item thumbnail", "thumbnailTitle": "Set the current frame as this item's 400×400 custom thumbnail", "animatedThumbnailTitle": "Generate animated thumbnail", - "animatedThumbnailNote": "This replaces the current thumbnail and cannot be undone by the plugin. Frame count, color precision and detail are reduced first; if needed, dimensions are reduced progressively from 400×400.", + "animatedThumbnailAttention": "Warning:", + "animatedThumbnailNote": "The generated thumbnail replaces the existing thumbnail. This cannot be undone and ", + "animatedThumbnailDanger": "the original thumbnail cannot be restored", + "animatedThumbnailSizeNote": ". To prevent animated thumbnail data from becoming too large, the file will be reduced below the configured size.", "animatedFormat": "Output format", "animatedRange": "Animation range", "animatedStart": "Start", "animatedEnd": "End", "framesUnit": "frames", "animatedQuality": "Thumbnail quality", - "animatedMaxSize": "File size limit", - "animatedInvalidSize": "Enter a whole number between 50 and 10240 KB", + "animatedMaxSize": "Thumbnail size", + "animatedInvalidSize": "Enter a whole number between 10 and 1024 KB", "animatedCompressing": "Compressing animated thumbnail {current}/{total}…", "animatedWebpUnavailable": "This environment cannot encode WebP. Choose APNG instead.", "animatedCannotFit": "The animation cannot be reduced to {target} KB (minimum about {actual} KB). Increase the limit or shorten the frame range.", diff --git a/_locales/es_ES.json b/_locales/es_ES.json index 893d685..69fcb0a 100644 --- a/_locales/es_ES.json +++ b/_locales/es_ES.json @@ -21,15 +21,18 @@ "thumbnail": "Usar como miniatura actual", "thumbnailTitle": "Usar el fotograma actual como miniatura personalizada de 400×400 de este elemento", "animatedThumbnailTitle": "Generar miniatura animada", - "animatedThumbnailNote": "Esto reemplaza la miniatura actual y el complemento no puede restaurar la imagen anterior. Las animaciones largas reducen automáticamente la frecuencia de fotogramas para limitar el tamaño.", + "animatedThumbnailAttention": "Atención:", + "animatedThumbnailNote": "La miniatura generada reemplaza la existente. Esta acción no se puede deshacer y ", + "animatedThumbnailDanger": "la miniatura original no se puede restaurar", + "animatedThumbnailSizeNote": ". Para evitar datos de animación demasiado grandes, el archivo se ajustará por debajo del tamaño configurado.", "animatedFormat": "Formato de salida", "animatedRange": "Rango de animación", "animatedStart": "Inicio", "animatedEnd": "Fin", "framesUnit": "fotogramas", "animatedQuality": "Calidad de miniatura", - "animatedMaxSize": "Límite de tamaño", - "animatedInvalidSize": "Introduce un número entero entre 50 y 10240 KB", + "animatedMaxSize": "Tamaño de miniatura", + "animatedInvalidSize": "Introduce un número entero entre 10 y 1024 KB", "animatedCompressing": "Comprimiendo miniatura animada {current}/{total}…", "animatedWebpUnavailable": "Este entorno no puede codificar WebP. Selecciona APNG.", "animatedCannotFit": "No se puede reducir la animación a {target} KB (mínimo aproximado: {actual} KB). Aumenta el límite o acorta el rango.", diff --git a/_locales/ja_JP.json b/_locales/ja_JP.json index fcb391d..11be177 100644 --- a/_locales/ja_JP.json +++ b/_locales/ja_JP.json @@ -21,15 +21,18 @@ "thumbnail": "現在の項目のサムネイルに設定", "thumbnailTitle": "現在のフレームをこの項目の 400×400 カスタムサムネイルに設定", "animatedThumbnailTitle": "アニメーションサムネイルを生成", - "animatedThumbnailNote": "現在のサムネイルが置き換えられ、プラグインから元に戻すことはできません。長いアニメーションはファイルサイズを抑えるためフレームレートを自動的に下げます。", + "animatedThumbnailAttention": "注意:", + "animatedThumbnailNote": "生成されたサムネイルは既存のサムネイルを置き換えます。この操作は元に戻せず、", + "animatedThumbnailDanger": "元のサムネイルは復元できません", + "animatedThumbnailSizeNote": "。データが大きくなりすぎないよう、ファイルは設定サイズ以下に調整されます。", "animatedFormat": "出力形式", "animatedRange": "アニメーション範囲", "animatedStart": "開始", "animatedEnd": "終了", "framesUnit": "フレーム", "animatedQuality": "サムネイル品質", - "animatedMaxSize": "ファイルサイズ上限", - "animatedInvalidSize": "50 から 10240 KB までの整数を入力してください", + "animatedMaxSize": "サムネイルサイズ", + "animatedInvalidSize": "10 から 1024 KB までの整数を入力してください", "animatedCompressing": "アニメーションサムネイルを圧縮中 {current}/{total}…", "animatedWebpUnavailable": "この環境では WebP をエンコードできません。APNG を選択してください。", "animatedCannotFit": "アニメーションを {target} KB まで圧縮できません(最小約 {actual} KB)。上限を増やすかフレーム範囲を短くしてください。", diff --git a/_locales/ko_KR.json b/_locales/ko_KR.json index be202c0..ba801ab 100644 --- a/_locales/ko_KR.json +++ b/_locales/ko_KR.json @@ -21,15 +21,18 @@ "thumbnail": "현재 항목 썸네일로 설정", "thumbnailTitle": "현재 프레임을 이 항목의 400×400 사용자 지정 썸네일로 설정", "animatedThumbnailTitle": "애니메이션 썸네일 생성", - "animatedThumbnailNote": "현재 썸네일이 교체되며 플러그인에서 이전 이미지를 복원할 수 없습니다. 긴 애니메이션은 파일 크기를 줄이기 위해 프레임 속도를 자동으로 낮춥니다.", + "animatedThumbnailAttention": "주의:", + "animatedThumbnailNote": "생성된 썸네일은 기존 썸네일을 교체합니다. 이 작업은 취소할 수 없으며 ", + "animatedThumbnailDanger": "기존 썸네일을 복원할 수 없습니다", + "animatedThumbnailSizeNote": ". 데이터가 너무 커지지 않도록 파일은 설정한 크기 이하로 조정됩니다.", "animatedFormat": "출력 형식", "animatedRange": "애니메이션 범위", "animatedStart": "시작", "animatedEnd": "종료", "framesUnit": "프레임", "animatedQuality": "썸네일 품질", - "animatedMaxSize": "파일 크기 제한", - "animatedInvalidSize": "50~10240KB 사이의 정수를 입력하세요", + "animatedMaxSize": "썸네일 크기", + "animatedInvalidSize": "10~1024KB 사이의 정수를 입력하세요", "animatedCompressing": "애니메이션 썸네일 압축 중 {current}/{total}…", "animatedWebpUnavailable": "현재 환경에서 WebP를 인코딩할 수 없습니다. APNG를 선택하세요.", "animatedCannotFit": "애니메이션을 {target}KB로 줄일 수 없습니다(최소 약 {actual}KB). 제한을 높이거나 프레임 범위를 줄이세요.", diff --git a/_locales/ru_RU.json b/_locales/ru_RU.json index 43cfe6c..e036811 100644 --- a/_locales/ru_RU.json +++ b/_locales/ru_RU.json @@ -21,15 +21,18 @@ "thumbnail": "Сделать миниатюрой элемента", "thumbnailTitle": "Установить текущий кадр как пользовательскую миниатюру 400×400 для этого элемента", "animatedThumbnailTitle": "Создать анимированную миниатюру", - "animatedThumbnailNote": "Текущая миниатюра будет заменена, и плагин не сможет восстановить прежнее изображение. Для длинных анимаций частота кадров снижается автоматически.", + "animatedThumbnailAttention": "Внимание:", + "animatedThumbnailNote": "Созданная миниатюра заменит существующую. Это действие нельзя отменить, и ", + "animatedThumbnailDanger": "исходную миниатюру нельзя восстановить", + "animatedThumbnailSizeNote": ". Чтобы данные анимации не были слишком большими, файл будет уменьшен до размера ниже заданного.", "animatedFormat": "Формат вывода", "animatedRange": "Диапазон анимации", "animatedStart": "Начало", "animatedEnd": "Конец", "framesUnit": "кадров", "animatedQuality": "Качество миниатюры", - "animatedMaxSize": "Лимит размера файла", - "animatedInvalidSize": "Введите целое число от 50 до 10240 КБ", + "animatedMaxSize": "Размер миниатюры", + "animatedInvalidSize": "Введите целое число от 10 до 1024 КБ", "animatedCompressing": "Сжатие анимированной миниатюры {current}/{total}…", "animatedWebpUnavailable": "Эта среда не поддерживает кодирование WebP. Выберите APNG.", "animatedCannotFit": "Анимацию нельзя уменьшить до {target} КБ (минимум около {actual} КБ). Увеличьте лимит или сократите диапазон кадров.", diff --git a/_locales/zh_CN.json b/_locales/zh_CN.json index 4970cb1..04a1d44 100644 --- a/_locales/zh_CN.json +++ b/_locales/zh_CN.json @@ -20,16 +20,19 @@ "backgroundTitle": "50×50 方格背景,随画布移动和缩放,并参与混合模式", "thumbnail": "设为当前素材缩略图", "thumbnailTitle": "将当前帧设为当前素材的 400×400 自定义缩略图", - "animatedThumbnailTitle": "生成动画缩略图", - "animatedThumbnailNote": "生成后将替换所选素材的缩略图,插件无法自动恢复原图。将自动降低帧数、颜色精度和内部细节;仍超标时会把尺寸从 400×400 逐级调低。", + "animatedThumbnailTitle": "生成动态缩略图", + "animatedThumbnailAttention": "注意:", + "animatedThumbnailNote": "生成的缩略图会替换原有缩略图,该操作不可撤销且", + "animatedThumbnailDanger": "无法恢复原有缩略图", + "animatedThumbnailSizeNote": ",为避免动态缩略图数据过大,文件尺寸将调整至设定大小之下", "animatedFormat": "输出格式", "animatedRange": "动画范围", "animatedStart": "开始", "animatedEnd": "结束", "framesUnit": "帧", "animatedQuality": "缩略图质量", - "animatedMaxSize": "文件大小上限", - "animatedInvalidSize": "请输入 50 到 10240 KB 之间的整数", + "animatedMaxSize": "缩略图大小", + "animatedInvalidSize": "请输入 10 到 1024 KB 之间的整数", "animatedCompressing": "正在压缩动画缩略图 {current}/{total}…", "animatedWebpUnavailable": "当前环境不支持 WebP 编码,请选择 APNG", "animatedCannotFit": "无法在保留动画的前提下压缩到 {target} KB(最小约 {actual} KB),请提高上限或缩短帧范围", diff --git a/_locales/zh_TW.json b/_locales/zh_TW.json index 17bc692..0313dda 100644 --- a/_locales/zh_TW.json +++ b/_locales/zh_TW.json @@ -21,15 +21,18 @@ "thumbnail": "設為目前素材縮圖", "thumbnailTitle": "將目前影格設為目前素材的 400×400 自訂縮圖", "animatedThumbnailTitle": "產生動畫縮圖", - "animatedThumbnailNote": "產生後會取代目前素材縮圖,外掛無法自動復原原圖。會自動降低影格數、色彩精度和內部細節;仍超標時會將尺寸從 400×400 逐級調低。", + "animatedThumbnailAttention": "注意:", + "animatedThumbnailNote": "產生的縮圖會取代原有縮圖,該操作無法復原且", + "animatedThumbnailDanger": "無法恢復原有縮圖", + "animatedThumbnailSizeNote": ",為避免動態縮圖資料過大,檔案尺寸將調整至設定大小以下", "animatedFormat": "輸出格式", "animatedRange": "動畫範圍", "animatedStart": "開始", "animatedEnd": "結束", "framesUnit": "影格", "animatedQuality": "縮圖品質", - "animatedMaxSize": "檔案大小上限", - "animatedInvalidSize": "請輸入 50 到 10240 KB 之間的整數", + "animatedMaxSize": "縮圖大小", + "animatedInvalidSize": "請輸入 10 到 1024 KB 之間的整數", "animatedCompressing": "正在壓縮動畫縮圖 {current}/{total}…", "animatedWebpUnavailable": "目前環境不支援 WebP 編碼,請選擇 APNG", "animatedCannotFit": "無法在保留動畫的情況下壓縮到 {target} KB(最小約 {actual} KB),請提高上限或縮短影格範圍", diff --git a/js/spine-visible-bounds.js b/js/spine-visible-bounds.js new file mode 100644 index 0000000..e97270c --- /dev/null +++ b/js/spine-visible-bounds.js @@ -0,0 +1,26 @@ +'use strict'; + +function findAlphaBounds(rgba, width, height, threshold = 4) { + let left = width, top = height, right = 0, bottom = 0; + for (let y = 0; y < height; y++) { + for (let x = 0; x < width; x++) { + if (rgba[(y * width + x) * 4 + 3] <= threshold) continue; + left = Math.min(left, x); + top = Math.min(top, y); + right = Math.max(right, x + 1); + bottom = Math.max(bottom, y + 1); + } + } + return right > left && bottom > top ? { left, top, right, bottom } : null; +} + +function toWorldBounds(pixels, width, height, scale, centerX, centerY) { + if (!pixels || !isFinite(scale) || scale <= 0) return null; + const left = centerX + (pixels.left - width / 2) / scale; + const right = centerX + (pixels.right - width / 2) / scale; + const top = centerY - (pixels.top - height / 2) / scale; + const bottom = centerY - (pixels.bottom - height / 2) / scale; + return { x: left, y: bottom, width: right - left, height: top - bottom }; +} + +module.exports = { findAlphaBounds, toWorldBounds }; diff --git a/release/UNIVERSAL_SpineViewer/_locales/de_DE.json b/release/UNIVERSAL_SpineViewer/_locales/de_DE.json index ac09909..b6185fc 100644 --- a/release/UNIVERSAL_SpineViewer/_locales/de_DE.json +++ b/release/UNIVERSAL_SpineViewer/_locales/de_DE.json @@ -21,15 +21,18 @@ "thumbnail": "Als aktuelles Vorschaubild setzen", "thumbnailTitle": "Aktuellen Frame als benutzerdefiniertes 400×400-Vorschaubild dieses Elements setzen", "animatedThumbnailTitle": "Animiertes Vorschaubild erzeugen", - "animatedThumbnailNote": "Das aktuelle Vorschaubild wird ersetzt und kann vom Plugin nicht wiederhergestellt werden. Bei langen Animationen wird die Bildrate automatisch reduziert, um die Dateigröße zu begrenzen.", + "animatedThumbnailAttention": "Achtung:", + "animatedThumbnailNote": "Das erzeugte Vorschaubild ersetzt das vorhandene. Dieser Vorgang kann nicht rückgängig gemacht werden und ", + "animatedThumbnailDanger": "das ursprüngliche Vorschaubild kann nicht wiederhergestellt werden", + "animatedThumbnailSizeNote": ". Damit Animationsdaten nicht zu groß werden, wird die Datei unter die eingestellte Größe reduziert.", "animatedFormat": "Ausgabeformat", "animatedRange": "Animationsbereich", "animatedStart": "Start", "animatedEnd": "Ende", "framesUnit": "Frames", "animatedQuality": "Vorschaubildqualität", - "animatedMaxSize": "Dateigrößenlimit", - "animatedInvalidSize": "Geben Sie eine ganze Zahl zwischen 50 und 10240 KB ein", + "animatedMaxSize": "Vorschaubildgröße", + "animatedInvalidSize": "Geben Sie eine ganze Zahl zwischen 10 und 1024 KB ein", "animatedCompressing": "Animiertes Vorschaubild wird komprimiert {current}/{total}…", "animatedWebpUnavailable": "Diese Umgebung kann WebP nicht kodieren. Bitte APNG auswählen.", "animatedCannotFit": "Die Animation kann nicht auf {target} KB reduziert werden (mindestens etwa {actual} KB). Erhöhen Sie das Limit oder verkürzen Sie den Framebereich.", diff --git a/release/UNIVERSAL_SpineViewer/_locales/en.json b/release/UNIVERSAL_SpineViewer/_locales/en.json index 12b3bb3..2fb2505 100644 --- a/release/UNIVERSAL_SpineViewer/_locales/en.json +++ b/release/UNIVERSAL_SpineViewer/_locales/en.json @@ -21,15 +21,18 @@ "thumbnail": "Set current item thumbnail", "thumbnailTitle": "Set the current frame as this item's 400×400 custom thumbnail", "animatedThumbnailTitle": "Generate animated thumbnail", - "animatedThumbnailNote": "This replaces the current thumbnail and cannot be undone by the plugin. Frame count, color precision and detail are reduced first; if needed, dimensions are reduced progressively from 400×400.", + "animatedThumbnailAttention": "Warning:", + "animatedThumbnailNote": "The generated thumbnail replaces the existing thumbnail. This cannot be undone and ", + "animatedThumbnailDanger": "the original thumbnail cannot be restored", + "animatedThumbnailSizeNote": ". To prevent animated thumbnail data from becoming too large, the file will be reduced below the configured size.", "animatedFormat": "Output format", "animatedRange": "Animation range", "animatedStart": "Start", "animatedEnd": "End", "framesUnit": "frames", "animatedQuality": "Thumbnail quality", - "animatedMaxSize": "File size limit", - "animatedInvalidSize": "Enter a whole number between 50 and 10240 KB", + "animatedMaxSize": "Thumbnail size", + "animatedInvalidSize": "Enter a whole number between 10 and 1024 KB", "animatedCompressing": "Compressing animated thumbnail {current}/{total}…", "animatedWebpUnavailable": "This environment cannot encode WebP. Choose APNG instead.", "animatedCannotFit": "The animation cannot be reduced to {target} KB (minimum about {actual} KB). Increase the limit or shorten the frame range.", diff --git a/release/UNIVERSAL_SpineViewer/_locales/es_ES.json b/release/UNIVERSAL_SpineViewer/_locales/es_ES.json index 893d685..69fcb0a 100644 --- a/release/UNIVERSAL_SpineViewer/_locales/es_ES.json +++ b/release/UNIVERSAL_SpineViewer/_locales/es_ES.json @@ -21,15 +21,18 @@ "thumbnail": "Usar como miniatura actual", "thumbnailTitle": "Usar el fotograma actual como miniatura personalizada de 400×400 de este elemento", "animatedThumbnailTitle": "Generar miniatura animada", - "animatedThumbnailNote": "Esto reemplaza la miniatura actual y el complemento no puede restaurar la imagen anterior. Las animaciones largas reducen automáticamente la frecuencia de fotogramas para limitar el tamaño.", + "animatedThumbnailAttention": "Atención:", + "animatedThumbnailNote": "La miniatura generada reemplaza la existente. Esta acción no se puede deshacer y ", + "animatedThumbnailDanger": "la miniatura original no se puede restaurar", + "animatedThumbnailSizeNote": ". Para evitar datos de animación demasiado grandes, el archivo se ajustará por debajo del tamaño configurado.", "animatedFormat": "Formato de salida", "animatedRange": "Rango de animación", "animatedStart": "Inicio", "animatedEnd": "Fin", "framesUnit": "fotogramas", "animatedQuality": "Calidad de miniatura", - "animatedMaxSize": "Límite de tamaño", - "animatedInvalidSize": "Introduce un número entero entre 50 y 10240 KB", + "animatedMaxSize": "Tamaño de miniatura", + "animatedInvalidSize": "Introduce un número entero entre 10 y 1024 KB", "animatedCompressing": "Comprimiendo miniatura animada {current}/{total}…", "animatedWebpUnavailable": "Este entorno no puede codificar WebP. Selecciona APNG.", "animatedCannotFit": "No se puede reducir la animación a {target} KB (mínimo aproximado: {actual} KB). Aumenta el límite o acorta el rango.", diff --git a/release/UNIVERSAL_SpineViewer/_locales/ja_JP.json b/release/UNIVERSAL_SpineViewer/_locales/ja_JP.json index fcb391d..11be177 100644 --- a/release/UNIVERSAL_SpineViewer/_locales/ja_JP.json +++ b/release/UNIVERSAL_SpineViewer/_locales/ja_JP.json @@ -21,15 +21,18 @@ "thumbnail": "現在の項目のサムネイルに設定", "thumbnailTitle": "現在のフレームをこの項目の 400×400 カスタムサムネイルに設定", "animatedThumbnailTitle": "アニメーションサムネイルを生成", - "animatedThumbnailNote": "現在のサムネイルが置き換えられ、プラグインから元に戻すことはできません。長いアニメーションはファイルサイズを抑えるためフレームレートを自動的に下げます。", + "animatedThumbnailAttention": "注意:", + "animatedThumbnailNote": "生成されたサムネイルは既存のサムネイルを置き換えます。この操作は元に戻せず、", + "animatedThumbnailDanger": "元のサムネイルは復元できません", + "animatedThumbnailSizeNote": "。データが大きくなりすぎないよう、ファイルは設定サイズ以下に調整されます。", "animatedFormat": "出力形式", "animatedRange": "アニメーション範囲", "animatedStart": "開始", "animatedEnd": "終了", "framesUnit": "フレーム", "animatedQuality": "サムネイル品質", - "animatedMaxSize": "ファイルサイズ上限", - "animatedInvalidSize": "50 から 10240 KB までの整数を入力してください", + "animatedMaxSize": "サムネイルサイズ", + "animatedInvalidSize": "10 から 1024 KB までの整数を入力してください", "animatedCompressing": "アニメーションサムネイルを圧縮中 {current}/{total}…", "animatedWebpUnavailable": "この環境では WebP をエンコードできません。APNG を選択してください。", "animatedCannotFit": "アニメーションを {target} KB まで圧縮できません(最小約 {actual} KB)。上限を増やすかフレーム範囲を短くしてください。", diff --git a/release/UNIVERSAL_SpineViewer/_locales/ko_KR.json b/release/UNIVERSAL_SpineViewer/_locales/ko_KR.json index be202c0..ba801ab 100644 --- a/release/UNIVERSAL_SpineViewer/_locales/ko_KR.json +++ b/release/UNIVERSAL_SpineViewer/_locales/ko_KR.json @@ -21,15 +21,18 @@ "thumbnail": "현재 항목 썸네일로 설정", "thumbnailTitle": "현재 프레임을 이 항목의 400×400 사용자 지정 썸네일로 설정", "animatedThumbnailTitle": "애니메이션 썸네일 생성", - "animatedThumbnailNote": "현재 썸네일이 교체되며 플러그인에서 이전 이미지를 복원할 수 없습니다. 긴 애니메이션은 파일 크기를 줄이기 위해 프레임 속도를 자동으로 낮춥니다.", + "animatedThumbnailAttention": "주의:", + "animatedThumbnailNote": "생성된 썸네일은 기존 썸네일을 교체합니다. 이 작업은 취소할 수 없으며 ", + "animatedThumbnailDanger": "기존 썸네일을 복원할 수 없습니다", + "animatedThumbnailSizeNote": ". 데이터가 너무 커지지 않도록 파일은 설정한 크기 이하로 조정됩니다.", "animatedFormat": "출력 형식", "animatedRange": "애니메이션 범위", "animatedStart": "시작", "animatedEnd": "종료", "framesUnit": "프레임", "animatedQuality": "썸네일 품질", - "animatedMaxSize": "파일 크기 제한", - "animatedInvalidSize": "50~10240KB 사이의 정수를 입력하세요", + "animatedMaxSize": "썸네일 크기", + "animatedInvalidSize": "10~1024KB 사이의 정수를 입력하세요", "animatedCompressing": "애니메이션 썸네일 압축 중 {current}/{total}…", "animatedWebpUnavailable": "현재 환경에서 WebP를 인코딩할 수 없습니다. APNG를 선택하세요.", "animatedCannotFit": "애니메이션을 {target}KB로 줄일 수 없습니다(최소 약 {actual}KB). 제한을 높이거나 프레임 범위를 줄이세요.", diff --git a/release/UNIVERSAL_SpineViewer/_locales/ru_RU.json b/release/UNIVERSAL_SpineViewer/_locales/ru_RU.json index 43cfe6c..e036811 100644 --- a/release/UNIVERSAL_SpineViewer/_locales/ru_RU.json +++ b/release/UNIVERSAL_SpineViewer/_locales/ru_RU.json @@ -21,15 +21,18 @@ "thumbnail": "Сделать миниатюрой элемента", "thumbnailTitle": "Установить текущий кадр как пользовательскую миниатюру 400×400 для этого элемента", "animatedThumbnailTitle": "Создать анимированную миниатюру", - "animatedThumbnailNote": "Текущая миниатюра будет заменена, и плагин не сможет восстановить прежнее изображение. Для длинных анимаций частота кадров снижается автоматически.", + "animatedThumbnailAttention": "Внимание:", + "animatedThumbnailNote": "Созданная миниатюра заменит существующую. Это действие нельзя отменить, и ", + "animatedThumbnailDanger": "исходную миниатюру нельзя восстановить", + "animatedThumbnailSizeNote": ". Чтобы данные анимации не были слишком большими, файл будет уменьшен до размера ниже заданного.", "animatedFormat": "Формат вывода", "animatedRange": "Диапазон анимации", "animatedStart": "Начало", "animatedEnd": "Конец", "framesUnit": "кадров", "animatedQuality": "Качество миниатюры", - "animatedMaxSize": "Лимит размера файла", - "animatedInvalidSize": "Введите целое число от 50 до 10240 КБ", + "animatedMaxSize": "Размер миниатюры", + "animatedInvalidSize": "Введите целое число от 10 до 1024 КБ", "animatedCompressing": "Сжатие анимированной миниатюры {current}/{total}…", "animatedWebpUnavailable": "Эта среда не поддерживает кодирование WebP. Выберите APNG.", "animatedCannotFit": "Анимацию нельзя уменьшить до {target} КБ (минимум около {actual} КБ). Увеличьте лимит или сократите диапазон кадров.", diff --git a/release/UNIVERSAL_SpineViewer/_locales/zh_CN.json b/release/UNIVERSAL_SpineViewer/_locales/zh_CN.json index 4970cb1..04a1d44 100644 --- a/release/UNIVERSAL_SpineViewer/_locales/zh_CN.json +++ b/release/UNIVERSAL_SpineViewer/_locales/zh_CN.json @@ -20,16 +20,19 @@ "backgroundTitle": "50×50 方格背景,随画布移动和缩放,并参与混合模式", "thumbnail": "设为当前素材缩略图", "thumbnailTitle": "将当前帧设为当前素材的 400×400 自定义缩略图", - "animatedThumbnailTitle": "生成动画缩略图", - "animatedThumbnailNote": "生成后将替换所选素材的缩略图,插件无法自动恢复原图。将自动降低帧数、颜色精度和内部细节;仍超标时会把尺寸从 400×400 逐级调低。", + "animatedThumbnailTitle": "生成动态缩略图", + "animatedThumbnailAttention": "注意:", + "animatedThumbnailNote": "生成的缩略图会替换原有缩略图,该操作不可撤销且", + "animatedThumbnailDanger": "无法恢复原有缩略图", + "animatedThumbnailSizeNote": ",为避免动态缩略图数据过大,文件尺寸将调整至设定大小之下", "animatedFormat": "输出格式", "animatedRange": "动画范围", "animatedStart": "开始", "animatedEnd": "结束", "framesUnit": "帧", "animatedQuality": "缩略图质量", - "animatedMaxSize": "文件大小上限", - "animatedInvalidSize": "请输入 50 到 10240 KB 之间的整数", + "animatedMaxSize": "缩略图大小", + "animatedInvalidSize": "请输入 10 到 1024 KB 之间的整数", "animatedCompressing": "正在压缩动画缩略图 {current}/{total}…", "animatedWebpUnavailable": "当前环境不支持 WebP 编码,请选择 APNG", "animatedCannotFit": "无法在保留动画的前提下压缩到 {target} KB(最小约 {actual} KB),请提高上限或缩短帧范围", diff --git a/release/UNIVERSAL_SpineViewer/_locales/zh_TW.json b/release/UNIVERSAL_SpineViewer/_locales/zh_TW.json index 17bc692..0313dda 100644 --- a/release/UNIVERSAL_SpineViewer/_locales/zh_TW.json +++ b/release/UNIVERSAL_SpineViewer/_locales/zh_TW.json @@ -21,15 +21,18 @@ "thumbnail": "設為目前素材縮圖", "thumbnailTitle": "將目前影格設為目前素材的 400×400 自訂縮圖", "animatedThumbnailTitle": "產生動畫縮圖", - "animatedThumbnailNote": "產生後會取代目前素材縮圖,外掛無法自動復原原圖。會自動降低影格數、色彩精度和內部細節;仍超標時會將尺寸從 400×400 逐級調低。", + "animatedThumbnailAttention": "注意:", + "animatedThumbnailNote": "產生的縮圖會取代原有縮圖,該操作無法復原且", + "animatedThumbnailDanger": "無法恢復原有縮圖", + "animatedThumbnailSizeNote": ",為避免動態縮圖資料過大,檔案尺寸將調整至設定大小以下", "animatedFormat": "輸出格式", "animatedRange": "動畫範圍", "animatedStart": "開始", "animatedEnd": "結束", "framesUnit": "影格", "animatedQuality": "縮圖品質", - "animatedMaxSize": "檔案大小上限", - "animatedInvalidSize": "請輸入 50 到 10240 KB 之間的整數", + "animatedMaxSize": "縮圖大小", + "animatedInvalidSize": "請輸入 10 到 1024 KB 之間的整數", "animatedCompressing": "正在壓縮動畫縮圖 {current}/{total}…", "animatedWebpUnavailable": "目前環境不支援 WebP 編碼,請選擇 APNG", "animatedCannotFit": "無法在保留動畫的情況下壓縮到 {target} KB(最小約 {actual} KB),請提高上限或縮短影格範圍", diff --git a/release/UNIVERSAL_SpineViewer/js/spine-visible-bounds.js b/release/UNIVERSAL_SpineViewer/js/spine-visible-bounds.js new file mode 100644 index 0000000..e97270c --- /dev/null +++ b/release/UNIVERSAL_SpineViewer/js/spine-visible-bounds.js @@ -0,0 +1,26 @@ +'use strict'; + +function findAlphaBounds(rgba, width, height, threshold = 4) { + let left = width, top = height, right = 0, bottom = 0; + for (let y = 0; y < height; y++) { + for (let x = 0; x < width; x++) { + if (rgba[(y * width + x) * 4 + 3] <= threshold) continue; + left = Math.min(left, x); + top = Math.min(top, y); + right = Math.max(right, x + 1); + bottom = Math.max(bottom, y + 1); + } + } + return right > left && bottom > top ? { left, top, right, bottom } : null; +} + +function toWorldBounds(pixels, width, height, scale, centerX, centerY) { + if (!pixels || !isFinite(scale) || scale <= 0) return null; + const left = centerX + (pixels.left - width / 2) / scale; + const right = centerX + (pixels.right - width / 2) / scale; + const top = centerY - (pixels.top - height / 2) / scale; + const bottom = centerY - (pixels.bottom - height / 2) / scale; + return { x: left, y: bottom, width: right - left, height: top - bottom }; +} + +module.exports = { findAlphaBounds, toWorldBounds }; diff --git a/release/UNIVERSAL_SpineViewer/viewer/spine.css b/release/UNIVERSAL_SpineViewer/viewer/spine.css index 3a70237..bb4c8bc 100644 --- a/release/UNIVERSAL_SpineViewer/viewer/spine.css +++ b/release/UNIVERSAL_SpineViewer/viewer/spine.css @@ -113,7 +113,10 @@ .thumb-dialog-input.hidden { display: none; } .thumb-dialog-error { color: var(--error); min-height: 18px; } .animated-thumb-card { width: min(480px, 92vw); gap: 10px; padding: 16px; } - .thumb-dialog-note.warning { color: #e6b35c; } + .animated-thumb-card .thumb-dialog-title { text-align: center; } + .animated-thumb-warning { color: #fff; } + .animated-thumb-warning-title { display: block; } + .animated-thumb-danger { color: var(--error); } .animated-thumb-card .thumb-dialog-note { font-size: 13px; } .animated-thumb-form { display: grid; grid-template-columns: 96px minmax(0, 1fr); align-items: center; gap: 10px 14px; padding: 2px 0; } .animated-thumb-label { color: var(--text-dim); } @@ -181,7 +184,8 @@ #viewport { position: relative; width: 100%; min-width: 0; flex: 1; overflow: hidden; } canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; } #status { - position: absolute; bottom: calc(22px + var(--timeline-height)); left: 12px; + position: absolute; left: 50%; bottom: calc(22px + var(--timeline-height)); + transform: translateX(-50%); max-width: min(560px, calc(100% - 24px)); padding: 6px 12px; color: var(--text); font-size: 12px; font-weight: 500; line-height: 1.45; diff --git a/release/UNIVERSAL_SpineViewer/viewer/spine.html b/release/UNIVERSAL_SpineViewer/viewer/spine.html index f1d3060..055af0c 100644 --- a/release/UNIVERSAL_SpineViewer/viewer/spine.html +++ b/release/UNIVERSAL_SpineViewer/viewer/spine.html @@ -89,8 +89,8 @@