Перейти к содержимому
JaggerDer

Формат картинок для OpenComputers

Рекомендуемые сообщения

"Недавно" почитал о формате .png и под впечатлением(ради чего сделал бесполезную семибайтную подпись файла) решил придумать свой формат изображения для OpenComputers и, естественно библиотеку для работы с ним.

 

Изображение закодированное в этом формате имеет малый размер, поддерживает альфа-канал и в нем возможно закодировать utf8 символ на "пискель".

 

Картинки:

 

 

nAODBSZ.png

FQVPCOk.png

cxJVJhq.png

 

 

Библиотека для работы с .ocif

Конечно же я сделал библиотеку для работы с форматом. Точнее сказать библиотека сделала формат, но это неважно.

Сама же библиотека умеет делать три тривиальные вещи:

  • Кодировать изображение и записывать в файл: write( filename:string, image:table, full_array:bool ):nil
    filename - название файла, в который запишется закодированное изображение
    image - массив изображения; может быть представлен в двух форматах: удобном для восприятия и оптимизированным для уменьшения занимаемой оперативной памяти
    full_array - выбор формата массива: true - "удобный" массив, в ином случае оптимизированный
     
  • Читать изображение: read( filename:string, full_array:bool ):table
    filename
    - название файла, который будет прочитан и декодирован. Результат возвращается в виде оптимизированного формата массива
  • full_array - выбор формата массива: true - "удобный" массив, в ином случае оптимизированный
     
  • Рисовать прочитанное изображение: draw(image:table, frame:number, rawPosX:number, drawPosY:number, gpu:table ):nil
    image - принимает оптимизированный формат изображения
    frame - выбор фрейма, который будет отрисован.
    drawPosX, drawPosY - позиция с которой происходит отрисовка
    gpu - ваша видеокарта
    Функция неоптимизирована и нестабильна!

Так же теперь есть небольшие настройки:

  • Выбор режима работы: setMode( mode:string ):bool
    на данный момент режима только два, это: "24bit" - 24bit формат, и стандартный: "8bit" или nil - то есть 8bit.
    24bit требует больше места для хранения, но точно передает все доступные цвета; 8bit занимет меньше места на диске, но у него хромает цветопередача(240 цветных оттенков + 16 оттенков серого).
  • Выбор месторасположения файла ралитры: setPalette( palette_path:string ):nil
    выбирает местораположение файла с палитрой, т.к. вам, вероятно, будет неудобен стандартный вариант с расположением в корне и названием "palette.cia".
    В режиме 8bit необходимо загружать палитру этой функцией!

 

Это собственно и все, что она умеет делать.

 

.OCIF - Open Computers Image Format

 

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

 

Но вкраце расскажу. "Пиксель" в данном формате кодируется 4 байтами в лучшем случае и 9 байтами в худшем(т.к размер utf8 символа в байтах имеет переменную длину). Первый байт кодирует цвет символа, второй - цвет фона, третий - альфа-канал, а остальными байтами кодируется символ. В файл также записывается такая служебная информация как подпись формата и ширина с высотой изображения.

 

Расскажу немного о массивах, в которых у нас хранится раскодированное изображение.

Таких массива у нас два: обычный и оптимизированный. В первом массиве очень удобно редактировать нашу картинку, иначе он прост для восприятия, относительно; второй массив является оптимизированным, то есть его невозможно читать. Оптимизированный вид массива сделан для того, чтобы он занимал меньше места в оперативной памяти, так как изображения в памяти занимают достаточно много места.

 

Так же данный формат поддерживает альфа-канал.

 

Вот так выглядит обыный массив:

 

 

--Константы(можно скопипастить)--
local IMAGE_WIDTH  = 1
local IMAGE_HEIGHT = 2
local IMAGE_FRAMES = 3
local IMAGE        = 4

