Прежде, чем начать решать задачу программирования сложных разделов блога надо научиться разрабатывать плагины. Они относятся к расширениям, которые бывают трех типов: темы, плагины и виджеты. Для изучения плагина потребуется знать только 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}. Он ничего не означает. Но если Вы напишите плагин для обработки таких тегов, то эта информация может быть заменена на нужный текст из базы данных, например, описание продукта