Глубокое увеличение – база данных Silverlight - Хранение растровых изображений в базе данных Microsoft Access

ОГЛАВЛЕНИЕ

Хранение растровых изображений в базе данных Microsoft Access

Не каждый день приходится сохранять растровые изображения в поле BLOB (большой двоичный объект). Для достижения этой цели используется объект параметризованной команды. Параметр для растрового изображения должен иметь тип OleDbType.LongVarBinary, и этому параметру передается массив байтов. Чтобы превратить растровое изображение в массив байтов, растровое изображение сериализуется в поток памяти с помощью BinaryFormatter.

public override void SaveImageTile(int imageId, int level, 
                     int x, int y, Bitmap bitmap)
{
    // Создается SQL

    string sql = "INSERT INTO DeepZoomTile(imageId, [level], x, y,
        bitmap) values (?, ?, ?, ?, ?)";
    var cmd = new OleDbCommand(sql, dbConnection);

    //Сериализация изображения
    byte[] bytes = BitmapToByteArray(bitmap);

    // Добавление параметров
    cmd.Parameters.Add("@imageid", OleDbType.Integer).Value = imageId;
    cmd.Parameters.Add("@level", OleDbType.Integer).Value = level;
    cmd.Parameters.Add("@x", OleDbType.Integer).Value = x;
    cmd.Parameters.Add("@y", OleDbType.Integer).Value = y;
    cmd.Parameters.Add("@bitmap", OleDbType.LongVarBinary,
        bytes.Length).Value = bytes;

    // Исполнение
    cmd.ExecuteNonQuery();
}

/// <summary>
/// Сериализация бинарного изображения в байтовый массив
/// </summary>
/// <param name="bitmap">Бинарное изображение.</param>
/// <returns></returns>
private static byte[] BitmapToByteArray(Bitmap bitmap)
{
    var memStream = new MemoryStream();
    var formatter = new BinaryFormatter();
    formatter.Serialize(memStream, bitmap);

    byte[] bytes = memStream.GetBuffer();
    memStream.Close();
    return bytes;
}

Возврат информации об изображениях из базы данных в окно списка Silverlight

Веб-интерфейс показывает окно списка правее изображения с глубоким увеличением. Это окно списка отображает данные из базы данных. Поскольку Silverlight не может работать с DataTable или DataSet, нельзя передать один из этих объектов как обычно. Поэтому класс доступа к базе данных возвращает список объектов ImageInfo. Здесь LINQ превосходно упрощает работу разработчика, если вы поняли требуемый им синтаксис. Вы можете использовать данный пример всегда, когда понадобится вернуть список объектов из DataSet. Переданный параметр fromUri метода необходим для возврата ThumbnailUrl. Так как приложение Silverlight может быть развернуто где угодно в сети, а значит и путь к HttpHandler, возвращающему эскиз изображения, меняется, URI передается с вызывающей страницы. При этом адрес для ThumbnailUrl всегда верен.

/// <summary>
/// Получает список с информацией об изображениях.
/// </summary>
/// <param name="fromUri">Url, из которого делается вызов.</param>
/// <returns></returns>
public override List<ImageInfo> GetImageInfo(Uri fromUri)
{
    string sql = "Select * from DeepZoomImage order by imageName";
    var dataAdapter = new OleDbDataAdapter(sql, dbConnection);
    var ds = new DataSet();

    dataAdapter.Fill(ds, "ImageInfo");

    var imageInfos = from image in ds.Tables["ImageInfo"].AsEnumerable()
                     select new ImageInfo
                    {
                        ImageId = image.Field<int>("ImageId"),
                        ImageName = image.Field<string>("ImageName"),
                        Height = image.Field<int>("Height"),
                        Width = image.Field<int>("Width"),
                        TileSize = image.Field<int>("TileSize"),
                        Overlap = image.Field<int>("Overlap"),
                        MimeType = image.Field<string>("MimeType"),
                        ThumbnailUrl = new Uri(fromUri,
                               "ThumbnailHandler.ashx?ImageId=" +
                               image.Field<int>("ImageId")).ToString()
                    };

    return imageInfos.ToList();
}

Возвращенный список объектов ImageInfo затем передается приложению Silverlight с помощью службы WCF. Служба, определенная в приложении ASP.NET, выглядит так:

namespace DeepZoomSilverlightWeb
{
    [ServiceContract(Namespace = "")]
    [AspNetCompatibilityRequirements(RequirementsMode =
        AspNetCompatibilityRequirementsMode.Allowed)]
    public class ImageListService
    {
        /// <summary>
        /// Получает список изображений из базы данных.
        /// </summary>
        /// <returns>Список объектов ImageInfo</returns>
        [OperationContract]
        public List<ImageInfo> GetImageList()
        {
            DbDzComposer.DzDbAccess accessDb = Helper.GetAccessDb();
            return accessDb.GetImageInfo(HttpContext.Current.Request.Url);
        }
    }
}

В приложении Silverlight, использующем возвращенный список, вызывается метод GetImageList из конструктора страницы. Так как это асинхронный вызов, он связывается с обработчиком события завершенного этого метода.

Сначала инициализируется imageListClient...

public Page()
{
    InitializeComponent();

    // Установка источника данных для списка
     var imageListClient = ServiceClientFactory.GetImageListServiceClient();
    imageListClient.GetImageListCompleted +=
      new EventHandler<DeepZoomSilverlightProject.
          ImageListClient.GetImageListCompletedEventArgs>(
    imageListCliet_GetImageListCompleted);
    imageListClient.GetImageListAsync();

Результат связывается с imageList, и выбирается первый элемент в списке...

/// <summary>
/// Обрабатывает событие GetImageListCompleted управляющего элемента imageListCliet.
/// </summary>
/// <param name="sender">Источник события.</param>
/// <param name="e">The <see cref="DeepZoomSilverlight
///                 Project.ImageListClient.GetImageListCompletedEventArgs"/>
/// экземпляр, содержащий данные события.</param>
void imageListCliet_GetImageListCompleted(object sender,
    DeepZoomSilverlightProject.ImageListClient.GetImageListCompletedEventArgs e)
{
    // Установка источника данных для списка изображений
    imageList.ItemsSource = e.Result;

    if (imageList.Items.Count > 0)
        imageList.SelectedIndex = 0;
}

В событии SelectionChanged окна списка передается объект MultiScaleTileSource в MultiScaleImage.
private void imageList_SelectionChanged(object sender, SelectionChangedEventArgs e)

{
    ImageInfo imageInfo = imageList.SelectedItem as ImageInfo;

    if (imageInfo != null)
    {
        // Установка источника изображения
        msi.Source = new DeepZoomTileSource(imageInfo.ImageId,
            imageInfo.Width, imageInfo.Height, imageInfo.TileSize,
            imageInfo.Overlap, imageInfo.MimeType);
    }
}

Вот и все! Надеемся код вам поможет в ваших проектах.