- •Содержание
- •Введение
- •Постановка задачи
- •Теоретическое исследование
- •Представление изображений в эвм. Форматы изображений
- •Общие положения о защите авторского права и водяных знаках
- •Методы внедрения водяных знаков в изображения
- •Метод микширования
- •Метод нанесения текста
- •Метод lsb
- •Метод Patchwork
- •Обзор существующих программ-аналогов
- •Tsr Watermark Image 1.9.6.4
- •ImageSpyer 1.1
- •Разработка схемы алгоритма и её описание
- •Общая схема работы программы
- •Описание работы класса wmParameters
- •Описание работы класса TextParameters
- •Описание работы класса lsbInjector
- •Описание работы класса PatchworkInjector
- •Разработка программы
- •Тестирование и отладка
- •Руководство пользователя
- •Описание менюFile
- •Описание интерфейса метода микширования
- •Описание интерфейса метода нанесения текста
- •Описание интерфейса методовLsBиPatchwork
- •Заключение
- •Список использованных источников
- •Приложение а. Диаграмма классов приложения watermark injector
- •Приложение б. Исходный текст классаmainform
- •Приложение в. Исходный текст класса wmparameters
- •Приложение г. Исходный текст класса textparameters
- •Приложение д. Исходный текст классаlsbinjector
- •Приложение д. Исходный текст классаpatchworkinjector
Заключение
В результате работы было написано программное средство встраивания водяных знаков в изображения. Данное программное средство отвечает поставленным требованиям: оно обеспечивает работу с изображениями различных форматов, внедрение и проверку цифровых водяных знаков, встраиваемых четырьмя различными методами. Программное средство имеет удобный и эффективный графический пользовательский интерфейс.
Программное средство для внедрения водяных знаков может быть применено для защиты авторского права на изображения, выкладываемые в свободный доступ в интернет, для констатации факта изменения или несанкционированного использования данных медиафайлов.
В процессе работы были изучены графические форматы, алгоритмы внедрения водяных знаков и области их применения, а также были углублены знания в области работы с платформой .NET и программирования на высокоуровневом языке программирования C#.
Список использованных источников
[1] Гросс, К. Самоучитель C# 2008 / К. Гросс – БХВ-Петербург., 2009. – 576с.
[2] Троелсен, Э. Язык программирования C# 2008 и платформа .NET 3.5. / Э. Троелсен – Издательский дом «Вильямс», Москва, 2010. – 1343 с.
[3] Грибунин, В. Цифровая стеганография / В. Грибунин, И. Оков, И. Туринцев – Солон-Пресс, Москва, 2002. – 261 с.
[4] MSDN Library for Visual Studio 2008 [Электронный ресурс]. – Электронные данные. – Режим доступа : http://msdn.microsoft.com.
[5] Форматы графических файлов [Электронный ресурс]. – Электронные данные. – Режим доступа : http://ru.wikipedia.org.
[6] Разработка C# приложений [Электронный ресурс]. – Электронные данные. – Режим доступа : http://www.rsdn.ru.
[7] Стеганография в .NET [Электронный ресурс]. – Электронные данные. – Режим доступа : http://www.devx.com.
Приложение а. Диаграмма классов приложения watermark injector
Приложение б. Исходный текст классаmainform
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Windows.Media.Imaging;
using System.Drawing.Imaging;
using System.Xaml;
namespace WatermarkInjector
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
OpenFileDialog openSrcDlg;
private Bitmap LoadedBmp, CurBmp, WMBmp;
WMParameters wmpar;
TextParameters txtpar;
private void openContainerToolStripMenuItem_Click(object sender, EventArgs e) //открытие контейнера - файла с исходным изображением
{
openSrcDlg = new OpenFileDialog();
openSrcDlg.RestoreDirectory = true;
openSrcDlg.FilterIndex = 1;
openSrcDlg.Filter = "Images (*.jpg,*.png,*.gif,*.bmp)|*.jpg;*.png;*.gif;*.bmp" ;
if (openSrcDlg.ShowDialog() == DialogResult.OK)
{
Image img = Image.FromFile(openSrcDlg.FileName);
LoadedBmp = new Bitmap(img);
CurBmp = new Bitmap(img);
string pathname = openSrcDlg.FileName;
pictureBox1.Load(pathname);
operationsToolStripMenuItem.Enabled = true;
}
}
public Bitmap RotateImage(Bitmap currentBitmap,float angle) //метод вращения изображения
{
//используется математическое преобразование: находится соотношение точек исходного и повёрнутого растра с использованием тригонометрических функций
const double pi2 = Math.PI / 2.0;
double oldWidth = (double)currentBitmap.Width;
double oldHeight = (double)currentBitmap.Height;
double theta = ((double)angle) * Math.PI / 180.0;
double locked_theta = theta;
while (locked_theta < 0.0)
locked_theta += 2 * Math.PI;
double newWidth, newHeight;
int nWidth, nHeight;
double adjacentTop, oppositeTop;
double adjacentBottom, oppositeBottom;
if ((locked_theta >= 0.0 && locked_theta < pi2) ||
(locked_theta >= Math.PI && locked_theta < (Math.PI + pi2)))
{
adjacentTop = Math.Abs(Math.Cos(locked_theta)) * oldWidth;
oppositeTop = Math.Abs(Math.Sin(locked_theta)) * oldWidth;
adjacentBottom = Math.Abs(Math.Cos(locked_theta)) * oldHeight;
oppositeBottom = Math.Abs(Math.Sin(locked_theta)) * oldHeight;
}
else
{
adjacentTop = Math.Abs(Math.Sin(locked_theta)) * oldHeight;
oppositeTop = Math.Abs(Math.Cos(locked_theta)) * oldHeight;
adjacentBottom = Math.Abs(Math.Sin(locked_theta)) * oldWidth;
oppositeBottom = Math.Abs(Math.Cos(locked_theta)) * oldWidth;
}
newWidth = adjacentTop + oppositeBottom;
newHeight = adjacentBottom + oppositeTop;
nWidth = (int)Math.Ceiling(newWidth);
nHeight = (int)Math.Ceiling(newHeight);
Bitmap rotatedBmp = new Bitmap(nWidth, nHeight);
using (Graphics g = Graphics.FromImage(rotatedBmp))
{
Point[] points;
if (locked_theta >= 0.0 && locked_theta < pi2)
{
points = new Point[] {
new Point( (int) oppositeBottom, 0 ),
new Point( nWidth, (int) oppositeTop ),
new Point( 0, (int) adjacentBottom )
};
}
else if (locked_theta >= pi2 && locked_theta < Math.PI)
{
points = new Point[] {
new Point( nWidth, (int) oppositeTop ),
new Point( (int) adjacentTop, nHeight ),
new Point( (int) oppositeBottom, 0 )
};
}
else if (locked_theta >= Math.PI && locked_theta < (Math.PI + pi2))
{
points = new Point[] {
new Point( (int) adjacentTop, nHeight ),
new Point( 0, (int) adjacentBottom ),
new Point( nWidth, (int) oppositeTop )
};
}
else
{
points = new Point[] {
new Point( 0, (int) adjacentBottom ),
new Point( (int) oppositeBottom, 0 ),
new Point( (int) adjacentTop, nHeight )
};
}
g.DrawImage(currentBitmap, points);
}
return (Bitmap)rotatedBmp.Clone();
}
private void addTextToolStripMenuItem_Click(object sender, EventArgs e) //реализация метода нанесения текста на изображение
{
int i,j, RealW, RealH;
int BegHPoint, BegVPoint, EndHPoint, EndVPoint;
float HR, VR;
Color c1, c2;
Application.DoEvents();
txtpar = new TextParameters();
if (txtpar.ShowDialog() == DialogResult.OK)
{
Application.DoEvents();
statusStrip1.Text = "Preparing the image...";
Bitmap textBmp = new Bitmap(10000,2000);//в textbmp - водяной знак на прозрачном фоне для инъекции
Graphics g = Graphics.FromImage(textBmp);
g.FillRectangle(new SolidBrush(Color.Transparent), 0, 0, 1024, 768);
SolidBrush sb = new SolidBrush(txtpar.textCol);
Rectangle r = new Rectangle(0, 0, 10000,10000);
SizeF sf = g.MeasureString(txtpar.txtInj, txtpar.font);
RealW = (int)sf.Width;
RealH = (int)sf.Height;
g.DrawString(txtpar.txtInj, txtpar.font, sb, r);
Bitmap newTextBmp = new Bitmap(RealW, RealH);
for (i = 0; i <= RealW - 1; i++)
for (j = 0; j <= RealH - 1; j++)
newTextBmp.SetPixel(i, j, textBmp.GetPixel(i, j));
textBmp = RotateImage(newTextBmp, (float)txtpar.RA);
VR = (float)(textBmp.Height) / (float)(CurBmp.Height * txtpar.VWS);
HR = (float)(textBmp.Width) / (float)(CurBmp.Width *txtpar.HWS);
BegHPoint = 0;
EndHPoint = 0;
switch (txtpar.HA)
{
case WMParameters.HrAlignment.Left:
BegHPoint = 0;
EndHPoint = (int)(CurBmp.Width * txtpar.HWS - 1);
break;
case WMParameters.HrAlignment.Middle:
BegHPoint = (int)((float)CurBmp.Width / 2 * (1 - txtpar.HWS));
EndHPoint = CurBmp.Width - BegHPoint;
break;
case WMParameters.HrAlignment.Right:
BegHPoint = (int)(CurBmp.Width * (1 - txtpar.HWS) - 1);
EndHPoint = CurBmp.Width;
break;
}
BegVPoint = 0;
EndVPoint = 0;
switch (txtpar.VA)
{
case WMParameters.VrAlignment.Upper:
BegVPoint = 0;
EndVPoint = (int)(CurBmp.Height * txtpar.VWS - 1);
break;
case WMParameters.VrAlignment.Center:
BegVPoint = (int)((float)CurBmp.Height / 2 * (1 - txtpar.VWS));
EndVPoint = CurBmp.Height - BegVPoint;
break;
case WMParameters.VrAlignment.Lower:
BegVPoint = (int)(CurBmp.Height * (1 - txtpar.VWS) - 1);
EndVPoint = CurBmp.Height;
break;
}
for (i = BegHPoint; i <= EndHPoint - 1; i++)
for (j = BegVPoint; j <= EndVPoint - 1; j++)
{
c1 = CurBmp.GetPixel(i, j);
if (((i - BegHPoint) * HR < textBmp.Width) && ((j - BegVPoint) * VR < textBmp.Height))
c2 = textBmp.GetPixel((int)((i - BegHPoint) * HR), (int)((j - BegVPoint) * VR));
else
c2 = CurBmp.GetPixel(i, j);
if (c2.A != 255)
c2 = ((txtpar.isBorder) && (c2.A != 0)) ? txtpar.bordCol : CurBmp.GetPixel(i, j);
CurBmp.SetPixel(i, j, Color.FromArgb((int)(c1.A * txtpar.TR + c2.A * (1 - txtpar.TR)), (int)(c1.R * txtpar.TR + c2.R * (1 - txtpar.TR)), (int)(c1.G * txtpar.TR + c2.G * (1 - txtpar.TR)), (int)(c1.B * txtpar.TR + c2.B * (1 - txtpar.TR))));
progressBar1.Value = Convert.ToInt32((float)((i - BegHPoint) * CurBmp.Height * txtpar.VWS + j - BegVPoint) / (float)(CurBmp.Width * CurBmp.Height * txtpar.HWS * txtpar.VWS) * 100)%100;
statusStrip1.Text = "Injecting watermark... "+Convert.ToString(progressBar1.Value);
}
pictureBox1.Image = CurBmp;
progressBar1.Value = 0;
}
}
private void mixingMethodToolStripMenuItem_Click(object sender, EventArgs e)
{
int i, j;
int BegHPoint, BegVPoint, EndHPoint, EndVPoint;
Color c1,c2;
double HR=1,VR=1;//horizontal&vertical resolution - get from form
Application.DoEvents();
if (CurBmp != null)
{
wmpar = new WMParameters();
if (DialogResult.OK == wmpar.ShowDialog())
{
Application.DoEvents();
progressBar1.Maximum = 100;
progressBar1.Value = 0;
Image img = Image.FromFile(wmpar.pathname);
double rt = 1 - wmpar.TR;
WMBmp = new Bitmap(img);
switch (wmpar.LA)
{
case WMParameters.WMLayout.Center:
VR = (float)(WMBmp.Height) / (float)(CurBmp.Height * wmpar.WS);
HR = (float)(WMBmp.Width) / (float)(CurBmp.Width * wmpar.WS);
BegHPoint = (int)((float)CurBmp.Width / 2 * (1 - wmpar.WS));
BegVPoint = (int)((float)CurBmp.Height / 2 * (1 - wmpar.WS));
EndHPoint = CurBmp.Width - BegHPoint;
EndVPoint = CurBmp.Height - BegVPoint;
for (i = BegHPoint; i <= EndHPoint - 1; i++)
for (j = BegVPoint; j <= EndVPoint - 1; j++)
{
c1 = CurBmp.GetPixel(i, j);
if (((i - BegHPoint) * HR < WMBmp.Width) && ((j - BegVPoint) * VR < WMBmp.Height))
c2 = WMBmp.GetPixel((int)((i - BegHPoint) * HR), (int)((j - BegVPoint) * VR));
else
c2 = CurBmp.GetPixel(i, j);
CurBmp.SetPixel(i, j, Color.FromArgb((int)(c1.A * rt + c2.A * (1 - rt)), (int)(c1.R * rt + c2.R * (1 - rt)), (int)(c1.G * rt + c2.G * (1 - rt)), (int)(c1.B * rt + c2.B * (1 - rt))));
progressBar1.Value = Convert.ToInt32((float)((i - BegHPoint) * CurBmp.Height * wmpar.WS + j - BegVPoint) / (float)(CurBmp.Width * CurBmp.Height * wmpar.WS * wmpar.WS) * 100);
}
break;
case WMParameters.WMLayout.Stretch:
HR = (float)WMBmp.Height / (float)CurBmp.Height;
VR = (float)WMBmp.Width / (float)CurBmp.Width;
for (i = 0; i <= CurBmp.Width - 1; i++)
for (j = 0; j <= CurBmp.Height - 1; j++)
{
c1 = CurBmp.GetPixel(i, j);
c2 = WMBmp.GetPixel((int)(i * VR), (int)(j * HR));
CurBmp.SetPixel(i, j, Color.FromArgb((int)(c1.A * rt + c2.A * (1 - rt)), (int)(c1.R * rt + c2.R * (1 - rt)), (int)(c1.G * rt + c2.G * (1 - rt)), (int)(c1.B * rt + c2.B * (1 - rt))));
progressBar1.Value = Convert.ToInt32((float)(i * CurBmp.Height + j) / (float)(CurBmp.Width * CurBmp.Height) * 100);
}
break;
case WMParameters.WMLayout.Tile:
VR = (float)(WMBmp.Height) / (float)(CurBmp.Height * wmpar.WS);
HR = (float)(WMBmp.Width) / (float)(CurBmp.Width * wmpar.WS);
BegHPoint = 0;
EndHPoint = 0;
switch (wmpar.HA)
{
case WMParameters.HrAlignment.Left:
BegHPoint = 0;
EndHPoint = (int)(CurBmp.Width * wmpar.WS - 1);
break;
case WMParameters.HrAlignment.Middle:
BegHPoint = (int)((float)CurBmp.Width / 2 * (1 - wmpar.WS));
EndHPoint = CurBmp.Width - BegHPoint;
break;
case WMParameters.HrAlignment.Right:
BegHPoint = (int)(CurBmp.Width * (1 - wmpar.WS) - 1);
EndHPoint = CurBmp.Width;
break;
}
BegVPoint = 0;
EndVPoint = 0;
switch (wmpar.VA)
{
case WMParameters.VrAlignment.Upper:
BegVPoint = 0;
EndVPoint = (int)(CurBmp.Height * wmpar.WS - 1);
break;
case WMParameters.VrAlignment.Center:
BegVPoint = (int)((float)CurBmp.Height / 2 * (1 - wmpar.WS));
EndVPoint = CurBmp.Height - BegVPoint;
break;
case WMParameters.VrAlignment.Lower:
BegVPoint = (int)(CurBmp.Height * (1 - wmpar.WS) - 1);
EndVPoint = CurBmp.Height;
break;
}
for (i = BegHPoint; i <= EndHPoint - 1; i++)
for (j = BegVPoint; j <= EndVPoint - 1; j++)
{
c1 = CurBmp.GetPixel(i, j);
if (((i - BegHPoint) * HR < WMBmp.Width) && ((j - BegVPoint) * VR < WMBmp.Height))
c2 = WMBmp.GetPixel((int)((i - BegHPoint) * HR), (int)((j - BegVPoint) * VR));
else
c2 = CurBmp.GetPixel(i, j);
CurBmp.SetPixel(i, j, Color.FromArgb((int)(c1.A * rt + c2.A * (1 - rt)), (int)(c1.R * rt + c2.R * (1 - rt)), (int)(c1.G * rt + c2.G * (1 - rt)), (int)(c1.B * rt + c2.B * (1 - rt))));
progressBar1.Value = Convert.ToInt32((float)((i - BegHPoint) * CurBmp.Height * wmpar.WS + j - BegVPoint) / (float)(CurBmp.Width * CurBmp.Height * wmpar.WS * wmpar.WS) * 100);
}
break;
case WMParameters.WMLayout.Zoom:
VR = (float)WMBmp.Height / (float)CurBmp.Height;
HR = (float)WMBmp.Width / (float)CurBmp.Width;
double resol = (HR > VR) ? HR : VR;
BegHPoint = (HR < VR) ? (int)(CurBmp.Width / 2 - (float)(WMBmp.Width / (resol * 2))) : 0;
EndHPoint = (HR < VR) ? (int)(CurBmp.Width / 2 + (float)(WMBmp.Width / (resol * 2))) : CurBmp.Width;
BegVPoint = (HR < VR) ? 0 : (int)(CurBmp.Height / 2 - (float)(WMBmp.Height / (resol * 2)));
EndVPoint = (HR < VR) ? CurBmp.Height : (int)(CurBmp.Height / 2 + (float)(WMBmp.Height / (resol * 2)));
for (i = BegHPoint; i <= EndHPoint - 1; i++)
for (j = BegVPoint; j <= EndVPoint - 1; j++)
{
c1 = CurBmp.GetPixel(i, j);
if (((i - BegHPoint) * HR < WMBmp.Width) && ((j - BegVPoint) * VR < WMBmp.Height))
c2 = WMBmp.GetPixel((int)((i - BegHPoint) * resol), (int)((j - BegVPoint) * resol));
else
c2 = CurBmp.GetPixel(i, j);
CurBmp.SetPixel(i, j, Color.FromArgb((int)(c1.A * rt + c2.A * (1 - rt)), (int)(c1.R * rt + c2.R * (1 - rt)), (int)(c1.G * rt + c2.G * (1 - rt)), (int)(c1.B * rt + c2.B * (1 - rt))));
progressBar1.Value = Convert.ToInt32((float)((i - BegHPoint) * (EndVPoint - BegVPoint) + j - BegVPoint) / (float)((EndHPoint - BegHPoint) * (EndVPoint - BegVPoint)) * 100);
statusStrip1.Text = "Injecting watermark... " + Convert.ToString(progressBar1.Value);
}
break;
}
}
}
else
MessageBox.Show("Container is not opened!");
pictureBox1.Image = CurBmp;
progressBar1.Value = 0;
}
private void saveToolStripMenuItem_Click(object sender, EventArgs e)
{
saveFileDialog1 = new SaveFileDialog();
saveFileDialog1.RestoreDirectory = true;
saveFileDialog1.FilterIndex = 1;
saveFileDialog1.Filter = "jpg Files (*.jpg)|*.jpg|gif Files (*.gif)|*.gif|png Files (*.png)|*.png |bmp Files (*.bmp)|*.bmp";
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
string ext = Path.GetExtension(saveFileDialog1.FileName);
switch (ext)
{
case ".jpg":
CurBmp.Save(saveFileDialog1.FileName,ImageFormat.Jpeg);
break;
case ".gif":
CurBmp.Save(saveFileDialog1.FileName,ImageFormat.Gif);
break;
case ".png":
CurBmp.Save(saveFileDialog1.FileName,ImageFormat.Png);
break;
default:
CurBmp.Save(saveFileDialog1.FileName,ImageFormat.Bmp);
break;
}
}
}
private void exitToolStripMenuItem_Click(object sender, EventArgs e)
{
this.Close();
}
private void closeToolStripMenuItem_Click(object sender, EventArgs e)
{
CurBmp = null;
pictureBox1.Image = null;
operationsToolStripMenuItem.Enabled = false;
}
private void injectToolStripMenuItem_Click(object sender, EventArgs e)
{
openFileDialog3.FileName = "";
openFileDialog3.Filter = "All files (*.*)|*.*";
if (openFileDialog3.ShowDialog() == DialogResult.OK)
{
Application.DoEvents();
LSBInjector lsb = new LSBInjector(CurBmp, openFileDialog3.FileName, 1);
CurBmp = lsb.Inject();
pictureBox1.Image = CurBmp;
progressBar1.Value = 0;
MessageBox.Show("Ready!");
}
}
private void assureToolStripMenuItem_Click(object sender, EventArgs e)
{
openFileDialog3.FileName = "";
openFileDialog3.Filter = "All files (*.*)|*.*";
if (openFileDialog3.ShowDialog() == DialogResult.OK)
{
Application.DoEvents();
LSBInjector lsb = new LSBInjector(CurBmp, openFileDialog3.FileName, 1);
bool b = lsb.Assure();
if (b)
MessageBox.Show("Watermark is assured");
else
MessageBox.Show("Watermark is not assured");
pictureBox1.Image = CurBmp;
progressBar1.Value = 0;
}
}
private void injectToolStripMenuItem1_Click(object sender, EventArgs e)
{
openFileDialog3.FileName = "";
openFileDialog3.Filter = "All files (*.*)|*.*";
if (openFileDialog3.ShowDialog() == DialogResult.OK)
{
Application.DoEvents();
PatchworkInjector pi = new PatchworkInjector(CurBmp, openFileDialog3.FileName);
CurBmp = pi.Inject();
MessageBox.Show("Ready!");
}
pictureBox1.Image = CurBmp;
}
private void assureToolStripMenuItem1_Click(object sender, EventArgs e)
{
openFileDialog3.FileName = "";
openFileDialog3.Filter = "All files (*.*)|*.*";
if (openFileDialog3.ShowDialog() == DialogResult.OK)
{
Application.DoEvents();
PatchworkInjector pi = new PatchworkInjector(CurBmp, openFileDialog3.FileName);
bool b = pi.Assure();
if (b)
MessageBox.Show("Watermark is assured");
else
MessageBox.Show("Watermark is not assured");
}
pictureBox1.Image = CurBmp;
}
}
}