LINUX.ORG.RU

Рисовалка битмапов на тикле

 , ,


1

1

Я тут под свои нужды накидал простенький редактор битмапок, который позволит кабанчиком рисовать небольшие пиктограммки. Получилось довольно неплохо и я решил поделиться им с сообществом. Код простой, поэтому легко будет подстроить под свои нужны.

Перемещение фукуса стрелочками. Для рисования/стирания пикселя используется пробел. По нажатию кнопки «Dump» в консоль выплёвывается последовательность 0 и 1 в виде текста, которую дальше можете сконвертировать в тот формат, который вам нужен.

Пример использования https://0x0.st/Kf8v.png

#!/usr/bin/wish

##########################
###   settings start   ###


set bitmapWidth  32
set bitmapHeight 32


###    settings end    ###
##########################

set currentFocusX 0
set currentFocusY 0

set verticalSymmetry   0
set horizontalSymmetry 0
set diagonalSymmetry   0


ttk::style layout pixel.TCheckbutton {
	Checkbutton.indicator
	Checkbutton.focus
}


proc focusUp { } {
	
	if { $::currentFocusY > 0 } {
		incr ::currentFocusY -1
	}
	
	focus .checkboxArea.pixelr${::currentFocusY}c${::currentFocusX}
}

proc focusDown { } {
	
	if { $::currentFocusY < [expr $::bitmapHeight - 1] } {
		incr ::currentFocusY
	}
	
	focus .checkboxArea.pixelr${::currentFocusY}c${::currentFocusX}
}

proc focusLeft { } {
	
	if { $::currentFocusX > 0 } {
		incr ::currentFocusX -1
	}
	
	focus .checkboxArea.pixelr${::currentFocusY}c${::currentFocusX}
}

proc focusRight { } {
	
	if { $::currentFocusX < [expr $::bitmapWidth - 1] } {
		incr ::currentFocusX
	}
	
	focus .checkboxArea.pixelr${::currentFocusY}c${::currentFocusX}
}

proc shiftUp { } {
	
	for { set rowNo 1 } { $rowNo < $::bitmapHeight } { incr rowNo } {
		
		set rowNoTo [expr $rowNo - 1]
		
		for { set colNo 0 } { $colNo < $::bitmapWidth } { incr colNo } {
			set ::pixelr${rowNoTo}c${colNo} [ set ::pixelr${rowNo}c${colNo} ]
		}
	}
}

proc shiftLeft { } {
	
	for { set colNo 1 } { $colNo < $::bitmapWidth } { incr colNo } {
		
		set colNoTo [ expr $colNo - 1 ]
		
		for { set rowNo 0 } { $rowNo < $::bitmapHeight } { incr rowNo } {
			set ::pixelr${rowNo}c${colNoTo} [ set ::pixelr${rowNo}c${colNo} ]
		}
	}
}
proc shiftRight { } {
	
	if { $::bitmapWidth < 2 } return
	
	for { set colNo [expr $::bitmapWidth - 2] } { $colNo >= 0 } { incr colNo -1 } {
		
		set colNoTo [ expr $colNo + 1 ]
		
		for { set rowNo 0 } { $rowNo < $::bitmapHeight } { incr rowNo } {
			set ::pixelr${rowNo}c${colNoTo} [ set ::pixelr${rowNo}c${colNo} ]
		}
	}
}

proc shiftDown { } {
	
	if { $::bitmapHeight < 2 } return
	
	for { set rowNo [expr $::bitmapHeight - 2] } { $rowNo >= 0 } { incr rowNo -1 } {
		
		set rowNoTo [ expr $rowNo + 1 ]
		
		for { set colNo 0 } { $colNo < $::bitmapWidth } { incr colNo } {
			set ::pixelr${rowNoTo}c${colNo} [ set ::pixelr${rowNo}c${colNo}]
		}
	}
}



proc setAllPixelsValue { value } {
	for { set rowNo 0 } { $rowNo < $::bitmapHeight } { incr rowNo } {
		for { set colNo 0 } { $colNo < $::bitmapWidth } { incr colNo } {
			set ::pixelr${rowNo}c${colNo} $value
		}
	}
}

