
Всем привет. Сегодня будет маленькая заметка. Сидя поздним вечером дома и листая youtube я увидел, что много кто делает пиксельные игры, рисует пиксельный арт. Это сейчас в тренде. Вот и подумал, а почему бы мне не сделать такое же для блога?
Не буду долго расписывать про то, как работает генерация графики в Java, или про то, почему мое решение не лучшее. Просто расскажу как сделать пиксельное сердце.
BufferedImage и imageIO
Все что надо знать — это то, что BufferedImage по сути отвечает за формирование изображения, а ImageIO — за запись и чтение. Поэтому сначала набросаем метод по записи картинки
fun writeImage(img: BufferedImage, file: String) {
val imagethread = Thread(Runnable {
ImageIO.write(img, File(file).extension, File(file))
})
try {
imagethread.start()
} catch (ex: Exception) {
ex.printStackTrace()
imagethread.interrupt()
}
}
Тут все просто. На вход принимаем два параметра — нашу пиксельную картинку и путь к файлу. ImageIO блокирующий метод, поэтому тут он в отдельном потоке. В случае ошибки мы выбрасываем исключение и тормозим поток. Теперь дело за самим формированием изображения.
fun drawPixel(x:Int, y:Int, red:Int, green:Int, blue: Int, image: BufferedImage) {
image.setRGB(x, y, Color(red,green,blue).rgb)
}
Метод drawPixel как следует из названия рисует пиксель по координате (x, y) с заданным цветом — red, green. blue. Для записи информации о пикселе используем метод setRGB у BufferedImage, куда в качестве цвета передаем Color() с нашими цветами.
Напомню, что цвет по каждому каналу можно указывать в диапазоне от 0 до 255. Теперь напишем метод, который будет закрашивать небольшую область, имитируя большой размер пикселя.
fun drawTile(startX: Int, startY: Int, size: Int, red: Int, green: Int, blue: Int, image: BufferedImage) {
for (posX in startX until startX+size) {
for (posY in startY until startY+size) {
drawPixel(posX,posY,red,green,blue,image)
}
}
}
Функция drawTile принимает параметры — начальную позицию, размер плитки, три цвета и изображение, куда это будет отрисовываться. В цикле мы проходимся по координатам (X, Y) и рисуем наш большой пиксель с помощью drawPixel, согласно указанному размеру плитки.
Рисуем пиксельное сердце
Настало время для главного метода. В него мы передаем двумерный массив, в котором:
- вместо цифры 1 рисуется красный цвет
- если встречается 2, то красим в темно-красный
- вместо тройки — будет фиолетовый
- а цифра 4 дает нам белый цвет
fun drawIcon(pixels: Array<List<Int>>, image: BufferedImage) {
pixels.forEachIndexed { posY, rowElement ->
rowElement.forEachIndexed { posX, colElement ->
when(colElement) {
1 -> drawTile(posX*10,posY*10,10,255,2,0, image) // red
2 -> drawTile(posX*10,posY*10,10,156,25,31, image) // dark red
3 -> drawTile(posX*10,posY*10,10,255,255,255, image) // violet
else -> drawTile(posX*10,posY*10,10,23,0,44, image) // white
}
}
}
}
Здесь я задал фиксированный размер плитки в 10 пикселей вот тут — posX*10, но можно добавить его в виде параметра в метод drawIcon.
Проходимся по каждому массиву в подмассиве, и закрашиваем все поочередно. Теперь осталось составить массив из цифр
// prints pixel heart
val map = arrayOf(
listOf(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
listOf(0,0,0,1,1,1,0,0,0,1,2,2,0,0,0),
listOf(0,0,1,3,3,1,1,0,1,1,1,2,2,0,0),
listOf(0,1,3,3,1,1,1,1,1,1,1,1,2,2,0),
listOf(0,1,3,1,1,1,1,1,1,1,1,1,2,2,0),
listOf(0,1,1,1,1,1,1,1,1,1,1,1,2,2,0),
listOf(0,1,1,1,1,1,1,1,1,1,1,1,2,2,0),
listOf(0,0,1,1,1,1,1,1,1,1,1,2,2,0,0),
listOf(0,0,0,1,1,1,1,1,1,1,2,2,0,0,0),
listOf(0,0,0,0,1,1,1,1,1,2,2,0,0,0,0),
listOf(0,0,0,0,0,1,1,1,2,2,0,0,0,0,0),
listOf(0,0,0,0,0,0,1,2,2,0,0,0,0,0,0),
listOf(0,0,0,0,0,0,0,2,0,0,0,0,0,0,0),
listOf(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
)
Затем создать наше изображение, вызвать метод отрисовки и сохранить его на компьютере или в любом другом месте.
val heartImage = BufferedImage(150,150,TYPE_INT_RGB)
drawIcon(map,heartImage)
writeImage(heartImage,"D:/heart.bmp")

Улучшения
Я специально не стал брать Graphics2D, потому что для моей задачи это через чур. Также вы можете заметить, я использовал тип TYPE_INT_RGB, но есть TYPE_INT_ARGB, тогда появится еще прозрачность. Еще можно сделать чтение массива цифр из файла, чтобы не вводить вручную в редакторе кода. Цвет закрашивания тоже можно выбрать свой, или сделать к примеру 7 штук — по цветам радуги.
Размер большого пикселя(плитки) можно пропорционально привязать к размеру создаваемого изображения. В общем, была бы фантазия, а сделать можно все что душе угодно!
Исходник можно найти по ссылке на github
Вывод
Вот таким нехитрым способом можно рисовать pixel графику и иконки. Надеюсь, статья была чем-то полезна для Вас! В следующий раз мы напишем редактор для пиксельной графики, добавим эффектов и еще много чего.
Всем пока!