Использование jpegtran, jpegoptim или другой оптимизации / сжатия jpeg в C#
У меня есть 100-е (может быть, 1000-е) продуктов с 10-30 изображениями каждого продукта, поступающего в интернет-магазин, который я собрал. Мне нужно максимально оптимизировать размеры файлов изображений без потери качества изображения.
Я не использовал jpegtran, jpegoptim или любой другой оптимизатор jpeg напрямую, но заметил, что punypng сокращает размеры файлов примерно на 4-6% на больших изображениях jpeg без потерь.
Метаданные уже извлекаются из изображений во время загрузки (через Jumpoader), так что это больше не является проблемой / проблемой.
Есть ли способ заставить один из оптимизаторов jpeg работать из кода C#?
Примечание: я использую общий хостинг Godaddy с IIS7 и.Net 3.5
5 ответов
Это может быть на 7 лет позже, но я столкнулся с этим вопросом, пытаясь решить эту проблему. В конце концов мне удалось сделать это, и это решение. Для PNG сначала необходимо установить nQuant с помощью NuGet.
включают:
using System.Web.Hosting;
using System.IO;
using System.Diagnostics;
using nQuant;
using System.Drawing;
using System.Drawing.Imaging;
Методы:
public void optimizeImages()
{
string folder =
Path.Combine(HostingEnvironment.ApplicationPhysicalPath, @"assets\temp");
var files = Directory.EnumerateFiles(folder);
foreach (var file in files)
{
switch (Path.GetExtension(file).ToLower())
{
case ".jpg":
case ".jpeg":
optimizeJPEG(file);
break;
case ".png":
optimizePNG(file);
break;
}
}
}
private void optimizeJPEG(string file)
{
string pathToExe = HostingEnvironment.MapPath("~\\adminassets\\exe\\") + "jpegtran.exe";
var proc = new Process
{
StartInfo =
{
Arguments = "-optimize \"" + file + "\" \"" + file + "\"",
FileName = pathToExe,
UseShellExecute = false,
CreateNoWindow = false,
WindowStyle = ProcessWindowStyle.Hidden,
RedirectStandardError = true,
RedirectStandardOutput = true
}
};
Process jpegTranProcess = proc;
jpegTranProcess.Start();
jpegTranProcess.WaitForExit();
}
private void optimizePNG(string file)
{
string tempFile = Path.GetDirectoryName(file) + @"\temp-" + Path.GetFileName(file);
int alphaTransparency = 10;
int alphaFader = 70;
var quantizer = new WuQuantizer();
using (var bitmap = new Bitmap(file))
{
using (var quantized = quantizer.QuantizeImage(bitmap, alphaTransparency, alphaFader))
{
quantized.Save(tempFile, ImageFormat.Png);
}
}
System.IO.File.Delete(file);
System.IO.File.Move(tempFile, file);
}
Он возьмет все файлы из папки /assets/temp и оптимизирует JPEG и PNG. Я следил за этим вопросом для PNG. Часть JPEG, которую я соскоблил из нескольких источников. Включая PicJam и Оптимизатор изображения. Я использую его путем загрузки всех файлов от пользователя во временную папку, запуска этого метода, загрузки файлов в хранилище BLOB-объектов Azure и удаления локальных файлов. Я скачал jpegtran здесь.
Если вам не нравится возиться с временными файлами, я бы посоветовал использовать C++/CLI.
Создайте C++/CLI dll проект в visual studio. Создайте один статический управляемый класс и определите функции так, как вы хотите их использовать из C#:
public ref class JpegTools
{
public:
static array<byte>^ Optimize(array<byte>^ input)
};
Эти функции, которые вы определяете, могут быть напрямую вызваны из C#, и вы можете реализовать их со всем, что предлагает C++.
массив ^ соответствует байтовому массиву C#. Вам нужно будет использовать pin_ptr<> для закрепления байтового массива в памяти, чтобы вы могли передавать данные неуправляемой вспомогательной функции Jpeg по вашему выбору. C++/CLI имеет достаточную поддержку для преобразования управляемых типов в собственные типы. Вы также можете выделить новый массив с помощью gc_new, чтобы возвращать CLI-совместимые типы. Если вам необходимо выполнить маршаллинг строк из C# в C++ как часть этого упражнения, используйте тип CString Mfc/Atl.
Вы можете статически связать весь код jpeg в dll. DLL C++ может быть смешан с чистым нативным кодом и кодом C++/CLI. В наших проектах C++ / CLI обычно только исходные файлы интерфейса знают о типах CLI, все остальные работают с типами C++.
Для этого нужно проделать определенную работу, но положительным моментом является то, что ваш код проверяется по типу во время компиляции, а все операции с неуправляемым кодом и памятью выполняются на стороне C++. На самом деле это работает настолько хорошо, что я использовал C++ / CLI для тестирования модулей собственного кода C++ почти напрямую с NUnit.
Удачи!
Я бы пакетно обработал изображения перед их загрузкой на ваш веб-сервер, а не пытался обрабатывать их во время их обслуживания. Это приведет к меньшей нагрузке на веб-сервер и позволит использовать любые подходящие инструменты для обработки изображений.
Я уверен, что опоздал ответить на этот вопрос, но недавно я столкнулся с проблемой оптимизации без потерь в формате jpeg и не нашел подходящей реализации C# утилиты jpegtran. Итак, я решил самостоятельно реализовать процедуры для уменьшения размера jpeg без потерь на основе оболочки C модифицированного jpegtran, которую вы можете найти здесь. Получается, что подобная реализация с использованием чистого.Net LibJpeg.NET намного медленнее, чем завернутое в C решение, поэтому я не включил его в репозиторий. Использование обертки довольно просто,
if (JpegTools.Transform(jpeg, out byte[] optimized, copy: false, optimize: true))
{
//do smth useful
}
else
{
//report on error or use original jpeg
}
Надеюсь, кто-то найдет это полезным.
Почему бы не вызвать punypng.com с Process.Start ()? Нет причин, по которым ваш код.net не может запускать внешние программы при условии, что обработка выполняется во время загрузки (а не при обработке изображений)
Например
- загрузить в папку "загрузить",
- есть службы windows, которые следят за новыми файлами в папке "upload"
- когда вы получите новый файл, запустите punypng.com для его обработки и поместите вывод в правильную папку с изображениями.