proc verticalSymmetryHandler { rowNo colNo } {
	set mirrorCol [ expr $::bitmapWidth - $colNo - 1 ]
	set ::pixelr${rowNo}c${mirrorCol} [ set ::pixelr${rowNo}c${colNo} ]
}

proc horizontalSymmetryHandler { rowNo colNo } {
	set mirrorRow [ expr $::bitmapHeight - $rowNo - 1 ]
	set ::pixelr${mirrorRow}c${colNo} [ set ::pixelr${rowNo}c${colNo} ]
}

proc diagonalSymmetryHandler { rowNo colNo } {
	
	set diagonalRow [ expr $::bitmapWidth - $rowNo - 1 ]
	set diagonalCol [ expr $::bitmapWidth - $colNo - 1 ]
	
	set ::pixelr${diagonalRow}c${diagonalCol} [ set ::pixelr${rowNo}c${colNo} ]
}
 
proc symmetryHandler { rowNo colNo } {
	
	if { $::verticalSymmetry } {
		verticalSymmetryHandler $rowNo $colNo
	}
	
	if { $::horizontalSymmetry } {
		horizontalSymmetryHandler $rowNo $colNo
	}
	
	if { $::diagonalSymmetry } {
		diagonalSymmetryHandler $rowNo $colNo
	}
}

proc dumpPixelmap { } {
	
	puts ""
	
	for { set rowNo 0 } { $rowNo < $::bitmapHeight } { incr rowNo } {
		for { set colNo 0 } { $colNo < $::bitmapWidth } { incr colNo } {
			puts -nonewline [set ::pixelr${rowNo}c${colNo}]
		}
	}
	
	puts ""
	puts ""
}

proc buildCheckboxArea { } {
	
	for { set rowNo 0 } { $rowNo < 32 } { incr rowNo } {
		
		for { set colNo 0 } { $colNo < 32 } { incr colNo } {
			
			ttk::checkbutton .checkboxArea.pixelr${rowNo}c${colNo} -style pixel.TCheckbutton -variable pixelr${rowNo}c${colNo} -command "symmetryHandler $rowNo $colNo"
			grid .checkboxArea.pixelr${rowNo}c${colNo} -row $rowNo -column $colNo
			
			set ::pixelr${rowNo}c${colNo}  0
			
		}
	}
}


proc buildGui { } {
	
	set buttonsPaddingY 30
	
	# window layout
	ttk::frame .checkboxArea
	ttk::frame .controlPanel
	grid .checkboxArea  -row 0 -column 0 -padx 10 -pady 10
	grid .controlPanel  -row 0 -column 1 -padx 10 -pady 10
	
	#chechbox area build
	buildCheckboxArea
	
	#control panel
	
	#sel clear
	ttk::button .controlPanel.allClear -text "All clear" -command { setAllPixelsValue 0 }
	ttk::button .controlPanel.allSet   -text "All set"   -command { setAllPixelsValue 1 }
	
	grid .controlPanel.allClear -row 0 -column 0
	grid .controlPanel.allSet   -row 10 -column 0
	
	
	#shift panel
	ttk::frame .controlPanel.shift
	grid .controlPanel.shift  -row 20 -column 0 -pady $buttonsPaddingY
	
	
	ttk::button .controlPanel.shift.up    -text "/\\" -command shiftUp 
	ttk::button .controlPanel.shift.left  -text "<"   -command shiftLeft
	ttk::button .controlPanel.shift.right -text ">"   -command shiftRight
	ttk::button .controlPanel.shift.down  -text "\\/" -command shiftDown
	
	grid .controlPanel.shift.up    -row 0 -column 1
	grid .controlPanel.shift.left  -row 1 -column 0
	grid .controlPanel.shift.right -row 1 -column 2
	grid .controlPanel.shift.down  -row 2 -column 1
	
	
	#symmetry settings
	ttk::frame .controlPanel.symmetry
	grid       .controlPanel.symmetry -row 30 -column 0 -pady $buttonsPaddingY
	
	ttk::checkbutton .controlPanel.symmetry.vertical   -text "Вертикальная симметрия"   -variable verticalSymmetry
	ttk::checkbutton .controlPanel.symmetry.horizontal -text "Горизонтальная симметрия" -variable horizontalSymmetry
	ttk::checkbutton .controlPanel.symmetry.diagonal   -text "Диагональная симметрия" -variable diagonalSymmetry
	
	grid .controlPanel.symmetry.vertical   -pady 5
	grid .controlPanel.symmetry.horizontal -pady 5
	grid .controlPanel.symmetry.diagonal   -pady 5
	
	
	#dump
	ttk::button .controlPanel.dump     -text "Dump"      -command { dumpPixelmap }
	grid .controlPanel.dump     -row 100 -column 0 -pady $buttonsPaddingY
	
}



