Программирование сайтов | Плагин. Сохранение картинок блога на диске.

В этом разделе сайта дается описание технологии проектирования интернет-ресурсов на базе ASP.NET (Active Server Pages). Примерный стек разработки asp страниц: C#, ASP.NET, SQL Server, Visual Studio, CSS, HTML, ASPX, ASCX, XML, XLSX, JavaScript, jQuery, JS, JSON, ZIP, Razor, bootstrap, Photoshop, Unit тесты, шаблоны MVC и Repository.

Плагин. Сохранение картинок блога на диске.

Прежде, чем начать решать задачу программирования сложных разделов блога надо научиться разрабатывать плагины. Они относятся к расширениям, которые бывают трех типов: темы, плагины и виджеты. Для изучения плагина потребуется знать только C# и структуры блога

Создадим новый плагин "Сохранение картинок блога на диске", на английском языке выглядит название так: AutoSaveBlobImage. В списке плагинов блога он выглядит так.

Кнопка CUSTOMIZE позволяет вызвать форму с настройками плагина. Настройки изменяются через код C#. 

Для чего нужен этот плагин. Когда Вы перенесете картинку через буфер обмена (Windows Paint) в блог, то он на диске не сохраняется. Он конвертируется в BLOB формат и хранится как текст в базе данных. Для этого нажмите кнопку <> (исходный код) и просмотрите этот текст. Есть важное замечание. Такой объем в базе данных текста-картинок является не правильным с точки зрения производительности системы. Она падает, приходится из базы данных загружать много информации. Лучше, чтобы картинка в блоге ссылалась на графический файл на диске *.png, *.gif, *.jpg Вот это мы попытаемся сделать с помощью плагина. Найдем в сообщении блога BLOB текст и заменим его на ссылку на файл, который сохраним на диск. Примечание. Плагин можно отключить, если нам он не нужен.

 

Разберем структуру кода плагина на C#.

  • Сначала найдите в коде Extension (Расширение). Прямо в программе мы описываем назначение модуля, что он будет делать. Даем описание некоторых параметров, BlobPrefix, FileFormat, EndContent. Можно даже дать описание на ссылку плагина в интернете. В коде она не задействована, просто указан сайт me.ru
  • Находим функцию AutoSaveBlobImage. Она задает события которые нужно обработать при обработке сообщения блога.
  • Функция ServingHandler обрабатывает входящее сообщение, т.е. мы должны в сообщении найти нужный нам текст
  • Функция PostSaved сохраняет картинку, Slug - это название статьи блога на английском языке, добавлено как дополнительная функция.

Первая часть кода

/// <summary>
/// Сохраняет изображения в формате BLOB на диск ввиде файла.
/// </summary
[Extension(
    "Сохраняет изображения в формате BLOB на диск ввиде файла. " + 
    "Для имени файла использует заголовок сообщения, причем русское " + 
    "название сообщения конвертирует в английский вариант.<br>" +
    "Параметры:<br>" + 
    " • BlobPrefix - префикс изображения в формате Blob<br>" +
    " • FileFormat - формат файла для сохранения на диск<br>" +
    " • EndContent - Тэг окончания текста в сообщении.",
    "1.0", "<a href=\"http://me.ru\">Me</a>")]

public class AutoSaveBlobImage
{
    // Настройки, т.е. параметры расширения
    static protected ExtensionSettings _settings = null;
     
    public AutoSaveBlobImage()
    {
        //Post.Serving += new EventHandler<ServingEventArgs>(ServingHandler);
        Post.Serving += ServingHandler;
        Post.Saved += PostSaved;
        InitSettings();
    }

    /// <summary>
    /// Обрезаем лишний текст в сообщении, например, таблицу цен и т.п.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="BlogEngine.Core.ServingEventArgs"/> instance containing the event data.</param>
    private static void ServingHandler(object sender, ServingEventArgs e)
    {
        if (!ExtensionManager.ExtensionEnabled("AutoSaveBlobImage"))
            return;

        var body = e.Body;

        // Тег окончания содержания. Далее может идти любой текст.
        string EndContent = _settings.GetSingleValue("EndContent");
        var start = body.IndexOf($"{EndContent}");
        if (start <= -1)
        {
            return;
        }

        e.Body = body.Substring(0, start); 
    }
    // --- End ---

    /// <summary>
    /// Сохраняем сообщение
    /// </summary>
    private static void PostSaved(object sender, SavedEventArgs e)
    {
        // Проверка доступности приложения
        if (!ExtensionManager.ExtensionEnabled("AutoSaveBlobImage"))
            return;

        // Отменяем, если действия не сохраняют Post
        if (e.Action == SaveAction.None || e.Action == SaveAction.Delete)
            return;

        // Сохраняем картинки
        Post p = (Post)sender;
        Save(p);
        if (_settings.GetSingleValue("SlugToEnglish") == "True")
         {
            p.Slug = RusToLatin(p.Slug);
         }
    }

Вторая часть кода.  Если нажать на кнопку CUSTOMIZE, то можно увидеть форму с детальным описанием этого плагина. Добавляем параметры, чтобы отобразить текст в панели администратора.