--Сырое изображение, т.е. массив(первый формат, удобен для редактирования из редактора)
local ocif_image_raw = {
    [IMAGE_WIDTH] = 8, --Ширина изображения
    [IMAGE_HEIGHT] = 4, --Высота изображения
    [IMAGE_FRAMES] = 2, --Кол-во изображений
    [IMAGE] = {
        0xffffff, 0x000000, 0, '┌',
        0xffffff, 0x114B96, 120, '─',
        0xffffff, 0x114B96, 120, '─',
        0xffffff, 0x114B96, 120, '─',
        0xffffff, 0x114B96, 120, '─',
        0xffffff, 0x114B96, 120, '─',
        0xffffff, 0x114B96, 120, '─',
        0xffffff, 0x000000, 0, '┐',

        0xffffff, 0x114B96, 120, '╞',
        0xffffff, 0x114B96, 120, '─',
        0xffffff, 0x114B96, 120, 'O',
        0xffffff, 0x114B96, 120, 'C',
        0xffffff, 0x114B96, 120, 'I',
        0xffffff, 0x114B96, 120, 'F',
        0xffffff, 0x114B96, 120, '─',
        0xffffff, 0x114B96, 120, '╡',
    
        0xffffff, 0x114B96, 120, '╞',
        0xffffff, 0x114B96, 120, '─',
        0xffffff, 0x114B96, 120, 'L',
        0xffffff, 0x114B96, 120, 'I',
        0xffffff, 0x114B96, 120, 'B',
        0xffffff, 0x114B96, 120, 'R',
        0xffffff, 0x114B96, 120, '─',
        0xffffff, 0x114B96, 120, '╡',

        0xffffff, 0x114B96, 120, '└',
        0xffffff, 0x114B96, 120, '─',
        0xffffff, 0x114B96, 120, '─',
        0xffffff, 0x114B96, 120, '─',
        0xffffff, 0x114B96, 120, '─',
        0xffffff, 0x114B96, 120, '─',
        0xffffff, 0x114B96, 120, '─',
        0xffffff, 0x114B96, 120, '┘'
    },
    [IMAGE+1] = {
        0xffffff, 0x000000, 0, '┌',
        0xffffff, 0x114B96, 0, '─',
        0xffffff, 0x114B96, 0, '─',
        0xffffff, 0x114B96, 0, '─',
        0xffffff, 0x114B96, 0, '─',
        0xffffff, 0x114B96, 0, '─',
        0xffffff, 0x114B96, 0, '─',
        0xffffff, 0x000000, 0, '┐',

        0xffffff, 0x114B96, 0, '╞',
        0xffffff, 0x114B96, 0, '─',
        0xffffff, 0x114B96, 0, 'O',
        0xffffff, 0x114B96, 0, 'C',
        0xffffff, 0x114B96, 0, 'I',
        0xffffff, 0x114B96, 0, 'F',
        0xffffff, 0x114B96, 0, '─',
        0xffffff, 0x114B96, 0, '╡',
    
        0xffffff, 0x114B96, 0, '╞',
        0xffffff, 0x114B96, 0, '─',
        0xffffff, 0x114B96, 0, 'L',
        0xffffff, 0x114B96, 0, 'I',
        0xffffff, 0x114B96, 0, 'B',
        0xffffff, 0x114B96, 0, 'R',
        0xffffff, 0x114B96, 0, '─',
        0xffffff, 0x114B96, 0, '╡',

        0xffffff, 0x114B96, 0, '└',
        0xffffff, 0x114B96, 0, '─',
        0xffffff, 0x114B96, 0, '─',
        0xffffff, 0x114B96, 0, '─',
        0xffffff, 0x114B96, 0, '─',
        0xffffff, 0x114B96, 0, '─',
        0xffffff, 0x114B96, 0, '─',
        0xffffff, 0x114B96, 0, '┘'
    }
}

 

 

 

А так оптимизированный:

 

 

local IMAGE_WIDTH  = 1
local IMAGE_HEIGHT = 2
local IMAGE        = 3

local image_raw_optimized {
[IMAGE_WIDTH] = 8,
[IMAGE_HEIGHT] = 5,
	[IMAGE] = {
		65480,"1",
		65480,"0",
		65480,"З",
		65480,"0",
		65480,"1",
		2760," ",
		2760," ",
		2760," ",

		2560," ",
		14745344,"1",
		65280,"0",
		65280,"1",
		65280,"0",
		65280,"1",
		2560," ",
		2560," ",

		2560," ",
		2560," ",
		65280,"1",
		65280,"0",
		65280,"1",
		65280,"0",
		65280,"1",
		2560," ",

		65280,"P",
		65280,"A",
		65280,"S",
		65280,"░",
		65280,"Ж",
		65280,"B",
		65280,"I",
		65280,"N",

		22783," ",
		22783," ",
		22783," ",
		22728," ",
		22728," ",
		22728," ",
		22728," ",
		22728," "
	}
}

 

 

Думаю это наглядно объяснит, почему лучше не надо редактировать во втором формате массива?

 

