.

13. ОПЕРАЦИИ С КАРТИНКАМИ

Работа с изображениями (картинками) является важным элементом современного программирования. Для людей, не умеющих программировать, существует большое количество готовых программ, которые выполняют такую работу. Тем не менее, необходимо иметь средства, позволяющие скомбинировать операции над изображениями с другими операциями. Как указывалось выше, картинка может играть роль псевдо-меню или показывать таблицу псевдо-кнопок для реализации общения с пользователем. Можно реализовать вырезание фрагментов и другие преобразования картинок. Для всех этих и других операций картинку надо сначала показать.

Для этой цели разработана команда #window или короче #w. Это весьма сложная команда. Она позволяет показывать как готовые картинки, так и научные графики в отдельном окне, если параметр [sav] = -1 или 0. При этом картинка помещается в кнопку и стоит на экране, если параметр [c] > 0, например, [c=1;]. В этом случае для того, чтобы закрыть окно, достаточно кликнуть мышкой на изображении. Однако, если параметр [c] равен 0, то программа показывает картинку и сразу двигается дальше, не закрывая ее. Эта модификация позволяет программисту использовать окно в комбинации с другими окнами и выполнять другую работу на фоне окна. При этом окно быстро становится неактивным и активировать его можно только после выполнения всей ACL программы. Первая модификация позволяет производить над окном (картинкой) определенную работу. Первоначально положение окна не задавалось и окно всегда выставлялось в центре экрана. Затем был введен параметр [emp]. Если он равен 0, то действует старый режим, а если 1, то дополнительно параметры [xp] и [yp] указывают координаты левого верхнего угла окна относительно левого верхнего угла экрана. Для первой модификации [c=1;] строка под картинкой показывает текущее положение курсора мыши на картинке и полный размер картинки (в квадратных скобках).

Информацию о координатах различных точек картинки можно использовать в последующей работе над ней. Если пользователь нажмет левую кнопку мыши в каком-либо положении курсора, затем, не отпуская кнопку, передвинет курсор в новое положение и отпустит кнопку, то это эквивалентно клику и окно закрывается. Но при этом координаты первого и последнего положений курсора при нажатой клавише будут возвращены в параметры s(102), ..., s(105) как x1, y1, x2, y2. Эта информация может быть использована для последующего автоматического выделения отмеченной части картинки или для суммирования отмеченной части как сечения в случае математических изображений.

Если изображение было показано с ненулевым значением [c], то программа также возвращает способ, каким был сделан клик. Модификатор будет возвращен в параметр s(1). Для простого клика он равен 16, другие варианты: 17 для Shift+Click, 18 для Ctrl+Click, 19 для Shift+Ctrl+Click, 24 для Alt+Click, 25 для Alt+Shift+Click, 26 для Alt+Ctrl+Click, 27 для Alt+Ctrl+Shift+Click. Коды модификатора легко получить с помощью специальной ACL программы. Эта информация может быть использована в презентациях. Кроме того, окно можно закрыть путем нажатия любой клавиши на клавиатуре, то есть не используя мышь. При этом код нажатой клавиши будет возвращен в параметр s(2). Это также очень полезно при организации показа многих картинок сразу (слайд-шоу). Коды клавиш также легко получить с помощью специальной ACL программы. Наиболее удобные клавиши цифр и латинских букв имеют коды, совпадающие с UNI (ASCII) кодами цифр и заглавных латинских букв.

