Проектирование и разработка веб-приложений на основе технологий Microsoft

Работа с изображениями в ASP.Net

Показывать лекцию целиком

Доступ к изображениям с веб - страниц

HTML-тэг <img> используется для вывода изображения на Web-странице. Он поддерживает несколько атрибутов, с помощью которых задается ширина, высота изображения и альтернативный текст, выводимый, когда оно не доступно. HTML-определение этого элемента таково:

<img id="control ID" alt="alternate text"
align="top | middle | bottom | left | right" border="border width" height="height" src="URL"
width=" width" />

В Visual Studio имеется два серверных элемента управления для размещения изображений на веб - странице: Image и ImageButton.На панели свойств этих ЭУ можно указать URL изображения и задать прочие параметры (размер изображения, ID ЭУ и пр.)

Отличие Image от ImageButton заключается в том, что у ImageButton присутствует событие Click.

Доступ к изображениям, хранящимся в базе данных

Вопрос о целесообразности применения баз данных для хранения изображений является спорным. Одни специалисты считают такое решение вполне эффективным, другие говорят, что никогда не делали этого и не будут делать. Как бы там ни было, фактом остается то, что все популярные СУБД уже давным-давно поддерживают большие двоичные объекты — BLOB (binary large objects).

BLOB (англ. Binary Large OBject — двоичный большой объект) — массив двоичных данных. В СУБД BLOBспециальный тип данных, предназначенный, в первую очередь, для хранения изображений, аудио и видео, а также компилированного программного кода.

Загрузка В БД

// Показываем диалог выбора файла 
openFileDialog1.ShowDialog(); 
// В качестве имени сохраняемого файла устанавлиываем переменную fileName 
string fileName = openFileDialog1.FileName; 

Byte[] blob;// = null; 
using (FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read)) 
{ 
blob = new Byte[fileStream.Length]; 
fileStream.Read(blob, 0, blob.Length); 
} 

string commandText = "INSERT INTO table1 (name, rtf) VALUES(@name, @rtf)"; 
myCommand.Connection = conn; 
myCommand.CommandText = commandText; 

OleDbDataAdapter dataAdapter = new OleDbDataAdapter(); 
dataAdapter.InsertCommand = myCommand; 
myCommand.Parameters.Add("@name", OleDbType.VarChar, 50).Value = "Дима"; 
myCommand.Parameters.Add("@rtf", OleDbType.Binary, blob.Length).Value = blob; 


DataSet ds = new DataSet(); 

dataAdapter.TableMappings.Add("Table", "table1"); 
//dataAdapter.Fill(ds); 

conn.Open(); 
myCommand.ExecuteNonQuery(); 
conn.Close();

\

Чтение изображения из базы

//Показываем диалог выбора файла 
saveFileDialog1.ShowDialog(); 
// В качестве имени сохраняемого файла устанавлиываем переменную fileName 
string fileName = saveFileDialog1.FileName; 
//Создаем поток fs и открываем файл для записи. 
FileStream filestream = File.Open(fileName, FileMode.Create, FileAccess.Write); 
//Проверяем, открыт ли поток, и если открыт, выполняем условие 
if (filestream != null) 
{ 
//Создаем объект streamwriter и связываем его с потоком filestream 
StreamWriter streamwriter = new StreamWriter(filestream); 
//Записываем данные из TextBox в файл 


OleDbDataReader reader = myCommand.ExecuteReader(); 
BinaryWriter bw = new BinaryWriter(filestream); 

int bufferSize = 1024 * 1024 * 9; 
byte[] buffer = new byte[bufferSize]; 
reader.Read(); 
long startIndex = 0; 
int columnIdx = 2; 
long retval = reader.GetBytes(columnIdx, startIndex, buffer, 0, bufferSize); 
while (retval == bufferSize) 
{ 
bw.Write(buffer); 
bw.Flush(); 

startIndex += bufferSize; 
retval = reader.GetBytes(columnIdx, startIndex, buffer, 0, bufferSize); 
} 
bw.Write(buffer, 0, (int)retval); 
bw.Flush(); 



streamwriter.Write(buffer); 
//Переносим данные из потока в файл 
streamwriter.Flush(); 
//Закрываем поток 
filestream.Close(); 
} 
reader.Close(); conn.Close(); 

richTextRTF.LoadFile("Имя_Файла.rtf");

Динамическое генерирование изображений

Краткий обзор классов GDI+

GDI+ — это графическое ядро Microsoft Windows ХР, доступное и для других 32-и 64-разрядных платформ, в частности Windows 2000 и Windows 2003. Система GDI+, как следует из ее имени, является наследницей всем известной GDI (Graphics Device Interface — интерфейс графических устройств), входившей в состав предыдущих версий операционной системы Windows. .NET Framework инкапсулирует ключевые функции GDI+ в наборе управляемых классов и делает их доступными для приложений Web, Windows Forms и Web-сервисов.