Установка

Установка библиотеки: wget https://raw.githubusercontent.com/Pirnogion/OpenComputers_library/master/ocif/ocif.lua lib/ocif.lua
Установка цветовой палитры: wget https://raw.githubusercontent.com/Pirnogion/OpenComputers_library/master/ocif/palette.cia lib/palette.cia
Установка примера:    wget https://raw.githubusercontent.com/Pirnogion/OpenComputers_library/master/ocif/example.lua /example

В завершение

Весь исходный код можно посмотреть на GitHub: https://github.com/Pirnogion/OpenComputers_library/tree/master/ocif

 

З.Ы. Насчет бита-терминатора - так его обозвали в википедии, ко мне никаких претензий.

З.Ы.Ы. Насчет моего английского - ОТСТАНЬТЕ! Во всем виноват Google translate.

 

Обновления

Обновление 1:

  • Добавил альфа-канал, теперь есть возможность делать изображение полупрозрачными.
  • Так же изменил "форму" массива(сырого изображения) для того, чтобы он занимал меньше оперативной памяти, к сожалению массив стал менее понятным "из кода".
  • Добавил пример, который показывает как пользоваться библиотекой.
     

Обновление 2:

  • Изменил способ кодировки, теперь файл занимает вдвое меньший размер на диске.
  • Добавил оптимизированный формат массива сырого изображения.
  • Сделал возможность передавать массив в двух форматах.
  • Небольшой фикс примера.

 

Обновление 3:

  • Изменил способ конвертации цветов при помощи формулы на таблицу цветов.
  • Теперь для работы нужен файл цветовой палитры.
  • Появились небольшие цветопотери. Неясно почему.

 

Обновление 4:

  • Исправил ситуацию с потерей цветов.
  • Теперь можно выбирать режим работы 24bit(без цветопотерь) или 8bit(с небольшой потерей цветов). В первом случае размер файла выходит больше, а во-втором, соответственно, меньше.

Обновление 5:

  • Выловил кучу багов и сделал некоторые оптимизации

Обновление 6:

  • Добавил по предложению одного человека, возможность записывать в один файл до нескольких изображений.
  • Добавил возможность чтения изображения в "удобной", неоптимизированной формате массива.
  • Убрал принудительную загрузку палитры. Теперь ее необходимо прогружать функцией setPalette.
Изменено пользователем JaggerDer

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Сделал пару обновлений библиотеки. Добавил альфа-канал и провел пару оптимизаций.

 

Кстати, насчет того, что нельзя засунуть в 1 байт целый цвет. Оказывается я ошибался и кодировал цвета в 24 битном формате, что очень избыточно для 8 битного цвета, который используется в OpenComputers. Можно цвет закодировать и 1 байтом. Проверено на практике. А совсем недавно пытался доказать паре человек обратное :)


Достижение получено

Написать и придумать РАБОЧИЙ формат картинок

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Давно юзаю данную библиотеку в своей "ОС", каждая иконка - файл со структурой ocif. Удобная штука, рекомендую :)

 

c1a2f30d010a63a75f1ac41b97575b8d.png

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

 

 

А совсем недавно пытался доказать паре человек обратное
Похоже, я на подсознательном уровне понимал, что это возможно, но не мог объяснить =)) 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Похоже, я на подсознательном уровне понимал, что это возможно, но не мог объяснить =)) 

 

Кстати, знаешь, какие костыли мы придумываем, чтобы сделать  адекватную трансляцию 0xffffff -> 0xff? Кошмар какой-то - начинали с генерации 8-битной палитры и заканчиваем какими-то совершенно безумными формулами :D

 

Вот примерчик:

 

85b8f57323cdd05b5fdfba050d7c0d5f.jpg

Изменено пользователем EliteClubSessions

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Кстати, знаешь, какие костыли мы придумываем, чтобы сделать  адекватную трансляцию 0xffffff -> 0xff? Кошмар какой-то - начинали с генерации 8-битной палитры и заканчиваем какими-то совершенно безумными формулами :D

 

 

Сделал пару обновлений библиотеки. Добавил альфа-канал и провел пару оптимизаций.

Кстати, насчет того, что нельзя засунуть в 1 байт целый цвет. Оказывается я ошибался и кодировал цвета в 24 битном формате, что очень избыточно для 8 битного цвета, который используется в OpenComputers. Можно цвет закодировать и 1 байтом. Проверено на практике. А совсем недавно пытался доказать паре человек обратное :)

 

