Суббота, 19.09.2020, 12:43 | Приветствую Вас Гость
Шифрование изображений и алгоритм бегунка


Доброго всем времени суток друзья! Достаточно давно я ничего не писал на своем сайте, но вот - решил исправиться и наконец порадовать вас новой порцией полезных алгоритмов.
 

В первой части урока я поведую вам о такой замечательной и полезной вещи, как шифрование изображений. Наверное каждый из вас хоть раз хранил на картах MemoryStick нежелательные для общего пользования изображения, так вот - эта проблема теперь легко решаема.
Сразу же оговорюсь, что код программы был составлен лично мной для последующего личного применения, поэтому ежели вы будете выкладывать где-то эту программу как отдельный проект, или как дополнение к вашему проекту - обязательно укажите меня в качестве автора этого кода(алгоритма) и по возможности укажите ссылку на этот сайт, вдруг кому-то будет интересно прочитать этот урок.
Для корректной работы программы нам потребуется шрифт названный qwe.ttf и картинка img.png, лежащие в папке с нашим скриптом. Время простого шифрования в 1 пиксель в ширь или ввысь стандартного изображения размером 480x272pix формата .png ~ 1мин./ дешифрования ~30сек.
 

Во второй части - я разберу заданную вам задачку на сообразительность: придумать алгоритм бегунка(полосы прокрутки). В моем случаем алгоритм занимает две ключевые строчки - собственно то же требуется и от вас. Придумать формулу(алгоритм) для вычисления высоты бегунка в зависимости от размера информации вылезающей за пределы экрана и написать формулу(алгоритм) для вычисления шага спуска/подъема бегунка.
Предположим, что бегунок мы будем делать вертикальный. Высота экрана 272pix, высота информационного блока, состоящего из 10 полей по 50pix в высоту соответственно равна 500pix. Бегунок будет перемещаться путём нажатия кнопок вверх/вниз - однако это не суть важно. Алгоритм будет разобран в конце урока.

Часть I: Алгоритм шифрования изображения путём перестановки пикселей исходного

КОД:
System.setHigh()--"для улучшения быстродействия повышаем частоту CPU"
--"функция конвертирования поставляемого числа pos в координаты по Х и У"
function convert(pos,img,ver)--"на вход получает позицию от 0 до width()*height()/изображение/способ шифрования"
local x,y--"локальные переменные координат текущего пикселя"
if ver==0 then--"если шифрование производится по вертикали изображения"
x=math.floor(pos/img:height())--"путем не хитрых логических выкладок очевидно, что Х при шифровании по вертикали надо искать путём деления на высоту картинки"
y=pos-x*img:height()--"аналогично У находится путём вычитания из pos произведения Х и высоты картинки"
elseif ver==1 then--"если шифрование производится по горизонтали изображения"
y=math.floor(pos/img:width())--"думаю объяснять это уже не стоит, я ведь прав?)"
x=pos-y*img:width()--"будем надеяться что так.."
end return x,y
end


--"функция создающая шифр"
function gen(img_c,img,n,v)--"на вход получает картинку для шифрования/оригинальную картинку/сложность шифрования/и способ"
local size=img:width()*img:height()--"переменная хранящая общее количество пикселей в изображении, путем перемножения высоты на ширину"
local mas,pos,num,pix_c,h,k,x,y={},0--"массив хранящий 0 в незадействованных участках изображения и 1 в уже использованных/порядковый номер пикселя выбираемого из исходного изображения"
local file=io.open("img.map","w")
if v==0 then--"если шифруем по вертикали"
h=n*img:height()--"шаг равен n*img:height()"
elseif v==1 then--"если по горизонтали"
h=n*img:width()
end

k=h--"приравниваем этот шаг к временной переменной k"
file:write(v.."_")--"заносим в файл данные о типе шифрования (горизонталь-1/вертикаль-0)"
for i=0,size-1 do mas[i]=0 end--"обнуляем массив, ответственный за проверку на наличие ещё не переставленных пикселей"
while k<=size do while pos<k do--"цикл от изменяющейся границы k до size/цикл от изменяющейся pos до изменяющейся k"
x,y=convert(pos,img,v)--"получаю значения X и Y возвращенные нашей функцией convert(), рассмотренной ранее"
pix_c=img:pixel(x,y)--"копирую цвет пикселя по текущим координатам"
num=math.random(k-h,k-1)--"задаю произвольную(в интервале) будущую координату для этого пикселя в новой картинке"
while mas[num]==1 do--"если это место уже занято то подыскиваем близлежащее"
if num<k-1 then--"до тех пор, пока num<k-1"
num=num+1--"путем постоянного смещения вперёд"
else
num=k-h--"и возврата на начало текущего ряда, если места в этом ряду, от сгенерированной точки до края уже заняты"
end
end

mas[num]=1--"ставлю 'флажок - 1' на теперь использованное место"
x,y=convert(num,img,v)--"по этому месту определяю координаты X и Y"
img_c:pixel(x,y,pix_c)--"и вставляю по этим координатам скопированный пиксель"
if v==0 then--"если тип шифрования вертикаль, то"
file:write(y.."_")--"каждый раз записываю текущий Y"
elseif v==1 then--"если тип шифрования - горизонталь"
file:write(x.."_")--"каждый раз записываю текущий X"
end
pos=pos+1--"сдвигаюсь вперед на след. пиксель по 'реальной' картинке"
end
for i=k-h,k-1 do

mas[i]=nil--"освобождаю память"
end
k=k+h--"смещаю границы"
end file:close()
return img_c
end


--"функция дешифрования"
function build(img_c,img)--"на вход получает изображение для дешифрования и оригинал"
local m,p,v,file,pix_c=0,""
file=io.open("img.map","r")
local r,x,y=file:read(),0,0
for i=1,string.len(r) do