Большую часть сервисов GDI+ можно отнести к одной из двух категорий: двумерная векторная графика и операции с изображениями. К первой относятся средства рисования простых фигур, таких как линии, кривые и многоугольники; что касается второй категории, то сюда относятся функции для вывода растровых и векторных изображений, манипулирования ими, их сохранения и преобразования. Есть еще и функции, принадлежащие к третьей категории, — типографические; они обеспечивают вывод текста различными шрифтами.

Имея в виду динамическое создание изображений на Web-сервере, мы сосредоточимся на рисовании фигур и текста, а также сохранении результатов в файлах формата JPEG или GIF.

Класс Graphics

Центральным элементом модели программирования Win32 GDI является контекст устройства. Так называется структура данных, используемая для хранения информации о возможностях конкретного устройства отображения. Контекст устройства ассоциируется с поверхностью для рисования, такой как окно, бумага в принтере или блок памяти. Программы Win32 получают дескриптор контекста устройства и передают его всем вызываемым функциям GDI. В составе контекста устройства поддерживается список установленных графических атрибутов — цвета фона и рисования, кисть, перо и шрифт. Можно сказать, что контекст устройства является связующим звеном между высокоуровневым API и драйверами устройств.

Класс Bitmap

Класс Bitmap инкапсулирует растровое изображение GDI+, он содержит пикселы самого изображения плюс несколько атрибутов. В GDI+ поддерживается три типа растровых изображений — битовые карты, значки и метафайлы. Все три соответствующих класса являются производными от абстрактного класса Bitmap. Заметьте, что экземпляр класса Bitmap вовсе не обязательно представляет файл с расширением .bmp; это универсальный контейнер пиксельных данных, которые можно сохранить в виде изображения формата BMP или JPG, — как вы сочтете нужным.

Заполнение прямоугольников

Для создания заполненного прямоугольника вам потребуется указать лишь вид кисти и размеры прямоугольника. Метод, которым вы будете пользоваться, называется FillRectangle, а рабочую область для него можно задать либо непосредственно в виде координат, либо с использованием структуры RectangleF:

g.FillRectangle(brush, area);

В данном вызове brush — это объект-кисть, используемый для рисования прямоугольника. GDI+ поддерживает множество разных видов кисти, в том числе сплошную, градиентную и текстурную. Следующий код показывает, как можно нарисовать и заполнить прямоугольник:

// Рисуем границу
Pen р = new Pen(Color.Black);
g.DrawRectangle(p, 0, 0, width, height);

// Заполняем
Brush brlnterior = new SolidBrush(Color.SkyBlue); 
g.FillRectangle(brInterior, 1, 1, width-2, height-2);

Рисование текста

Метод DrawString объекта Graphics принимает текстовую строку, которую ему нужно вывести, объект, представляющий шрифт, и кисть, которой этот текст будет нарисован. Кроме того, вы можете задать прямоугольник, в который необходимо вписать текст, способ выравнивания (по вертикали или по горизонтали) и указать, что делать, если текст не поместится в заданную область, — обрезать его или выйти за пределы области. Воспользовавшись структурой StringFormat, можно задать все эти параметры одновременно.

StringFormat sf = new StringFormat(); 
sf.Alignment = StringAlignment.Center; 
sf.LineAlignment = StringAlignment.Center;