То есть [0]=48, ..., [9]=57, [A]=65, ..., [Z]=90. Другие клавиши имеют коды, совпадающие с ASCII кодами знаков нижнего регистра: [,]=44, [-]=45, [.]=46, [/]=47, [;]=59, [=]=61, [[]=91, [\]=92, []]=93. Служебные клавиши имеют следующие коды: [Bksp]=8, [Tab]=9 (не работает), [Enter]=10, [Shift]=16 (не работает), [Ctrl]=17 (не работает), [Alt]=18 (не работает), [CapsLock]=20, [Esc]=27, [Space]=32, [PgUp]=33, [PgDn]=34, [End]=35, [Home]=36. Стрелки имеют следующие коды: влево 37, вверх 38, вправо 39, вниз 40. Служебные клавиши [F1]=112, ..., [F12]=123. Наконец другие клавиши имеют специальные коды: [Ins]=155, [Del]=127, [']=222, [`]=192.

Тип изображения в окне задается параметром [op]. В этом разделе мы рассмотрим только одну операцию [op=im;] (image). Данные для изображения берутся обычно из файла, чье имя задается параметром [file]. Картинка спасается различным образом в зависимости от значения параметра [sav] (save). Если [sav] есть значение от 1 до 100, то картинка не будет показана совсем, а будет записана в оперативную память компьютера как элемент коллекции с номером, равным значению [sav]. Нужно помнить, что память компьютера, вообще говоря, не может запомнить все 100 картинок очень большого размера и может возникнуть ошибка "outOfMemory", которую возможно зафиксировать только в режиме запуска интерпретатора через командную строку или bat-файл. Текущая версия программы не проверяет размер свободной памяти при сохранении очередной картинки, так что пользователь должен быть осторожным при сохранении большого числа картинок.

Другие возможности: картинка может быть только показана, если [sav=0;], показана и спасена в файл, если [sav=-1;] и только спасена в файл, если [sav=-2;]. Картинка будет спасена в файл с именем "имя.jpg" где "имя" должно быть задано параметром [form] латинскими буквами. Отмечу еще раз, что [form] задает только первую часть имени файла, без расширения. Файл будет спасен в "рабочую" папку.

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

 #w [op=im; file=; form=; n=; c=; b=; le=; mo=; twi=; the=; wid=; hei=; xsh=; ysh=; sty=; 
      bot=; top=; nx=; ny=; sav=; sca=; ord=; dir=; em=; xp=; yp=; pa=;]

Тип данных источника для картинки зависит от значения параметра [mo]. Если [mo=0;], то изображение берется из любого графического файла с расширениями gif,   jpg,   png. Содержимое файла будет показано как есть. При этом размер окна определяется размером картинки в файле и возвращается как значения параметров s(12) (ширина) и s(13) (высота). Те же самые результаты получаются, если [mo=1;] и параметры [twi], [the], [wid], hei], [xsh] и [ysh] все отрицательны.

Если [mo=1;] и [twi] и [the] больше нуля, изображение файла будет промасштабировано к размерам [twi] и [the]. Изображение может быть как уменьшено, так и увеличено. Если только один из параметров положителен, а другой отрицателен, отрицательный параметр будет вычислен из условия сохранения аспектного отношения в исходном файле. При этом параметр [sca] задает выбор метода масштабирования из 5 возможных. Допустимые значения: sca = 1 (default) 2 (fast) 4 (smooth) 8 (replicate) 16 (area-averaging). Другие значения приводят к ошибке. Различия между методами может быть изучено эмпирически. Замечу, что масштабирование практически всеми методами делается довольно медленно, особенно для картинок больших размеров.

Если [wid], [hei] оба положительны и [xsh], [ysh] положительны или нули, команда покажет только часть промасштабированного исходного изображения с размерами [wid] и [hei] и с координатами левого нижнего угла [xsh] и [ysh], отсчитывая от левого нижнего угла исходного промасштабированного изображения. Замечу, что в случае [xsh]+[wid] > [twi] ширина изображения будет уменьшена для сохранения полного размера окна. То же самое справедливо для высоты. Наконец, можно взять часть исходного изображения если [twi] и [the] отрицательны, но другие параметры положительны. Однако в этом случае желательно знать размер исходного изображения. Они будут возвращены в параметры [twi], [the], которые одновременно являются элементами массива параметров s(12) and s(13). Для целей анимации есть и другие модификации.

В случае [op=im; mo=0 или 1;] есть дополнительная возможность показывать картинки, записанные внутри jar-файла программы в папку [resources]. Для этого перед именем файла надо поставить символ &, то есть [file=&name.jpg;] где name -- имя файла. Такая возможность позволяет использовать программу для показа многих картинок в виде слайд-шоу, но сделанную в виде одного файла. Также полезно записывать внутрь программы какие-либо служебные картинки. В основном, это применимо только при использовании программы в виде спец-окна или проигрывателя.

Если [mo=2;], то изображение будет взято из памяти как элемент с номером [n]. Если параметры [twi] и [the] оба или один положительны изображение будет промасштабировано точно или удерживая аспектное отношение методом, заданным параметром [sca].

Если [mo=3;], то изображение будет взято из памяти как элемент с номером [n]. Затем, если [wid], [hei] оба положительны и [xsh], [ysh] оба положительны или нули, команда покажет только часть изображения с размерами [wid] и [hei] и координатами левого нижнего угла [xsh] and [ysh] отсчитывая от левого нижнего угла исходного изображения.

Команда может показывать в виде изображений также числовые матрицы, записанные в коде компьютера. Эти операции реализуются при других возможных значениях параметра [mo] равных 8, 16, 24, 32, 100 и 125. При этом

[mo=8;] -- данные внутри файла с изображением есть целые числа размером 8 бит (один байт).
[mo=16;] -- данные есть целые числа размером 16 бит (два байта).
[mo=24;] -- данные есть цвета пикселей (красный, зеленый и синий) в 3-х байтах для каждой точки.
[mo=32;] -- данные есть реальные числа размером 32 бита (четыре байта).
[mo=100;] -- данные вычисляются (см. далее).
[mo=125;] -- данные записаны в файл по 8 пикселей в один байт (черно-белое изображение).

В этих случаях изображения определяются одной и той же системой параметров для всех типов. Параметр [le] показывает размер заголовка файла в байтах. Обычно заголовок - это некоторый текст, который предшествует данным в файле. Однако если [mo=32;] возможен специальный случай [file=here;] который означает, что данные будут взяты из вещественного массива r(), начиная с первого элемента с индексом [le] вместо того, чтобы читаться из файла. Этот случай полезен, когда данные непосредственно вычислены или приготовлены из нескольких источников.

Если [mo=16;], то параметр [ord] определяет порядок байтов при записи целого числа. Так если [ord=0;], то LowByteSecond (младший байт второй). В противном случае если, например, [ord=1;], то LowByteFirst (младший байт первый). Реально в файлах могут быть реализованы оба случая.

Параметры [twi], the] показывают полный размер изображения в пикселах горизонтально и вертикально. Параметр [dir] указывает на направление записи. Многие графические программы записывают файлы сверху вниз. В этом случае параметр [dir] должен быть равен 1. При всех других значениях [dir], например 0, предполагается, что картинка записана снизу вверх, то есть в нормальном направлении оси y на графике.

Параметры [wid], hei] определяют размеры части изображения, которая будет реально показана. Они могут быть равны или меньше чем [twi], [the]. Параметры [xsh], [ysh] показывают сдвиг левого угла для части изображения от левого угла для всей картинки. При этом для [dir=1;] углы верхние, а в остальных случаях [dir=0;] углы нижние.

Параметры [sty], [bot=1;], [top=99999;] задают стиль показа данных для серых картинок с [mo] = 16, 32 и 100. Как это работает? Численные данные имеют минимальное значение (Fmin) и максимальное значение (Fmax). Эти значения для [mo=100;] всегда задаются в элементах вещественного массива r(j) и r(j+1), где индекс j определяется параметром [b=j;]. Для [mo=16;] или [mo=32;], они задаются, если abs([sty]) > 10, и определяются автоматически в противном случае. В случае [mo=16;] или [mo=32;] при автоматическом определении эти значения возвращаются в те же элементы реального массива. Значение каждой точки данных показывается серым пикселом в пределах от 0 до 255 (8 бит). Этот диапазон получается масштабированием из области значений данных с началом и концом

Fmi = Fmin + Dff*[bot]/100000,   Fma = Fmin + Dff*[top]/100000,   Dff = Fmax - Fmin.

Тип масштабирования задается остатком от деления [sty] на 10. Пусть это будет rsty.
Масштабирование линейное если rsty=1 и делается по формуле   gray = 255*(f - Fmi)/(Fma - Fmi)
Оно логарифмическое если rsty=2 и делается по формуле   gray = 255*log(f/Fmi)/log(Fma/Fmi)
Если rsty=3, то оно вычисляется по квадратному корню, а именно   gray = 255*sqr((f - Fmi)/(Fma - Fmi))
При этом отрицательные значения заменяются нулями.
Обычно минимум черный, максимум белый. Однако если параметр [sty] отрицательный, то контраст противоположный. Целые параметры [bot] и [top] задают часть области внутри интервала (0,1) в единицах 0.00001. Поэтому они должны иметь значения от 1 до 99999. Наконец, каждый пиксель данных может быть показан прямоугольником имеющим [nx] и [ny] пикселей экрана горизонтально и вертикально. Все указанные параметры являются элементами служебного массива s() в следующем порядке: c (8) b (9) le (10) mo (11) tw (12) th (13) wi (14) hei (15) xs (16) ys (17) sty (18) bot (19) top (20) nxf (21) nyf (22) sav (23). Поэтому удобно определить значения всех параметров командой #d 16 s(8) 1 2 3 . . . Вот пример. Для показа части данных файла большого 16-битного серого изображения в формате *.edf , который является стандартным для некоторых фоточувствительных детекторов, можно использовать следующий код

 #d 16 s(8) 1 1 3072 16 2048 2048 128 128 1408 968 -2 1 999 4 4 0 
 #w [op=im; file=any.edf;]

Еще раз отмечу, что в случае [mo=32;] и [file=here;] данные находятся в массиве r() с первого элемента, задаваемого параметром [le]. Этот параметр определял заголовок файла. Но если файл не используется, то он же определяет первый элемент массива r().

Специальный случай [mo=100;] используется для автоматического приготовления шкалы почернения. В этом случае данные вычисляются вместо того, чтобы браться из массива или файла, но для соблюдения грамматики и во избежание сообщения об ошибке в этом случае все равно надо писать [file=here;]. Данные есть массив из n элементов где n = [wid]*[hei]. Этот массив описывает линейную кривую от Fmin до Fmax где Fmin = r(j) и Fmax = r(j+1) при задании [b=j;]. Поэтому этот массив позволяет получить изображение шкалы почернения. Изображение может быть вертикальным, если [wid=1;] или горизонтальным, если [hei=1;]. Один из размеров обязательно должен быть равен 1 иначе фиксируется ошибка. Поперечный размер шкалы нужно задавать размером пиксела.

Случай [mo=125;] позволяет показать черно-белое изображение, в котором каждый пикель описывается одним битом. Файл содержит 8 пикселей в каждом байте. Такие картинки обычно спасает сканер при сканировании книг и статей. Формат файлов с такой записью обычно TIF, но могут быть и другие. При показе такого файла используются все описанные выше параметры, то есть [le] для шапки файла, [twi], [the], [wid], [hei], [xsh], [ysh], [dir], [nx], [ny]. Но обычно такие файлы как раз имеют очень большое число пикселей и картинка в исходном виде на экране не умещается. Поэтому ее необходимо не увеличивать, а уменьшать. Это задается параметром [sca] который определяет масштабный множитель в процентах. Например, если [sca=50;], то размер показанной картинки в пикселах будет в два раза меньше, чем указано в [wid] и [hei]. Как и для других числовых файлов, исходные размеры шапки и картинки необходимо знать заранее.

Есть еще одна возможность. Если [mo=-1;] то программа показывает картинки по адресу в интернете. При этом естественно, компьютер должен быть в сети. Интернет адрес задается не параметром [file], а аргументом. Это связано с тем, что длина параметра ограничена 42 символами, а интернет-адреса могут быть очень длинными. Эта возможность позволяет показывать фото-шоу по картинкам в интернете или просто скачивать картинки на свой компьютер по списку интернет-адресов. Вообще-то конечная длина параметра file иногда создавало проблемы. Сейчас это ограничение снято. Нужно указать рабочую папку как null, и записать [file=arg;]. При этом адрес файла надо задавать первым аргументом команды, и отсутствие аргумента фиксируется как ошибка. Такое правило действует уже во всех режимах работы команды.

При показе картинок нужно задавать параметр pa (pallete), номер которого 44. Он регулирует карту цветов. Первоначально расчетные карты (числовые матрицы) рисовались градациями серого, то есть от черного до белого. Но сейчас широко распространена мода рисовать цветные карты. Поэтому сейчас если [pa=1;], то рисуется цветная карта, у которой минимум синий, среднее значение красное и максимум белый. Между ними цвета непрерывно переходят один в другой. Если [pa=2;], то используется другая палитра с переходами от черного к синему, затем к зеленому, красному и в конце к белому. Если [pa=3;], то палитру цветов может задавать сам пользователь. Программа ее берет из файла colmap.txt в главной папке интерпретатора. Исходно этот файл существует с еще более сложной палитрой, содержащей много цветов. Этот файл написал я, но любой пользователь может его переписать на другую палитру.

Более того, палитра используется в момент рисования, а это означает, что ACL программа может менять палитру динамически в процессе своего выполнения. Для этого ей необходимо переписать указанный файл. В нем записано 768 целых чисел текстом, по 256 на значения красного, зеленого и синего. Очевидно, что значения 1 и 2 являются частными случаями 3, но они оставлены для совместимости с уже написанными программами. Если [pa=0;] или больше 3, то используется старый режим черно-белой карты.