if string.sub(r,i,i)~="_" then--"в качестве разделителя между числами используется _"
p=p..string.sub(r,i,i)--"вынимаю из файла числа посимвольно, группируя их в одну целую p"
elseif i==2 then--"если нахожусь только в начале файла, то определяю тип, по которому была зашифрована картинка"
v=tonumber(p) p=""--"заношу это значение в переменную v"
else
if v==0 then--"если вертикальное шифрование"
y=tonumber(p)--"значит числа в файле - это координаты по Y"
if math.fmod(m,img:height())==0 and m>0 then--"при Y с порядковым номером, превышающем высоту изображения, смещаемся по X"
x=x+1
end

elseif v==1 then--"если горизонтальное шифрование"
x=tonumber(p)--"значит числа в файле - это координаты по X"
if math.fmod(m,img:width())==0 and m>0 then--"при X с порядковым номером, превышающем ширину изображения, смещаемся по Y"
y=y+1
end
end

pix_c=img:pixel(x,y)--"копирую пиксель по полученным из файла координатам"
x,y=convert(m,img,v)--"определяю, на какое его место по m ставить в восстанавливаемой картинке"
img_c:pixel(x,y,pix_c)--"ставлю его туда по полученным координатам X и Y"
m=m+1 p="" end end--"сдвигаюсь по m, которая отвечает за позицию постановки пикселя в восстанавливаемой картинке"
file:close() r=""
return img_c
end


--"функция сохранения изображения"
function save(img_c) img_c:save("img.png") end

function main()--"базовая функция"
local img,o=Image.load("img.png"),Timer.new() o:reset(0)--"загружаю оригинальное изображение из файла/объявляю таймер и сбрасываю его"
local q,s=math.ceil(System.getFileSize("img.png")/1024),0--"заношу в переменную q размер изображения/предварительно ставлю размер файла шифра на 0"
local img_c,n=Image.createEmpty(img:width(),img:height()),1--"объявляю шаблон для будущей зашифрованной картинки/n=1, т.е сложность разброса геренатора будет ровно в одну строчку или столбец пикселей изображения."
local font,v=Font.load("qwe.ttf"),1 font:setPixelSizes(10,10)--"задаю шрифт/тут написано v=1, т.е. тип шифрования - горизонтальное"
if io.open("img.map","r")~=nil then--"если файл шифра существует"
s=math.ceil(System.getFileSize("img.map")/1024)--"определю его размер"
end
while true do
screen:clear()
pad=Controls.read()

if pad:cross() then--"включение шифрования изображения"
if io.open("img.map","r")==nil then--"если файла шифра не существует"
o:reset(0) o:start() img_c=gen(img_c,img,n,v) o:stop() save(img_c)--"функция gen возвращает зашифрованное изображение img_c=="
s=math.ceil(System.getFileSize("img.map")/1024) img_c,img=img,img_c--"в пееменную s заношу размер файла шифра/меняю местами переменные изображений img и img_c"
q=math.ceil(System.getFileSize("img.png")/1024)--"в переменную q заношу размер файла изображения"
end
end

if pad:circle() then--"включение дешифрования изображения"
if io.open("img.map","r")~=nil then--"если файл шифра существует"
o:reset(0) o:start() img_c=build(img_c,img) o:stop() save(img_c) s=0--"функция build возвращает восстановленное изображение в переменную img_c/функция save сохраняет изображение полученное после восстановления, тем самым подменяя то, что было получено ранее функцией gen"
q=math.ceil(System.getFileSize("img.png")/1024) img_c,img=img,img_c--"в переменную q заношу размер файла изображения"
System.removeFile("img.map")--"удаление файла шифра"
end
end

if pad:start() then break end--"выход из программы"
if pad:r() then screen:blit(0,0,img_c) else screen:blit(0,0,img) end--"вывод на экран зашифрованной или оригинальной картинки"
screen:fontPrint(font,0,271,"<Time left="..math.ceil(o:time()/1000).." s> <Size map="..s.." kb> <Size img="..q.." kb>",Color.new(255,255,255))
screen:flip()
oldpad=pad
end
end


main()

 

 

Изображение до шифрования:


После вертикального шифрования:


Часть II: Алгоритм бегунка(полосы прокрутки)
В этой части урока я бы хотел отметить двух моих учеников, которым я задавал ранее эту задачку. Это Александр Грушевский и Андрей Рублёв. Самое быстрое и главное полностью правильное решение было получено у Александра, но конечно не с первого раза, и поэтому предлагаю отнестись к задачке серьёзнее.

Авторская версия алгоритма(2-ве ключевые строчки выделены):
272--высота экрана, 500--высота информационного блока
272/500=0.54--отношение высот экрана и информационного блока
0.54 от 272 это 272*0.54=146.8--высота бегунка, если учитывать, что его полная высота это 272pix при высоте информационного блока не выходящего за пределы экрана
(272-147)/10=12.5 на столько опускать бегунок при нажатии кнопки, где 10 - это кол-во информационных полей, составляющих информационный блок, каждое из которых по 50 пикселей в высоту

На этом всё - спасибо всем кто был на страничках моего сайта, кто принимал активное участие в его развитии. Этот урок станет последним в цикле уроков по LUA для PSP. Дело в том, что я покидаю LUA сцену и у меня не остаётся свободного времени заниматься этим языком, и написанием под него уроков. Если возникнут вопросы - обращайтесь на форум, я периодически буду его посещать. А так - рад был всех вас видеть!) До свидания.
VITTACH

 

 

Навигация
Форма входа

Календарь
«  Сентябрь 2020  »
ПнВтСрЧтПтСбВс
 123456
78910111213
14151617181920
21222324252627
282930