// Рисуем текст
Font f = new Font('Tahoma", 16);
g.DrawString("Hello, world", f, 
                new SolidBrush(Color.White), 
                new Rectangle(0, 0, width, height), sf);

Возможности GDI+ гораздо, шире, чем мы здесь описали, они отнюдь не ограничены выполнением нескольких простых операций. Однако полное рассмотрение функций этой системы выходит за рамки данной книги.

Поддерживаемые форматы изображений

GDI+ поддерживает достаточно много форматов изображений, включая самые распространенные из них: JPEG, GIF, BMP и PNG. Полный набор форматов изображений содержится в структуре ImageFormat. Находящийся в памяти объект Bitmap можно сохранить в любом поддерживаемом формате, используя одну из перегруженных версий метода Save:

bmp.Save(outputStream, ImageFormat.Gif);

Когда вы пытаетесь записать изображение в выходной поток или дисковый файл, система ищет кодер для запрошенного формата. Этим кодером является модуль GDI+, преобразующий данные в указанный формат. Учтите, что кодер реализован в виде неуправляемого кода, функционирующего на платформе Win32. Как правило, кодер позволяет задать не только формат данных, но и дополнительные установки, такие, например, как степень сжатия изображения JPEG.

Создание круговой диаграммы

Проще всего рассмотреть создание круговой диаграммы на конкретном примере:

namespace SMPA
{
  public partial class Diagram : System.Web.UI.Page
  {

    public void ProcessRequest(HttpContext context)
    {
      object o = context.Request["url"];
      if (o == null)
      {
        context.Response.Write("No image found");
        context.Response.End();
        return;
      }
      string file = context.Server.MapPath((string)o);
      if (File.Exists(file))
      {
        Bitmap bmp = draw();
        context.Response.ContentType = "image/jpeg";
        bmp.Save(context.Response.OutputStream, ImageFormat.Jpeg);
        bmp.Dispose();
      }
      else
      {
        context.Response.Write("No image found");
        context.Response.End();
       }
     }

    //Приступаем к непосредственному созданию диаграммы           
    Bitmap draw()
    {

      string strTypesLegend = "";
      string strTestsData = "";
      //В данном пример данные для диаграммы передаются через сессии
      //и представляют собой две строки, в которых значения раздеены запятыми
      strTypesLegend = (string)Session["map"];
      strTestsData = (string)Session["data"];
      //формируем массивы исходных данных
      char[] str = strTestsData.ToCharArray();
      int length = strTestsData.Length;
      int size = 1;

      for (int i = 0; i < length; ++i)
      {
        if (str[i] == ',') { ++size; }
      }

      float[] data = new float[size];
      string d1 = "";
      int j = 0;
      float sum = 0;
      for (int i = 0; i < length; ++i)
      {
        if ((str[i] != ',')  (i != length - 1)) { d1 += str[i]; }
        else
        {
          if (i == length - 1) { d1 += str[i]; }
          data[j] = Convert.ToInt64(d1);
          d1 = "";
          sum += data[j];
          ++j;
        }
      }
      //
      //массив исходных данных легенды диаграммы
      int leglength = strTypesLegend.Length;
      char[] chr = strTypesLegend.ToCharArray();
      string[] legend = new string[size];
      j = 0;
      for (int i = 0; i < leglength; ++i)
      {
        if ((chr[i] != ',')  (i != leglength)) { d1 += chr[i]; }
        else
        {
          legend[j] = "" + d1;
          d1 = "";
          ++j;
        }
        if (i == leglength - 1) { legend[j] = "" + d1; };
      }
      //

      // Для упрощения и большей наглядности, было решено выводить только 10 
     //значений данных, 9 наибольших и 1 - для всех оставшихся значений
      if (size > 10)
      {
        float sumoth = 0;
        for (int i = 9; i < size; i++)
        {
          sumoth += data[i];
        }
        data[9] = sumoth;
        legend[9] = "other";
        size = 10;
      }
      //

      Bitmap bmp = new Bitmap(500, 250);
      Graphics g = Graphics.FromImage(bmp);
      //задаем цвета секторов диаграммы
      Color[] clr = new Color[10];
      clr[0] = Color.Red;
      clr[1] = Color.Blue;
      clr[2] = Color.Violet;
      clr[3] = Color.Green;
      clr[4] = Color.Gray;
      clr[5] = Color.Chocolate;
      clr[6] = Color.Coral;
      clr[7] = Color.Indigo;
      clr[8] = Color.GreenYellow;
      clr[9] = Color.Khaki;
      float startAngle = 0;
      g.Clear(Color.White);
      StringFormat sf = new StringFormat();
      sf.Alignment = StringAlignment.Near;
      sf.LineAlignment = StringAlignment.Near;
      Font f = new Font("Times New Roman", 10);

      StringFormat sfr = new StringFormat();
      sfr.Alignment = StringAlignment.Near; ;
      sfr.LineAlignment = StringAlignment.Near;
      int t = 0;
      //Рисуем сегменты
      for (int counter = 8; counter > 0; --counter )
        for (int i = 0; i < size; ++i)
        {
          double dt = data[i] * 360 / sum;
          double prcnt = data[i] / sum * 100;
          //вычисляем угол очередного сегмента
          float sweepAngle = Convert.ToInt64(Math.Round(dt));

          Rectangle rect1 = new Rectangle(/*20-counter*/0, 2*counter, 250, 150);
          if (counter == 1)
          {
            g.FillPie(new SolidBrush(clr[i]), rect1, startAngle, sweepAngle);
          }
          else
          {
            g.FillPie(new HatchBrush(HatchStyle.Percent50, Color.Black, clr[i]),
            rect1, startAngle, sweepAngle);
          }
          
          if ((counter == 8) || (counter == 1))
          {
            g.DrawEllipse(new Pen(Color.Black, 1), rect1);
          }
          startAngle += sweepAngle;
          //Отрисовка легенды
          Rectangle rec = new Rectangle(280, i * 20, 250, 50);
          g.FillRectangle(new SolidBrush(clr[i]), new Rectangle(260,i*20,10,10));
          g.DrawString(legend[i] + " - " +data[i]+" ("+ 
                        Math.Round(prcnt, 2) + "%)", 
                       f, new SolidBrush(Color.Black), rec, sf);

        }            
        return bmp;
      }
    }
  }

Примеры диаграмм, сформированных на основе данного кода:

Вернуться к учебному плану