diff --git a/assets-gen/app-master.png b/assets-gen/app-master.png new file mode 100644 index 0000000..850fd08 Binary files /dev/null and b/assets-gen/app-master.png differ diff --git a/assets-gen/gen-one.sh b/assets-gen/gen-one.sh new file mode 100644 index 0000000..70e4ee0 --- /dev/null +++ b/assets-gen/gen-one.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +# gen-one.sh NAME "PROMPT BODY" +# codex imagegen2로 단일 PNG 생성. 코드 파일(.py/.svg/.html/.js)을 쓰면 실패로 보고 최대 3회 재시도. +set -u +NAME="$1" +BODY="$2" +ROOT="D:/workspace/Everything2Everthing/assets-gen" +DEST="$ROOT/$NAME.png" + +for attempt in 1 2 3 4; do + WORK="$(mktemp -d)" + # 깨끗한 작업 폴더에서만 쓰게 하고, 결과는 out.png 한 장으로 강제 + PROMPT=$(cat </dev/null 2>&1 + + # 코드 파일을 썼는지 검사 + CODE=$(find "$WORK" -type f \( -name '*.py' -o -name '*.svg' -o -name '*.html' -o -name '*.js' -o -name '*.ts' -o -name '*.sh' \) 2>/dev/null | head -1) + PNG=$(find "$WORK" -type f -name '*.png' 2>/dev/null | head -1) + + if [ -n "$CODE" ]; then + echo "[$NAME] attempt $attempt: codex wrote CODE ($CODE) — reject, retry" + rm -rf "$WORK"; continue + fi + if [ -z "$PNG" ]; then + echo "[$NAME] attempt $attempt: no PNG produced — retry" + rm -rf "$WORK"; continue + fi + # 너무 작은 PNG(코드로 만든 단색/플레이스홀더)도 거부 + SZ=$(stat -c%s "$PNG" 2>/dev/null || echo 0) + if [ "$SZ" -lt 120000 ]; then + echo "[$NAME] attempt $attempt: PNG too small ($SZ bytes) — likely synthetic, retry" + rm -rf "$WORK"; continue + fi + cp "$PNG" "$DEST" + echo "[$NAME] OK ($SZ bytes) -> $DEST" + rm -rf "$WORK" + exit 0 +done +echo "[$NAME] FAILED after retries" +exit 1 diff --git a/assets-gen/glyph-ai.png b/assets-gen/glyph-ai.png new file mode 100644 index 0000000..61a2dfb Binary files /dev/null and b/assets-gen/glyph-ai.png differ diff --git a/assets-gen/glyph-archive.png b/assets-gen/glyph-archive.png new file mode 100644 index 0000000..ad4c2d8 Binary files /dev/null and b/assets-gen/glyph-archive.png differ diff --git a/assets-gen/glyph-audio.png b/assets-gen/glyph-audio.png new file mode 100644 index 0000000..2a5373e Binary files /dev/null and b/assets-gen/glyph-audio.png differ diff --git a/assets-gen/glyph-data.png b/assets-gen/glyph-data.png new file mode 100644 index 0000000..d39c3f4 Binary files /dev/null and b/assets-gen/glyph-data.png differ diff --git a/assets-gen/glyph-document.png b/assets-gen/glyph-document.png new file mode 100644 index 0000000..30ba6ad Binary files /dev/null and b/assets-gen/glyph-document.png differ diff --git a/assets-gen/glyph-image.png b/assets-gen/glyph-image.png new file mode 100644 index 0000000..a105af1 Binary files /dev/null and b/assets-gen/glyph-image.png differ diff --git a/assets-gen/glyph-vector.png b/assets-gen/glyph-vector.png new file mode 100644 index 0000000..e55e7ec Binary files /dev/null and b/assets-gen/glyph-vector.png differ diff --git a/assets-gen/glyph-video.png b/assets-gen/glyph-video.png new file mode 100644 index 0000000..a8f1d1b Binary files /dev/null and b/assets-gen/glyph-video.png differ diff --git a/assets-gen/illus-done.png b/assets-gen/illus-done.png new file mode 100644 index 0000000..78de281 Binary files /dev/null and b/assets-gen/illus-done.png differ diff --git a/assets-gen/illus-empty.png b/assets-gen/illus-empty.png new file mode 100644 index 0000000..8b23471 Binary files /dev/null and b/assets-gen/illus-empty.png differ diff --git a/assets-gen/logo-mark.png b/assets-gen/logo-mark.png new file mode 100644 index 0000000..d8209c0 Binary files /dev/null and b/assets-gen/logo-mark.png differ diff --git a/packaging/Assets/Square150x150Logo.png b/packaging/Assets/Square150x150Logo.png index bd402c6..eff0d5b 100644 Binary files a/packaging/Assets/Square150x150Logo.png and b/packaging/Assets/Square150x150Logo.png differ diff --git a/packaging/Assets/Square44x44Logo.png b/packaging/Assets/Square44x44Logo.png index 997ce99..34fa601 100644 Binary files a/packaging/Assets/Square44x44Logo.png and b/packaging/Assets/Square44x44Logo.png differ diff --git a/packaging/Assets/StoreLogo.png b/packaging/Assets/StoreLogo.png index a052a96..972eeeb 100644 Binary files a/packaging/Assets/StoreLogo.png and b/packaging/Assets/StoreLogo.png differ diff --git a/packaging/Assets/Wide310x150Logo.png b/packaging/Assets/Wide310x150Logo.png index 10bdd46..0e36be7 100644 Binary files a/packaging/Assets/Wide310x150Logo.png and b/packaging/Assets/Wide310x150Logo.png differ diff --git a/packaging/Package.appxmanifest b/packaging/Package.appxmanifest index d21e931..2718519 100644 --- a/packaging/Package.appxmanifest +++ b/packaging/Package.appxmanifest @@ -12,7 +12,7 @@ diff --git a/src/Everything2Everything.App/Assets/app-icon.png b/src/Everything2Everything.App/Assets/app-icon.png new file mode 100644 index 0000000..4c26cf8 Binary files /dev/null and b/src/Everything2Everything.App/Assets/app-icon.png differ diff --git a/src/Everything2Everything.App/Assets/glyph-ai.png b/src/Everything2Everything.App/Assets/glyph-ai.png new file mode 100644 index 0000000..bfcf0c6 Binary files /dev/null and b/src/Everything2Everything.App/Assets/glyph-ai.png differ diff --git a/src/Everything2Everything.App/Assets/glyph-archive.png b/src/Everything2Everything.App/Assets/glyph-archive.png new file mode 100644 index 0000000..bb14843 Binary files /dev/null and b/src/Everything2Everything.App/Assets/glyph-archive.png differ diff --git a/src/Everything2Everything.App/Assets/glyph-audio.png b/src/Everything2Everything.App/Assets/glyph-audio.png new file mode 100644 index 0000000..aff2f7a Binary files /dev/null and b/src/Everything2Everything.App/Assets/glyph-audio.png differ diff --git a/src/Everything2Everything.App/Assets/glyph-data.png b/src/Everything2Everything.App/Assets/glyph-data.png new file mode 100644 index 0000000..ec9a081 Binary files /dev/null and b/src/Everything2Everything.App/Assets/glyph-data.png differ diff --git a/src/Everything2Everything.App/Assets/glyph-document.png b/src/Everything2Everything.App/Assets/glyph-document.png new file mode 100644 index 0000000..fc535b8 Binary files /dev/null and b/src/Everything2Everything.App/Assets/glyph-document.png differ diff --git a/src/Everything2Everything.App/Assets/glyph-image.png b/src/Everything2Everything.App/Assets/glyph-image.png new file mode 100644 index 0000000..e06ef12 Binary files /dev/null and b/src/Everything2Everything.App/Assets/glyph-image.png differ diff --git a/src/Everything2Everything.App/Assets/glyph-vector.png b/src/Everything2Everything.App/Assets/glyph-vector.png new file mode 100644 index 0000000..8568df7 Binary files /dev/null and b/src/Everything2Everything.App/Assets/glyph-vector.png differ diff --git a/src/Everything2Everything.App/Assets/glyph-video.png b/src/Everything2Everything.App/Assets/glyph-video.png new file mode 100644 index 0000000..b58aae9 Binary files /dev/null and b/src/Everything2Everything.App/Assets/glyph-video.png differ diff --git a/src/Everything2Everything.App/Assets/illus-done.png b/src/Everything2Everything.App/Assets/illus-done.png new file mode 100644 index 0000000..7d3225a Binary files /dev/null and b/src/Everything2Everything.App/Assets/illus-done.png differ diff --git a/src/Everything2Everything.App/Assets/illus-empty.png b/src/Everything2Everything.App/Assets/illus-empty.png new file mode 100644 index 0000000..4aa08a2 Binary files /dev/null and b/src/Everything2Everything.App/Assets/illus-empty.png differ diff --git a/src/Everything2Everything.App/Assets/logo-mark.png b/src/Everything2Everything.App/Assets/logo-mark.png new file mode 100644 index 0000000..5fe0703 Binary files /dev/null and b/src/Everything2Everything.App/Assets/logo-mark.png differ diff --git a/src/Everything2Everything.App/Everything2Everything.App.csproj b/src/Everything2Everything.App/Everything2Everything.App.csproj index 8aba88f..f3b035d 100644 --- a/src/Everything2Everything.App/Everything2Everything.App.csproj +++ b/src/Everything2Everything.App/Everything2Everything.App.csproj @@ -9,6 +9,7 @@ Everything2Everything Everything2Everything.App app.manifest + app.ico 10.0.17763.0 10.0.17763.0 $(NoWarn);NU1901;NU1902;NU1903;NU1904 @@ -26,4 +27,9 @@ + + + + + diff --git a/src/Everything2Everything.App/Views/CategoryGlyphs.cs b/src/Everything2Everything.App/Views/CategoryGlyphs.cs new file mode 100644 index 0000000..2532e89 --- /dev/null +++ b/src/Everything2Everything.App/Views/CategoryGlyphs.cs @@ -0,0 +1,63 @@ +using System.Windows.Media; +using System.Windows.Media.Imaging; + +namespace Everything2Everything.App.Views; + +/// +/// 파일 확장자 → 카테고리 글리프(imagegen2 생성 PNG) 매핑. +/// 큐 행·미리보기 placeholder 등에서 형식을 한눈에 보여주기 위해 사용한다. +/// +public static class CategoryGlyphs +{ + private static readonly Dictionary ExtToCategory = new(StringComparer.OrdinalIgnoreCase) + { + // image + [".jpg"] = "image", [".jpeg"] = "image", [".jpe"] = "image", [".png"] = "image", + [".webp"] = "image", [".avif"] = "image", [".bmp"] = "image", [".tif"] = "image", + [".tiff"] = "image", [".gif"] = "image", [".heic"] = "image", [".heif"] = "image", + [".cr2"] = "image", [".nef"] = "image", [".arw"] = "image", [".dng"] = "image", [".raw"] = "image", + // vector + [".svg"] = "vector", [".eps"] = "vector", [".ai"] = "vector", + // video + [".mp4"] = "video", [".webm"] = "video", [".mkv"] = "video", [".mov"] = "video", [".avi"] = "video", + // audio + [".mp3"] = "audio", [".aac"] = "audio", [".m4a"] = "audio", [".opus"] = "audio", + [".ogg"] = "audio", [".flac"] = "audio", [".wav"] = "audio", + // document + [".pdf"] = "document", [".docx"] = "document", [".doc"] = "document", + [".hwp"] = "document", [".hwpx"] = "document", [".html"] = "document", [".htm"] = "document", + [".md"] = "document", [".txt"] = "document", [".rtf"] = "document", + // data + [".csv"] = "data", [".json"] = "data", [".xlsx"] = "data", [".xls"] = "data", + [".tsv"] = "data", [".xml"] = "data", [".yaml"] = "data", [".yml"] = "data", + // archive + [".zip"] = "archive", [".7z"] = "archive", [".rar"] = "archive", + [".tar"] = "archive", [".gz"] = "archive", + }; + + private static readonly Dictionary Cache = new(StringComparer.OrdinalIgnoreCase); + + /// 확장자(.jpg 등)에 해당하는 카테고리 글리프 이미지. 매핑이 없으면 document로 폴백. + public static ImageSource ForExtension(string? extension) + { + var ext = string.IsNullOrWhiteSpace(extension) ? "" : extension.Trim(); + if (ext.Length > 0 && ext[0] != '.') ext = "." + ext; + var category = ExtToCategory.TryGetValue(ext, out var c) ? c : "document"; + return ForCategory(category); + } + + /// 카테고리명(image/video/audio/document/data/vector/archive/ai)에 해당하는 글리프. + public static ImageSource ForCategory(string category) + { + if (Cache.TryGetValue(category, out var cached)) return cached; + var uri = new Uri($"pack://application:,,,/Assets/glyph-{category}.png", UriKind.Absolute); + var img = new BitmapImage(); + img.BeginInit(); + img.CacheOption = BitmapCacheOption.OnLoad; + img.UriSource = uri; + img.EndInit(); + img.Freeze(); + Cache[category] = img; + return img; + } +} diff --git a/src/Everything2Everything.App/Views/MainWindow.xaml b/src/Everything2Everything.App/Views/MainWindow.xaml index efa947e..7ab50c4 100644 --- a/src/Everything2Everything.App/Views/MainWindow.xaml +++ b/src/Everything2Everything.App/Views/MainWindow.xaml @@ -3,6 +3,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" Title="FormatShift Utility" + Icon="pack://application:,,,/Assets/app-icon.png" Width="1280" Height="960" MinWidth="1080" MinHeight="640" ExtendsContentIntoTitleBar="True" @@ -62,10 +63,10 @@ - - + FormatShift @@ -192,7 +193,12 @@ - + + + + @@ -401,12 +407,12 @@ StrokeDashArray="5 4" Fill="#04FFFFFF"/> - - + + @@ -459,15 +465,9 @@ - - - + - - - + @@ -707,7 +701,10 @@ - + 래스터 미리보기가 없는 형식은 경고 대신 카테고리 글리프로 안내한다. + private void ShowPreviewGlyph(string? extension, string reason) + { + PreviewEmpty.Visibility = Visibility.Collapsed; + PreviewImage.Visibility = Visibility.Collapsed; + PreviewLoading.Visibility = Visibility.Collapsed; + PreviewGlyph.Source = CategoryGlyphs.ForExtension(extension); + PreviewGlyph.Visibility = Visibility.Visible; + PreviewWarnIcon.Visibility = Visibility.Collapsed; PreviewReasonText.Text = reason; PreviewReason.Visibility = Visibility.Visible; } @@ -1120,6 +1137,9 @@ public sealed class QueueItem : INotifyPropertyChanged public required string MetaLine { get; init; } public required long SourceSizeBytes { get; init; } + /// 형식 카테고리 글리프(라벨 아이콘). + public System.Windows.Media.ImageSource GlyphSource => CategoryGlyphs.ForExtension(Path.GetExtension(SourcePath)); + public string StateText { get => _state; @@ -1225,6 +1245,9 @@ public sealed record HistoryRow( { public string RevealPath => OutputPath ?? SourcePath; + /// 형식 카테고리 글리프(라벨 아이콘). + public System.Windows.Media.ImageSource GlyphSource => CategoryGlyphs.ForExtension(Path.GetExtension(SourcePath)); + public static HistoryRow From(HistoryEntry e) { var ext = Path.GetExtension(e.SourcePath).TrimStart('.').ToLowerInvariant(); diff --git a/src/Everything2Everything.App/Views/QuickProgressWindow.xaml b/src/Everything2Everything.App/Views/QuickProgressWindow.xaml index 0d668ca..e75932d 100644 --- a/src/Everything2Everything.App/Views/QuickProgressWindow.xaml +++ b/src/Everything2Everything.App/Views/QuickProgressWindow.xaml @@ -3,7 +3,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml" Title="빠른 변환" - Width="560" Height="220" + Width="560" Height="240" ExtendsContentIntoTitleBar="True" WindowBackdropType="Mica" WindowCornerPreference="Round" @@ -36,6 +36,11 @@ Style="{StaticResource TextCaption}" TextTrimming="CharacterEllipsis"/> + 0) + { + // 전부 성공했지만 일부 건너뛰어 창이 남는 경우 — 완료 일러스트로 마무리 + DoneIllustration.Visibility = Visibility.Visible; + Height = 360; + } } private void OnOpenFolderClick(object sender, RoutedEventArgs e) diff --git a/src/Everything2Everything.App/app.ico b/src/Everything2Everything.App/app.ico new file mode 100644 index 0000000..2da3d18 Binary files /dev/null and b/src/Everything2Everything.App/app.ico differ