Комментарии 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 заворачивать.
Так я тоже проверил, и у меня не вызывает. Ну а кто-то соберёт под другую версию фреймворка, или на моно каком-нибудь запустит и поймает исключение. Сколько лет топику - не важно. Сама идея вызова 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
BitImageTool — пиктограммы для кнопок и панелек приложений, закодированные в ASCII