OC, для мониторов тир3, юзает стандартную программную 8-битную палитру 6*8*5+16

 

Внутри кода sicot.lua есть простая формула генерации, и комментарии по безопасной палитре.

Изменено пользователем swg2you

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

 

 

Внутри кода sicot.lua есть простая формула генерации, и комментарии по безопасной палитре.
 

 

Красава, спасибо!

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

OC, для мониторов тир3, юзает стандартную программную 8-битную палитру 6*8*5+16

 

Внутри кода sicot.lua есть простая формула генерации, и комментарии по безопасной палитре.

Но монитор третьего уровня почему-то выводит больше чем 240 цветов и больше 16 цветов grayscale. Но за формулу все-равно спасибо. Вот таблица цветов, которую я сгенерировал по вашей формуле. Может быть я где-то накосячил.

 

Код генерации таблицы:

 

 

local f = io.open("colors", "w")
local line = 0
local x = 0

f:write( "colors = {\n" )
for r=0,5 do
  for g=0,7 do
    for b=0,4 do
      line = "	[" .. x .. "] = 0x" .. string.format("%X", r*0x330000 + g*0x2400 + b*0x3F) .. ",\n"
      f:write( line )
      x = x + 1
    end 
  end
end

for i=1, 15, 1 do
	line = "	[" .. 240+i .. "] = 0x" .. string.format("%X", gpu.getPaletteColor(i)) .. ",\n"
    f:write( line )
end

f:write( "}\n" )

f:close()

 

 

Изменено пользователем JaggerDer

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Но монитор третьего уровня почему-то выводит больше чем 240 цветов и больше 16 цветов grayscale. Но за формулу все-равно спасибо. Вот таблица цветов, которую я сгенерировал по вашей формуле. Может быть я где-то накосячил.

 

Код генерации таблицы:

 

 

local f = io.open("colors", "w")
local line = 0
local x = 0

f:write( "colors = {\n" )
for r=0,5 do
  for g=0,7 do
    for b=0,4 do
      line = "	[" .. x .. "] = 0x" .. string.format("%X", r*0x330000 + g*0x2400 + b*0x3F) .. ",\n"
      f:write( line )
      x = x + 1
    end 
  end
end

for i=1, 15, 1 do
	line = "	[" .. 240+i .. "] = 0x" .. string.format("%X", gpu.getPaletteColor(i)) .. ",\n"
    f:write( line )
end

f:write( "}\n" )

f:close()

 

 

Таблица и код вроде верные. 

 

При записи цвета 0xRRGGBB в монитор, значение 0xRRGGBB приводится к сокращенной палитре, реальное значение записанного цвета можно посмотреть вычитав знакоместо с помощью gpu.get. Т.е. если мы сделаем:

gpu.setForeground(0x123456)
gpu.set(5,5,' ')
local s, fg, bg = gpu.get(5,5)

То в fg мы получим вовсе не 0x123456, а приведенное значение. Алгоритм приведения неизвестен, но приведенные значения наиболее близки к палитре 6*8*5+16.

 

Попробуй в sicot.lua покликать по битам меняя цвет, а потом кликнув на цвет посмотреть реальное значение приведенного цвета, чтобы узнать, какие именно цвета выводятся сверх палитры.

 

В палитре Тир2 я находил аномальный 17-й цвет, возможно такие цвета есть и в Тир3.

 

ЗЫ

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

Изменено пользователем swg2you

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Порой необходимо использовать много маленьких картинок, держать их в отдельных файлах не целесообразно из-за того, что загружать через http.get по отдельности довольно долгое занятие. Будет очень удобным возможность собирать пакеты десятков картинок в одном файле, а при запуске программы загружать разом в один массив

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Порой необходимо использовать много маленьких картинок, держать их в отдельных файлах не целесообразно из-за того, что загружать через http.get по отдельности довольно долгое занятие. Будет очень удобным возможность собирать пакеты десятков картинок в одном файле, а при запуске программы загружать разом в один массив

Интересная идея, мне понравилась. Уже сделал :) Можно хранить до 255 картинок в одном файле(выделить больше 1 байта на кол-во картинок не позволила большая жаба).

Изменено пользователем JaggerDer

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Присоединяйтесь к обсуждению

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

Гость
Ответить в тему...

×   Вы вставили отформатированное содержимое.   Удалить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отобразить как ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.


×
×
  • Создать...