buildGui


bind . <KeyPress-Up>    { focusUp    }
bind . <KeyPress-Left>  { focusLeft  }
bind . <KeyPress-Down>  { focusDown  }
bind . <KeyPress-Right> { focusRight }

★★★

Ты конечно молодец, но я так и не понял где оно надо. Уж очень wish экзотический в силу устаревания. Проекту 37 годиков, старше меня, а патч последний прилетал на него аж в 2019 году, что давно. Я конечно иксы уважаю, но уже ИМХО пора перекатываться на вейланд. Ну максимум годика через 3, если у кого-то что-то пока не работает как надо.

anonymous
()
Ответ на: комментарий от anonymous

но я так и не понял где оно надо

Там, где нужны маленькие иконки. Основная фишка в том, что в обычном графическом редакторе рисуешь мышью. Рука может дрогнуть и т.д., а в моём редакторе рисование идёт с клавиатуры, поэтому пиксели закрашиваются ровно те, которые нужны. Остаётся лишь чётко представить то, что хочешь нарисовать.

Ну и функции симметрии тоже очень здорово помогают. На скрине видна пиктограммка динамика. Если присмотреться повнимательнее, то он кривой, потому что я ошибся там на один или два пикселя. После этого я решил сделать функцию симметрии и удобство рисования вышло на новый уровень.

Уж очень wish экзотический в силу устаревания

Может и так, но он работает и работает хорошо. Что ещё надо?

но уже ИМХО пора перекатываться на вейланд

Похоже, не все так считают, да? ;)

u5er ★★★
() автор топика
Ответ на: комментарий от anonymous

Проекту 37 годиков, старше меня, а патч последний прилетал на него аж в 2019 году, что давно.

вы с личного рождения ни разу не обновили пакеты ? ;-)

последний крупный апдейт tk (c 8 на 9) в этом году был, минорные выходят так примерно раз в квартал..

проект старый, тут нет споров, но сильно получше многих других

MKuznetsov ★★★★★
()
Ответ на: комментарий от u5er

да, для красивенькой графики, тебе понадобится сглаживание, наиболее простое это альфа ну хотя бы на 4 бита, заодно сможешь красить пикчи в цвета и смешивать между собой и с фоном

Morin ★★★★★
()
Ответ на: комментарий от Morin

Но это уже задача графического движка, нет? Он получает на вход битмап, координаты, цвет и альфу и уже рисует с учётом всего этого. По крайней мере, у меня мысль была именно такая. Просто если в самой картинке нужно хранить информацию об альфа канале, то тут уже есть PNG, который умеет в grayscale + alpha.

u5er ★★★
() автор топика
Ответ на: комментарий от u5er

теперь оставляем только grayscale и вот у нас уже только альфаканал, забавно правда? Но движок должен уметь в такое да

png это хорошо, но когда начинаешь писать что-то даже под жирные контрошки, обнаруживается, что места под графику не вагон :) все не пудрю мозги, развлекайся

Morin ★★★★★
()
Ответ на: комментарий от Morin

теперь оставляем только grayscale и вот у нас уже только альфаканал

Не уверен. Сам grayscale отвечает за интенсивность того цвета, которым рисуешь, а альфа - за смешивание этого цвета с фоном. Или я ошибаюсь?

