Как стать автором
Обновить

Комментарии 17

let canvases = document.getElementsByClassName("textimage");

Лучше тогда всё это завернуть в custom element. Будет как-то так:

<text-image data="0@@00080060ncWolI6HV0V1PI0H6@V1VigOnm706001000" color="0xFF4040FF"></text-image>

Если же оставлять канвасы как есть, то лучше не делать произвольные атрибуты, а передавать специально для того задуманными data-атрибутами (data-image, data-color).

Да, возможно, вы правы, спасибо за замечание. Этот код просто пример реализации, для наглядности метода, наверняка там ещё много можно оптимизировать.

Прикольно, я для маленьких игр на JS похожее делал. Вот просматривалка с примерами: https://codepen.io/mvasilkov/pen/xxJvEWN

Кодировка в моем случае была просто засунуть всё в BigInt попиксельно, чтобы минимизировать декодер.

Интересный вариант, как я понял, там разрядность цвета для пикселей задаётся параметром.

Думал над четырехцветным вариантом своего метода (по 2 бита на пиксель = 3 цвета плюс фон), но там уже рисовать картинки в редакторе будет более трудоёмко, решил, что самое удобное и простое - один цвет, без палитр.

Да-да, я тоже сначала так делал, а изображения вообще прямо в текстовом редакторе посимвольно вбивал.

Собственный пиксельный редактор поленился писать, поэтому сейчас рабочий вариант это рисовать картинки в Aseprite, а затем кошмарный питоноскрипт их превращает в целевую кодировку.

Напомнило svg. Я последнее время храню иконки как svg (с обрезанным описанием, 1 цвет, без стилей) строку внутри компонента. Очень удобно по сравнению с классическими ассетами

Это конечно хорошо. Но не вызывать Dispose для Pen, Brush в своем контроле - это нонсенс. Почитайте как управлять временем жизни unmanaged ресурсов в managed среде c#, и что будет если их не освобождать...

П.С. И кодестайл для c# нетепичный...

Спасибо за замечание. В данном случае предполагается, что существование инстансов этого контрола завершается с закрытием приложения (кнопки на формах обычно создаются вместе с формами и существуют до конца работы программы). В этом случае система и так освободит unmanaged ресурсы процесса.

Если же, в каких-то целях, предполагается динамически создавать и уничтожать объекты данного типа в больших количествах на протяжении работы программы, то да, лучше добавить в код контрола деструктор с вызовыми Dispose() для всех объектов GDI+. Но тут тоже возникает проблема - если во время работы свойству или полю с типом Brush будет назначен не новый SolidBrush, а например системный объект типа Brushes.Red, то надо будет как-то определять этот момент, чтобы не вызывать Dispose() для системных кистей. В общем, тема спорная и не такая простая.

Как вы закрываете ресурсы объектов типа Pen, Brush в winforms? Поделитесь своим опытом.

В данном случае предполагается, что существование инстансов этого контрола завершается с закрытием приложения (кнопки на формах обычно создаются вместе с формами и существуют до конца работы программы).

Это не правильный подход. Т.к. код вашего контрола могут использовать в mid приложении со многими окнами. И соответственно ваш контрол является memory leaks.
П.С. Любой кастомный контрол обязан писаться как независимый объект, который будет использоваться в любой экосистеме без нарушения её работы.

Как вы закрываете ресурсы объектов типа Pen, Brush в winforms?

Просто вызываю Dispose. Для системных кистей проблем нет.
Если кастомных кистей очень много и они переиспользуются, то надо писать класс кэширования который в себе хранит все созданные кастомные кисти.
Для полных unmanaged ресурсов надо смотреть в сторону SafeHandle.

Я сталкивался с проблемой нехватки системных handle, когда писал кастомное извлечение картинок по требуемому размеру из ico файлов, как раз из-за того что не вызывал Dispose для unmanaged ресурсов.
Вот статья по кистям: https://www.codeproject.com/Articles/37916/Diposer-for-GDI-resources-Pen-Brush

Хорошо, я переработал код примера контрола для winforms. Во избежание проблем убрал возможность задавать кисти, теперь используются кисти типа SolidBrush, задаются только цвета. Кисти и перья создаются только на время отрисовки с последующим вызовом Dispose().

Просто вызываю Dispose. Для системных кистей проблем нет.

Вот тут пишут, что вызывать Dispose для системных кистей не следует, это может привести к исключениям. В крайнем случае, если нет гарантии, что кисти не системные, то каждый вызов Dispose придётся в отдельный try-catch заворачивать.

Топику 14 лет. Проверил, Dispose системных кистей не вызывает исключение.

П.С. С текущим переходом всего на linux, советую присмотреться к Avalonia.

Так я тоже проверил, и у меня не вызывает. Ну а кто-то соберёт под другую версию фреймворка, или на моно каком-нибудь запустит и поймает исключение. Сколько лет топику - не важно. Сама идея вызова Dispose для системных ресурсов мне не кажется хорошей практикой, так что я просто убрал в обсуждаемом коде саму возможность использования системных кистей.

Да, так и есть! На mono в линуксе вылетает исключение. Попробовал Dispose для кистей (которые по умолчанию в свойствах системные) в деструкторе одного контрола для BitImageTool и при закрытии приложения получил в консоли:

Unhandled Exception:
System.ArgumentException: This Pen object can't be modified.
at System.Drawing.Pen.Dispose (System.Boolean disposing) [0x0001b] in <...>:0
at System.Drawing.Pen.Dispose () [0x00000] in <...>:0
at (wrapper remoting-invoke-with-check) System.Drawing.Pen.Dispose()
at BitImageTool.BitEditor.Finalize () [0x00030] in <...>:0

Так что верно всё пишут, Dispose для системных ресурсов GDI+ вызывать нельзя. По крайней мере без заворачивания каждого в try-catch.

Если есть возможность, то надо посмотреть исходники mono на то, как происходит проверка, что кисть системная . И уже на уровне кода реализовать такую же без try/catch.

Как я понял, отличить, системная она или созданная, можно только окольными путями, типа каких-то специфических полей через рефлексию. Поэтому, моё мнение - либо закрыть возможность создавать кисти/перья в свойствах, либо сделать метод расширения типа TryDispose

public static class Utils
{
    public static void TryDispose(this IDisposable obj)
    {
        try
        {
            obj?.Dispose();
        }
        catch { }
    }
}

чтобы потом вызывать как

public Pen pen1 { get; set; } = new Pen(color); // user defined pen
public Pen pen2 { get; set; } = Pens.White; // system pen
...
pen1?.TryDispose();
pen2?.TryDispose();

хотя, всё равно, пытаться вызывать Dispose для системных объектов, даже обёрнутых таким способом - не понятно, чем это обернётся. Мне больше нравится вариант - создавать их только на время отрисовки и не хранить в свойствах

Вышла версия BitImageTool v0.2, исправлены некоторые проблемы отображения интерфейса под Linux

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории