Delphi World - это проект, являющийся сборником статей и малодокументированных возможностей  по программированию в среде Delphi. Здесь вы найдёте работы по следующим категориям: delphi, delfi, borland, bds, дельфи, делфи, дэльфи, дэлфи, programming, example, программирование, исходные коды, code, исходники, source, sources, сорцы, сорсы, soft, programs, программы, and, how, delphiworld, базы данных, графика, игры, интернет, сети, компоненты, классы, мультимедиа, ос, железо, программа, интерфейс, рабочий стол, синтаксис, технологии, файловая система...
Вшивание информации в растровые рисунки

Оформил: DeeCo

Автор: Юрий Писарев

В данной статье демонстрируется программа, позволяющая сохранять текстовую информацию в растровые рисунки. Суть программы состоит в следующем: берется текстовый файл и набор файлов рисунков. Далее выбирается подходящий рисунок и на его основе создается второй рисунок, несколько измененный. Причем степень изменения зависит от количества "вшиваемых" данных. При небольшом количестве информации отличить рисунки практически невозможно. А получить обратно текстовую информацию можно только лишь совместив эти два рисунка, а также имея библиотеку, реализующую алгоритм "склеивания" этих рисунков.

Так выглядит программа в "рабочем" состоянии. А текст я взял из какого-то файла, валявшегося у меня под рукой.

Как работать с программой

Для того, чтобы создать "слепок" существующего рисунка, нужно:
  • Загрузить текстовый файл (секция text, кнопка Open)
  • Загрузить понравившиеся рисунки (секция Picture, кнопка Open, можно загружать несколько раз, загруженные ранее картинки не пропадут)
  • Выделить нужный рисунок в компоненте TGraphGrid
  • При желании, отмасштабировать его (кнопка Resize, масштабирует рисунок в соответствии с его пропорциями)
  • Нажать на кнопку Reflect. Через несколько секунд (это если картинка большая, а так - через несколько миллисекунд) в компоненте TGraphGrid появится сгенерированное изображение, созданное на основе выбраной картинки и текстового файла. Новая картинка будет иметь имя "Data".
  • Сохранить при необходимости нужный файл изображения, выбрав его в компоненте TDrawGrid и нажав на кнопку Save.
Для того, чтобы получить текст из двух одинаковых (на первый взгляд) картинок, нужно:
  • Загрузить картинку, на основе которой был сделан "слепок"
  • Нажать на кнопку Assembly. При этом появится диалоговое окно загрузки изображения и на этот раз Вам надо будет выбрать файл "слепка", т.е. измененную картинку.
  • Далее, через некоторое время (в зависимости от количества данных, содержащихся в картинке и размера самой картинки) в компоненте TRichEdit появится этот самый закодированный текст.

Некоторые важные моменты

Выше было сказано, что при больших размерах картинки и при небольшем объеме текстового файла отличить исходную и "слепленную" картинку практически невозможно. Это правильно, но только отчасти. Если взглянуть на изображения, в котором "зашит" большой текстовый файл, то сразу же в глаза бросаются чужеродные пиксели, распределенные по всему изображению (кстати, коэффициент разброса можно менять) а особенно хорошо эти пиксели видны на рисунке, с однородным фоном. Сравните следующие два рисунка:

Исходный рисунок  Рисунок, содержащий информацию

На правом рисунке отчетливо виден шум. Этого отчасти можно было бы избежать, используя неоднороные рисунки с резкими переходами цвета, а также рисунки большего формата. Или можно написать такой хитрый алгоритм кодирования, что второе изображение будет невозможно отличить от первого. В примере вместо увеличения размера рисунка я просто уменьшил количество информации:

Исходный рисунок Рисунок, содержащий информацию

Как работает программа

Программа использует компонент Graph, о котором я рассказывал в прошлой статье.

Примечание:
Материал Компоненты для работы с графикой раздела Сокровищница

Сейчас я несколько улучшил этот компонент. Плюс, в нем появилось две новых функции:
function ReflectData(BaseBitmap, DataBitmap: TBitmap; 
    List: TStrings; 
    Reflection: TReflectionProc; 
    ScatterType: TScatterType; 
    Factor: Integer = 1): TReflectionResult; virtual; 

function AssemblyData(BaseBitmap, DataBitmap: TBitmap; 
    Assembling: TAssemblingProc): Boolean; virtual; 

Первая функция создает изображение, содержащее информацию; вторая - получает информацию из двух изображений, как я рассказывал выше. Параметры функции ReflectData:
  • BaseBitmap - Базовое изображение, на его основе создается изображение, содержащее информацию
  • DataBitmap - Изображение, содержащее информацию
  • Reflection - Процедура, которая изменяет соответствующий байт исходного изображения и формирует DataBitmap Эта процедура отвечает за сохранение информации во второй картинке. Но о ней - чуть позже.
  • ScatterType - Тип распределения информации Может принимать два значения: stGiven и stEvenly По умолчанию в программе установлено значение stEvenly. Это означает, что вся информация будет равномерно распределена по всей картинке. Если так, то задавать значение следующего параметра Factor не нужно. Если ScatterType установить в stGiven, то распределение информации зависит от коэффициента распределения.
  • Factor - Коэффициент распределения. Если параметр ScatterType равен stGiven, то фактически Factor означает через сколько байт то начала картинки (не совсем от начала - первые восемь байт идут на длину записываемого текста и на этот коэффициент) будет вписан следующий код символа текста. В программе этот коэффициент задается в компоненте TEdit.
Теперь несколько слов о используемой функции Reflection. Эту функцию я вынес в библиотеку. Эта библиотека является специфическим ключем, паролем для соединения двух картинок. В нее могут быть заложены самые разные методы шифрования, в данный же момент использзуется самый примитивный: при шифровании код очередного символа просто прибавляется к значению из картинки BaseBitmap, при расшифровке - наооборот. Эта процедура имеет тип:
TReflectionProc = procedure(var Value: Byte; Text: string; Index: Integer); 
Параметры функции Reflection:
  • Value - Величина из BaseBitmap. Именно это значение шифруется.
  • Text - Текст в виде единой строки.
  • Index - Текущий символ в тексте, который должен быть зашифрован. В эой программе код этого символа складывается с параметром Value при зашифровке.
В процедуре AsseblyData происходит обратный процесс, выделение данных на основе двух изображений. Параметры функции AsseblyData:
  • BaseBitmap - Базовое изображение
  • DataBitmap - Изображение, содержащее информацию
  • Assembling - Процедура, формирующая текстовые данные
Процедура Assembling имеет следующий тип:
TAssemblingProc = procedure(BaseValue, DataValue: Byte); 
Ее параметры:
  • BaseValue - Текущая величина из BaseBitmap
  • DataValue - Текущая величина из DestBitmap
В этой программе каждое значение символа высчитывается путем вычитания DataValue из BaseValue.

Заключение

На последок хочу дать один совет. Не стоит сохранять полученное изображение в -jpg файле :) Хотя я один раз попробовал, текст оказался сильно поврежден, хотя такие слова как Microsoft все-таки сохранились... в этом что-то есть... :)

И еще одно, практический, такой пример:

Исходный рисунок Рисунок, содержащий информацию

Попробуйте получить информацию из этих рисунков. Должна получиться статья, (в формате HTML) которую Вы сейчас читаете.

Примечание:
В тексте статьи использовано конвертированное изображение, если Вы хотите получить реальный рисунок в формате BMP, содержащий информацию для вышеописанного конкретного примера, необходимо скачать Image7.zip (162 K)
Скачать :
Проект Delphi World © Выпуск 2002 - 2004
Автор проекта: ___Nikolay