u5er ★★★
() автор топика
Ответ на: комментарий от u5er

:) почитай как устроена альфа. Если юзать писишные либы, то да, там все готово. но вот под капотом, там оно самое, там только маска интенсивности, что в принципе тоже битмап

Morin ★★★★★
()

за tcl/tk плюс

но так-то и в calc/excel сделать визуальную табличку 32х32, заполнить ее символами и вывести последовательность 1/0, дело часа разработки и тестирования. Зато ничего особенного устанавливать не надо, офис у всех есть (скорее всего)

futurama ★★★★★
()
Ответ на: комментарий от futurama

да ты погоди, аппетит приходит во время еды)) сейчас подтянется, а если надо сдвинуть, отразить, повернуть. а если импортнуть картинку, а если запилить свой шрифт. Не, проект может оказаться интересный, если догонит iconedit

Morin ★★★★★
()
Ответ на: комментарий от Morin

а если запилить свой шрифт

Шрифты пилились в похожей самоделке, только на гтк. Сорцы той поделки да и она сама, похоже я куда-то потерял. Но та поделка была не так удобна.

Более того, на скрине можно видеть мой текущий шрифт - буквы на нём пляшут. А это значит что? Правильно - будет переделываться позже. А для того, чтоб буквы не плясали я думаю, что в редакторе нажно сделать маску, которая отключает часть чекбоксов, делая их неактивными и оставляя активным поле, в которое символ должен помещаться целиком. Тогда все буквы получится сделать одинаковыми по высоте.

u5er ★★★
() автор топика
Ответ на: комментарий от u5er

Редактор битмапок выглядит зачётно. Если бы я нагуглил его до того, как запилить свой ляс, то потыкал бы.

Так-то редакторов битмапов существует примерно несколько сотен. Я конкретные не подскажу, но описания и проекты встречал множество раз. Люди постоянно рисуют битмапы, я бы точно начал с того, что это уже многократно решенная задача.

Chiffchaff
()
Ответ на: комментарий от Chiffchaff

я бы точно начал с того, что это уже многократно решенная задача

Я тоже с этого начал, но в поиске не смог такого, чем сразу захотелось бы воспользоваться. Плюс ещё я сразу вспомнил, что нужно будет ещё разбираться с тем, в каком формате конкретный редактор сохраняет эти самые битмапы, чтоб потом перегнать в нужный мне - в сырые байты. От одних только этих мыслей на меня накатилось нежелание во всём этом копаться и я просто запилил 100501-ый редактор битмапов. Такие дела.

u5er ★★★
() автор топика
Ответ на: комментарий от u5er

в каком формате конкретный редактор сохраняет эти самые битмапы, чтоб потом перегнать в нужный мне - в сырые байты

Всегда ведь можно конвертнуть в формат XPM любой утилитой, который и есть фактически сырые байты, готовые для использования в коде на C.

Chiffchaff
()
Ответ на: комментарий от recei

Простите, но уровень аргумента на уровне: зачем пилить гимп, если есть фотошоп? Ну да, есть.

Нет. Между GIMP и Photoshop была (и есть, наверное), огромная разница.

Редакторов же пиксельной графики написано уже не менее тысячи, на любой вкус, на любом ЯП, с любыми возможными для редактора пиксельной графики, возможностями.

Я выше привёл список из 4-х редакторов пиксельной графики, и это только вершина айсберга, на самом деле, их на порядки больше.

Chiffchaff
()

У меня тоже есть IconEditor. В тот момент когда я его писал движок 2D-графики не поддерживал прозрачные цвета (он же альфа канал). Я его писал используя массив, поэтому поворот, отражение было не сложно сделать. Функции тон/насыщенность/яркость у меня уже были готовые, поэтому я их быстро встроил.

AZJIO
()
Ответ на: комментарий от AZJIO

У меня тоже есть IconEditor (purebasic.fr/...)

чуть не прослезился..:-) первый самоличнопальный софт был на бейсике, редактор спрайтов для MSX . в принципе такой-же битмап-редактор

MKuznetsov ★★★★★
()