  private void InitSettings()
    {
  
        ExtensionSettings settings = new ExtensionSettings(this);
        settings.IsScalar = true;
        settings.Help = "Настройки сохранения сообщения";
        settings.AddParameter("BlobPrefix", "Префикс BLOB изображения в тексте сообщения");
        settings.AddParameter("FileFormat","Новый формат файла в сообщении");
        settings.AddParameter("EndContent","Конец содержания сообщения.");
        settings.AddParameter("SlugToEnglish","Конвертировать Slug в английское название",1,true,false,ParameterType.Boolean);
        settings.AddValue("BlobPrefix", "data:image/png;base64,");
        settings.AddValue("FileFormat", "<img src =\"/blog/image.axd?picture=/Posts/Auto/{0}\"");
        settings.AddValue("EndContent", "[_EndContent_]");
        settings.AddValue("SlugToEnglish", true);

    }

Третья часть кода. Меняем текст в сообщении, т.е. заменяем BLOB на ссылку на файл. Используем библиотеку Regex для поиска данных. Функция SaveByteToImage сохраняет данные на диск

  private static string Save(Post item)
    {
        string newbody = "";
        try
        {
            //string BlobPrefix = "data:image/png;base64,";
            // Получаем переменные из настроек
            string BlobPrefix = _settings.GetSingleValue("BlobPrefix");
            string FileFormat = _settings.GetSingleValue("FileFormat");

            // Проверка на Blob
            if (item.Content.Contains(BlobPrefix) == false)  return "";

            // Создаем новый текст
            string src;
            string[] substrings = Regex.Split(item.Content, "<img[^>]+src=[\"']([^\"']+)[\"']");

            var p = BlobPrefix.Length ;
            long n = 1;
            List<string> ImageExtensions = new List<string> { ".jpg", ".jpe", ".bmp", ".gif", ".png" };

            foreach (string ss in substrings)
            {
                string subss = ss;
                if (ss.Substring(0, p) == BlobPrefix)
                {
                    var base64String = ss.Substring(p);

                    // Назначаем имя файла
                    string FilePng = "";
                    do
                    {
                        FilePng = RusToLatin(item.Title) + "_" + n.ToString("000") + ".png";
                        n = n + 1;

                    } while (item.Content.Contains(FilePng) == true);

                    // Сохраняем на диске
                    byte[] byteArray = Convert.FromBase64String(base64String);
                    src = SaveByteToImage(byteArray, FilePng);
                    // <img src="/blog/image.axd?picture=/images/logo.png"
                    //subss = "<img src=\"/blog/image.axd?picture=/Posts/Auto/" + FilePng + "\"";
                    subss = string.Format(FileFormat, FilePng);
                }
                else
                {
                    // Поиск файла изображения по расширению
                    string ext = Strings.Right(ss, 4);
                    if (ImageExtensions.IndexOf(ext) >= 0) 
                    {
                        subss = "<img src=\"" + ss + "\"";
                    }
                }
                // Собираем строку
                newbody = newbody + subss;
            }
        }
        catch (ArgumentException ex)
        {
            Utils.Log("Ошибка сохранения изображения. Save: ", ex);
        }
        if (newbody != "") item.Content = newbody;
        return newbody;
    }

    // Сохраняем файл для изображения
    private static string SaveByteToImage(byte[] ByteArray, string FilePng)
    {
        try
        { 
            MemoryStream ms = new MemoryStream(ByteArray);
            var image = System.Drawing.Image.FromStream(ms);
            string LocalDir = "~/App_Data/files/Posts/Auto/";
            string DirImagePosts = HttpContext.Current.Server.MapPath(LocalDir);
            if (System.IO.Directory.Exists(DirImagePosts) == false)
                System.IO.Directory.CreateDirectory(DirImagePosts);
            string filename = LocalDir + FilePng;
            string FullFile = DirImagePosts + FilePng;
            image.Save(FullFile, System.Drawing.Imaging.ImageFormat.Png);
            return filename;
        }
        catch (Exception ex)
        {
            Utils.Log("Ошибка сохранения изображения. SaveByteToImage", ex);
            return "";
        }
    }

Выводы. Таким образом, мы создали собственный плагин. Благодаря этой идеологии, можно серьезно автоматизировать отображение статей в блоге, добавляя собственные теги в текст. Например, вы написали в блоге текст: {s1}ProductID=465{s1}. Он ничего не означает. Но если Вы напишите плагин для обработки таких тегов, то эта информация может быть заменена на нужный текст из базы данных, например, описание продукта

Add comment

Loading