diff --git a/Minint.Core/Models/MinintDocument.cs b/Minint.Core/Models/MinintDocument.cs index e076b47..6ec01e0 100644 --- a/Minint.Core/Models/MinintDocument.cs +++ b/Minint.Core/Models/MinintDocument.cs @@ -8,24 +8,12 @@ public sealed class MinintDocument { public string Name { get; set; } - /// - /// Delay before showing the next frame during animation playback (ms). - /// public uint FrameDelayMs { get; set; } - /// - /// Document palette. Index 0 is always . - /// All layers reference colors by index into this list. - /// public List Palette { get; } public List Layers { get; } - /// - /// Reverse lookup cache: RgbaColor → palette index. Built lazily, invalidated - /// on structural palette changes (compact, clear). Call - /// after bulk palette modifications. - /// private Dictionary? _paletteCache; public MinintDocument(string name) diff --git a/Report/lab2/newuml/dz-a1-contrast-activity.png b/Report/lab2/newuml/dz-a1-contrast-activity.png new file mode 100644 index 0000000..5f0cb7d Binary files /dev/null and b/Report/lab2/newuml/dz-a1-contrast-activity.png differ diff --git a/Report/lab2/newuml/dz-a1-contrast-activity.puml b/Report/lab2/newuml/dz-a1-contrast-activity.puml new file mode 100644 index 0000000..4c7c45e --- /dev/null +++ b/Report/lab2/newuml/dz-a1-contrast-activity.puml @@ -0,0 +1,26 @@ +@startuml dz-a1-contrast-activity +title ДЗ.А1 — алгоритм ApplyContrast (по палитре документа) + +start +:Вход: **MinintDocument doc**, **double factor**; +:i ← 1; + +while (i < doc.Palette.Count?) is (да) + :c <- doc.Palette[i]; + :doc.Palette[i] <- новый RgbaColor\n(ContrastByte для R,G,B, c.A); + :i <- i + 1; +endwhile (нет) + +:doc.InvalidatePaletteCache(); + +floating note left + **ContrastByte(x, factor):** + v = ((x/255) - 0.5) * factor + 0.5 + return Clamp( round(v * 255), 0, 255 ) + -- + Индекс палитры 0 не меняется. +end note + +stop + +@enduml diff --git a/Report/lab2/newuml/dz-a1-grayscale-activity.png b/Report/lab2/newuml/dz-a1-grayscale-activity.png new file mode 100644 index 0000000..4b14c63 Binary files /dev/null and b/Report/lab2/newuml/dz-a1-grayscale-activity.png differ diff --git a/Report/lab2/newuml/dz-a1-grayscale-activity.puml b/Report/lab2/newuml/dz-a1-grayscale-activity.puml new file mode 100644 index 0000000..30c0e13 --- /dev/null +++ b/Report/lab2/newuml/dz-a1-grayscale-activity.puml @@ -0,0 +1,24 @@ +@startuml dz-a1-grayscale-activity +title ДЗ.А1 — алгоритм ApplyGrayscale (по палитре документа) + +start +:Вход: **MinintDocument doc**; +:i ← 1; + +while (i < doc.Palette.Count?) is (да) + :c ← doc.Palette[i]; + :Y ← 0.299×c.R + 0.587×c.G + 0.114×c.B + 0.5; + :gray ← (byte) Clamp((int)Y, 0, 255); + :doc.Palette[i] ← RgbaColor(gray, gray, gray, c.A); + :i ← i + 1; +endwhile (нет) + +:doc.InvalidatePaletteCache(); +stop + +note right + Индекс палитры **0** (прозрачный) пропускается циклом. + Коэффициенты — типичная формула **яркости** (ITU-R BT.601). +end note + +@enduml diff --git a/Report/lab2/newuml/dz-a1-image-effects-classes.png b/Report/lab2/newuml/dz-a1-image-effects-classes.png new file mode 100644 index 0000000..a9454a5 Binary files /dev/null and b/Report/lab2/newuml/dz-a1-image-effects-classes.png differ diff --git a/Report/lab2/newuml/dz-a1-image-effects-classes.puml b/Report/lab2/newuml/dz-a1-image-effects-classes.puml new file mode 100644 index 0000000..692ec59 --- /dev/null +++ b/Report/lab2/newuml/dz-a1-image-effects-classes.puml @@ -0,0 +1,40 @@ +@startuml dz-a1-image-effects-classes +title ДЗ.А1 — сервис эффектов палитры (контраст, оттенки серого) + +skinparam classAttributeIconSize 0 +skinparam shadowing false + +package "Minint.Core.Services" { + interface IImageEffectsService { + + ApplyContrast(doc : MinintDocument, factor : double) : void + + ApplyGrayscale(doc : MinintDocument) : void + } +} + +package "Minint.Core.Services.Impl" { + class ImageEffectsService { + + ApplyContrast(doc : MinintDocument, factor : double) : void + + ApplyGrayscale(doc : MinintDocument) : void + -- + {static} - ContrastByte(value : byte, factor : double) : byte + } +} + +package "Minint.Core.Models" <> { + class MinintDocument { + + Palette : List~RgbaColor~ + + InvalidatePaletteCache() : void + } +} + +IImageEffectsService <|.. ImageEffectsService : реализует +ImageEffectsService ..> MinintDocument : изменяет Palette[i],\ni = 1..Count-1 +ImageEffectsService ..> MinintDocument : InvalidatePaletteCache() + +note bottom of ImageEffectsService + Индекс **0** палитры (прозрачный) не меняется. + Контраст: **factor** 0 → серое, 1 → без изменений, >1 → выше контраст. + Grayscale: яркость **0,299·R + 0,587·G + 0,114·B** (округление к byte). +end note + +@enduml diff --git a/Report/lab2/newuml/dz-v1-editor-animation-flow.png b/Report/lab2/newuml/dz-v1-editor-animation-flow.png new file mode 100644 index 0000000..6451c5d Binary files /dev/null and b/Report/lab2/newuml/dz-v1-editor-animation-flow.png differ diff --git a/Report/lab2/newuml/dz-v1-editor-animation-flow.puml b/Report/lab2/newuml/dz-v1-editor-animation-flow.puml new file mode 100644 index 0000000..9bd4352 --- /dev/null +++ b/Report/lab2/newuml/dz-v1-editor-animation-flow.puml @@ -0,0 +1,56 @@ +@startuml dz-v1-editor-animation-flow +title ДЗ.В1 — анимация (EditorViewModel) + +skinparam shadowing false +skinparam ActivityFontSize 11 +skinparam ActivityBackgroundColor #F8F8F8 + +start + +partition PlayAnimation { + if (Container == null || Documents.Count < 2?) then (да) + stop + endif + if (IsPlaying?) then (да) + stop + endif + :IsPlaying = true; + :_animationFrameIndex = индекс ActiveDocument; +} + +partition AdvanceAnimationFrame { + if (Container == null || !IsPlaying?) then (да) + :StopAnimation(); + stop + endif + if (Documents.Count == 0?) then (да) + :StopAnimation(); + stop + endif + :index %= Count; doc = Documents[index]; + :suppress on; ActiveDocument = doc; suppress off; + :RefreshCanvasFor(doc); + :delay = max(FrameDelayMs, 10); + :новый DispatcherTimer(delay); + note right + Tick: Stop timer, index++, + снова AdvanceAnimationFrame + end note + :Start(); +} + +floating note left + Цикл: каждый Tick на UI-потоке + снова вызывает AdvanceAnimationFrame. + Пауза кадра — FrameDelayMs документа. +end note + +stop + +legend right + StopAnimation: стоп таймера, IsPlaying=false, + SyncLayersAndCanvas. Команда Stop или + выход из Advance при ошибке состояния. +end legend + +@enduml diff --git a/Report/lab2/newuml/oz-p1-container-domain-classes.png b/Report/lab2/newuml/oz-p1-container-domain-classes.png new file mode 100644 index 0000000..22101dd Binary files /dev/null and b/Report/lab2/newuml/oz-p1-container-domain-classes.png differ diff --git a/Report/lab2/newuml/oz-p1-container-domain-classes.puml b/Report/lab2/newuml/oz-p1-container-domain-classes.puml new file mode 100644 index 0000000..94a0f3d --- /dev/null +++ b/Report/lab2/newuml/oz-p1-container-domain-classes.puml @@ -0,0 +1,68 @@ +@startuml oz-p1-container-domain-classes +title ОЗ.П1 — структура графического контейнера и представление цвета пикселя\n(модуль Minint.Core.Models) + +skinparam classAttributeIconSize 0 +skinparam shadowing false + +class MinintContainer <<графический контейнер>> { + + Width : int + + Height : int + + Documents : List~MinintDocument~ {readOnly} + + PixelCount : int <> + -- + + MinintContainer(width, height) + + AddNewDocument(name : string) : MinintDocument +} + +class MinintDocument <<кадр / документ>> { + + Name : string + + FrameDelayMs : uint + + Palette : List~RgbaColor~ {readOnly} + + Layers : List~MinintLayer~ {readOnly} + + IndexByteWidth : int <> + -- + + MinintDocument(name : string) + + FindColorCached(color : RgbaColor) : int + + EnsureColorCached(color : RgbaColor) : int + + InvalidatePaletteCache() : void +} + +class MinintLayer <<растровый слой>> { + + Name : string + + IsVisible : bool + + Opacity : byte + + Pixels : int[] {readOnly} + -- + + MinintLayer(name, pixelCount) +} + +class RgbaColor <> { + + R : byte + + G : byte + + B : byte + + A : byte + -- + {static} Transparent : RgbaColor + + ToPackedRgba() : uint + + ToPackedArgb() : uint + {static} FromPackedRgba(packed : uint) : RgbaColor +} + +MinintContainer "1" *-- "0..*" MinintDocument : содержит +MinintDocument "1" *-- "0..*" MinintLayer : содержит +MinintDocument "1" *-- "1..*" RgbaColor : Palette +MinintLayer ..> RgbaColor : Pixels[i] — индекс\nв Palette документа + +note bottom of MinintLayer + Логический «пиксель» слоя в памяти — + целочисленный **индекс** в палитре документа. + Полное описание цвета — элемент **RgbaColor** + в **MinintDocument.Palette**. +end note + +note right of MinintContainer + Общие для всех документов размеры холста (**Width**, **Height**). + Число ячеек растра: **PixelCount** = Width × Height. +end note + +@enduml diff --git a/Report/lab2/newuml/render-png.sh b/Report/lab2/newuml/render-png.sh new file mode 100755 index 0000000..6ea24a1 --- /dev/null +++ b/Report/lab2/newuml/render-png.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# Rasterize PlantUML sources in this directory to PNG (ОЗ.Р1 / отчёт). +# Requires one of: plantuml in PATH, or Java + plantuml.jar (see below). +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +# PNG рядом с исходником: oz-r1-foo.puml -> oz-r1-foo.png +OUT_OPTS=(-tpng) + +run_plantuml() { + if command -v plantuml >/dev/null 2>&1; then + plantuml "${OUT_OPTS[@]}" "$@" + return 0 + fi + + local jar="${PLANTUML_JAR:-}" + if [[ -n "$jar" && -f "$jar" ]] && command -v java >/dev/null 2>&1; then + java -jar "$jar" "${OUT_OPTS[@]}" "$@" + return 0 + fi + + echo "plantuml не найден. Установите пакет (например plantuml) или задайте PLANTUML_JAR" >&2 + echo " export PLANTUML_JAR=/path/to/plantuml.jar" >&2 + echo "Скачать JAR: https://plantuml.com/download" >&2 + return 127 +} + +shopt -s nullglob +sources=(*.puml) +if ((${#sources[@]} == 0)); then + echo "В $SCRIPT_DIR нет файлов *.puml" >&2 + exit 0 +fi + +run_plantuml "${sources[@]}" +echo "Готово: PNG рядом с исходниками в $SCRIPT_DIR"