Вопрос:
Я сделал домашнюю страницу для моего брата, доступную здесь:
http://www.daniel-steiger.ch
Он использует Microsoft ASP.NET MVC3 для Linux с моно 3, поверх fastcgi с nginx (плюс мой собственный DNS-сервер).
Теперь я знаю, что это необычное созвездие, но до сих пор все работает отлично.
Тем не менее, я столкнулся с незначительной очень тонкой ошибкой.
Когда в галерее один щелчок на миниатюрном изображении, я хотел отобразить полноразмерное изображение с помощью метода FullImage контроллера галереи на новой вкладке.
Например, этот прямой URL:
http://www.daniel-steiger.ch/gallery/fullimage/001.jpg
В Internet Explorer я получил изображение в виде текста.
Во всех других браузерах отображается сообщение "недопустимое изображение".
Я решил проблему, вызвав изображение через него прямым URL-адресом файла, который отлично работает:
http://www.daniel-steiger.ch/Content/images/gallery/001.jpg?LastWriteTimeUTC=1358694795000
Впоследствии я сообщил об ошибке в списке моно-рассылки
http://mono.1490590.n4.nabble.com/Bug-in-mono-3-0-1-MVC3-File-FileResult-td4658382.html
Теперь я получил ответ, что это все моя вина, потому что я установил неправильный тип mime изображения, который/был прав.
Тем не менее, мне было странно, что если бы это было так, то тот же самый код отлично работает в Windows, а смарт-браузеры, такие как Chrome, обычно обнаруживают неправильный параметр mime и используют правильный.
Итак, я изменил тип mime с "image/jpg" на "image/jpeg" и перенастроил проект на сервер.
Я также проверил с файловой утилитой, если изображение на самом деле является jpeg-изображением, и оно есть.
Странно, что он все еще не показывает изображение.
В Internet Explorer я теперь "недоступен".
Во всех других браузерах я получаю: изображение невозможно отобразить, потому что оно содержит ошибки.
Теперь я сделал wget изображение с URL-адреса, где изображение содержит ошибки.
wget http://www.daniel-steiger.ch/gallery/fullimage/001.jpg
Затем я проверил двоичное сравнение между недопустимым и исходным файлом:
cmp -l 001.jpg 001a.jpg | awk '{printf "%08X %02X %02X\n", $1, strtonum(0$2), strtonum(0$3)}' >> comparison.txt
И это результат сравнения:
Что бросается в глаза, так это то, что изображение, которое интернет-исследователь говорит, что он не может найти, на самом деле имеет размер 1,7 МБ и содержит дополнительные байты:
31 39 36 62 36 38 0D 0A
в начале...
У кого-нибудь есть идея, что здесь происходит неправильно или откуда могут исходить эти байты (кроме того, что это скорее всего из-за ошибки в mono/fastcgi)?
Это новый код контроллера btw:
namespace Homepage.Controllers
{
public class GalleryController : Controller
{
protected static string GetImageDirectory()
{
string bd = AppDomain.CurrentDomain.BaseDirectory;
string strImageDirectory = System.IO.Path.Combine(bd,
"Content");
strImageDirectory =
System.IO.Path.Combine(strImageDirectory, "images");
strImageDirectory =
System.IO.Path.Combine(strImageDirectory, "gallery");
return strImageDirectory;
} // End Function GetImageDirectory
protected static string strImageDirectory = GetImageDirectory();
public FileResult FullImage(string id)
{
string strFileName =
System.IO.Path.Combine(strImageDirectory, id);
//return new FilePathResult("CorrectFullPathAndFileName", "CorrectMime");
//return File(strFileName, "image/jpg"); // Old
return File(strFileName, "image/jpeg"); // New
} // End Action FullImage
public FileResult Thumb(string id)
{
//return Redirect(id);
string strFileName =
System.IO.Path.Combine(strImageDirectory, id);
System.IO.Stream ms =
Tools.Imaging.GetThumbnailStream(strFileName,
System.Drawing.Imaging.ImageFormat.Png);
return File(ms, "image/png");
/*
using (System.IO.Stream ms =
Tools.Imaging.GetThumbnailStream(strFileName,
System.Drawing.Imaging.ImageFormat.Png))
{
return File(ms, "image/png");
}*/
} // End Action Thumb
} // End Class GalleryController : Controller
} // End Namespace Homepage.Controllers
Изменить:
он становится незнакомцем:
Существует также дополнительная последовательность с
0d 0a 0d 0a 30 0d 0a 0d 0a
в конце...
Я просто сделал hexdump и нашел, что исходный файл имеет размер файла (задерживает дыхание):
00196b68
Здесь hexdumps (по 8 MB каждый):
Канонический формат (hexdump -C 001.jpg > 001.txt):
Исходный файл: http://www.daniel-steiger.ch/001.txt
Загруженный файл: http://www.daniel-steiger.ch/001a.txt
Чистый дамп (hexdump 001.jpg > 001_1.txt):
Исходный файл: http://www.daniel-steiger.ch/001_1.txt
Загруженный файл: http://www.daniel-steiger.ch/001a_1.txt
Хммм, шестнадцатеричный дамп для поврежденных файлов - 5 МБ, для оригинала - 8,2 МБ...
Я использую последний стабильный nginx:
sudo -s
nginx=stable # use nginx=development for latest development version
add-apt-repository ppa:nginx/$nginx
apt-get update
apt-get install nginx
Полный код для Tools.Imaging(переименовал Tools to MvcTools тем временем, чтобы соответствовать пространству имен сборки)
using System;
using System.Text;
namespace MvcTools
{
public class Imaging
{
//public static System.Drawing.Size m_sMaxThumbNailDimensions = new System.Drawing.Size(200, 200);
public static System.Drawing.Size m_sMaxThumbNailDimensions = new System.Drawing.Size(300, 300);
public static System.IO.Stream GetImageAsStream(
string strOrgFileName
, System.Drawing.Imaging.ImageFormat ifOutputFormat
)
{
return GetImageAsStream(strOrgFileName, ifOutputFormat, 1024);
} // End Function GetImage
public static System.IO.Stream GetImageAsStream(
string strOrgFileName
,System.Drawing.Imaging.ImageFormat ifOutputFormat
,int rez
)
{
System.IO.MemoryStream ms = null;
if (!System.IO.File.Exists(strOrgFileName))
throw new System.IO.FileNotFoundException(strOrgFileName);
try
{
using (System.Drawing.Image imgSourceImage = System.Drawing.Image.FromFile(strOrgFileName))
{
ms = new System.IO.MemoryStream();
imgSourceImage.Save(ms, ifOutputFormat);
ms.Position = 0;
} // End Using imgSourceImage
} // End Try
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.GetType().ToString());
System.Windows.Forms.MessageBox.Show(ex.Message);
//Response.Write(ex.Message);
} // End Catch
return ms;
} // End Function GetImageAsStream
public static System.Drawing.Size GetThumbnailSize(string strOrgFileName)
{
System.Drawing.Size sThumbNailSizeToUse = new System.Drawing.Size();
try
{
using (System.Drawing.Image imgSourceImage = System.Drawing.Image.FromFile(strOrgFileName))
{
decimal decPixToSubstract = 0;
decimal decPercentage;
if (m_sMaxThumbNailDimensions.Width < imgSourceImage.Size.Width || m_sMaxThumbNailDimensions.Height < imgSourceImage.Size.Height)
{
if (imgSourceImage.Size.Width > imgSourceImage.Size.Height)
{
decPercentage = (((decimal)imgSourceImage.Size.Width - (decimal)m_sMaxThumbNailDimensions.Width) / (decimal)imgSourceImage.Size.Width);
decPixToSubstract = decPercentage * imgSourceImage.Size.Height;
sThumbNailSizeToUse.Width = m_sMaxThumbNailDimensions.Width;
sThumbNailSizeToUse.Height = imgSourceImage.Size.Height - (int)decPixToSubstract;
} // End if (imgSourceImage.Size.Width > imgSourceImage.Size.Height)
else
{
decPercentage = (((decimal)imgSourceImage.Size.Height - (decimal)m_sMaxThumbNailDimensions.Height) / (decimal)imgSourceImage.Size.Height);
decPixToSubstract = decPercentage * (decimal)imgSourceImage.Size.Width;
sThumbNailSizeToUse.Height = m_sMaxThumbNailDimensions.Height;
sThumbNailSizeToUse.Width = imgSourceImage.Size.Width - (int)decPixToSubstract;
} // End else of if (imgSourceImage.Size.Width > imgSourceImage.Size.Height)
} // End if (m_sMaxThumbNailDimensions.Width < imgSourceImage.Size.Width || m_sMaxThumbNailDimensions.Height < imgSourceImage.Size.Height)
else
{
sThumbNailSizeToUse.Width = imgSourceImage.Size.Width;
sThumbNailSizeToUse.Height = imgSourceImage.Size.Height;
} // End else of if (m_sMaxThumbNailDimensions.Width < imgSourceImage.Size.Width || m_sMaxThumbNailDimensions.Height < imgSourceImage.Size.Height)
} // End Using imgSourceImage
} // End Try
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
//Response.Write(ex.Message);
} // End Catch
return sThumbNailSizeToUse;
} // End Sub GetThumbnailSize(string strOrgFileName)
// http://stackoverflow.com/info/7319842/mvc3-razor-thumbnail-resize-image-ideas
// http://stackoverflow.com/info/1528525/alternatives-to-system-drawing-for-use-with-asp-net/1528908#1528908
public static void GenerateThumbnailFile(
string strPhysicalPath,
string strOrgFileName, string strThumbnailFileName,
System.Drawing.Imaging.ImageFormat ifOutputFormat, int rez
)
{
try
{
using (System.Drawing.Image imgSourceImage = System.Drawing.Image.FromFile(strOrgFileName))
{
//System.Drawing.Image oImg = System.Drawing.Image.FromStream(fil.InputStream);
decimal decPixToSubstract = 0;
decimal decPercentage;
//default
System.Drawing.Size sThumbNailSizeToUse = new System.Drawing.Size();
if (m_sMaxThumbNailDimensions.Width < imgSourceImage.Size.Width || m_sMaxThumbNailDimensions.Height < imgSourceImage.Size.Height)
{
if (imgSourceImage.Size.Width > imgSourceImage.Size.Height)
{
decPercentage = (((decimal)imgSourceImage.Size.Width - (decimal)m_sMaxThumbNailDimensions.Width) / (decimal)imgSourceImage.Size.Width);
decPixToSubstract = decPercentage * imgSourceImage.Size.Height;
sThumbNailSizeToUse.Width = m_sMaxThumbNailDimensions.Width;
sThumbNailSizeToUse.Height = imgSourceImage.Size.Height - (int)decPixToSubstract;
} // End if (imgSourceImage.Size.Width > imgSourceImage.Size.Height)
else
{
decPercentage = (((decimal)imgSourceImage.Size.Height - (decimal)m_sMaxThumbNailDimensions.Height) / (decimal)imgSourceImage.Size.Height);
decPixToSubstract = decPercentage * (decimal)imgSourceImage.Size.Width;
sThumbNailSizeToUse.Height = m_sMaxThumbNailDimensions.Height;
sThumbNailSizeToUse.Width = imgSourceImage.Size.Width - (int)decPixToSubstract;
} // End else of if (imgSourceImage.Size.Width > imgSourceImage.Size.Height)
} // End if (m_sMaxThumbNailDimensions.Width < imgSourceImage.Size.Width || m_sMaxThumbNailDimensions.Height < imgSourceImage.Size.Height)
else
{
sThumbNailSizeToUse.Width = imgSourceImage.Size.Width;
sThumbNailSizeToUse.Height = imgSourceImage.Size.Height;
} // End else of if (m_sMaxThumbNailDimensions.Width < imgSourceImage.Size.Width || m_sMaxThumbNailDimensions.Height < imgSourceImage.Size.Height)
using (System.Drawing.Bitmap bmpThumbnail = new System.Drawing.Bitmap(sThumbNailSizeToUse.Width, sThumbNailSizeToUse.Height))
{
bmpThumbnail.SetResolution(rez, rez);
using (System.Drawing.Image imgThumbNail = bmpThumbnail)
{
using (System.Drawing.Graphics gGraphicsContext = System.Drawing.Graphics.FromImage(imgThumbNail))
{
gGraphicsContext.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
gGraphicsContext.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
gGraphicsContext.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
System.Drawing.Rectangle rThumbnailDimension = new System.Drawing.Rectangle(0, 0, sThumbNailSizeToUse.Width, sThumbNailSizeToUse.Height);
gGraphicsContext.DrawImage(imgSourceImage, rThumbnailDimension);
} // End Using gGraphicsContext
imgThumbNail.Save(System.IO.Path.Combine(strPhysicalPath, strThumbnailFileName), ifOutputFormat);
} // End Using imgThumbNail
} // End Using bmpThumbnail
} // End Using imgSourceImage
} // End Try
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
//Response.Write(ex.Message);
} // End Catch
} // End Function GenerateThumbNail
public static System.IO.Stream GetThumbnailStream(
string strOrgFileName
, System.Drawing.Imaging.ImageFormat ifOutputFormat
)
{
return GetThumbnailStream(strOrgFileName, ifOutputFormat, 1024);
} // End Function GetThumbnailStream
public static System.IO.Stream GetThumbnailStream(
string strOrgFileName
,System.Drawing.Imaging.ImageFormat ifOutputFormat
,int rez
)
{
System.IO.MemoryStream ms = null;
try
{
using (System.Drawing.Image imgSourceImage = System.Drawing.Image.FromFile(strOrgFileName))
{
decimal decPixToSubstract = 0;
decimal decPercentage;
System.Drawing.Size sThumbNailSizeToUse = new System.Drawing.Size();
if (m_sMaxThumbNailDimensions.Width < imgSourceImage.Size.Width || m_sMaxThumbNailDimensions.Height < imgSourceImage.Size.Height)
{
if (imgSourceImage.Size.Width > imgSourceImage.Size.Height)
{
decPercentage = (((decimal)imgSourceImage.Size.Width - (decimal)m_sMaxThumbNailDimensions.Width) / (decimal)imgSourceImage.Size.Width);
decPixToSubstract = decPercentage * imgSourceImage.Size.Height;
sThumbNailSizeToUse.Width = m_sMaxThumbNailDimensions.Width;
sThumbNailSizeToUse.Height = imgSourceImage.Size.Height - (int)decPixToSubstract;
} // End if (imgSourceImage.Size.Width > imgSourceImage.Size.Height)
else
{
decPercentage = (((decimal)imgSourceImage.Size.Height - (decimal)m_sMaxThumbNailDimensions.Height) / (decimal)imgSourceImage.Size.Height);
decPixToSubstract = decPercentage * (decimal)imgSourceImage.Size.Width;
sThumbNailSizeToUse.Height = m_sMaxThumbNailDimensions.Height;
sThumbNailSizeToUse.Width = imgSourceImage.Size.Width - (int)decPixToSubstract;
} // End else of if (imgSourceImage.Size.Width > imgSourceImage.Size.Height)
} // End if (m_sMaxThumbNailDimensions.Width < imgSourceImage.Size.Width || m_sMaxThumbNailDimensions.Height < imgSourceImage.Size.Height)
else
{
sThumbNailSizeToUse.Width = imgSourceImage.Size.Width;
sThumbNailSizeToUse.Height = imgSourceImage.Size.Height;
} // End else of if (m_sMaxThumbNailDimensions.Width < imgSourceImage.Size.Width || m_sMaxThumbNailDimensions.Height < imgSourceImage.Size.Height)
using (System.Drawing.Bitmap bmpThumbnail = new System.Drawing.Bitmap(sThumbNailSizeToUse.Width, sThumbNailSizeToUse.Height))
{
bmpThumbnail.SetResolution(rez, rez);
using (System.Drawing.Image imgThumbNail = bmpThumbnail)
{
using (System.Drawing.Graphics gGraphicsContext = System.Drawing.Graphics.FromImage(imgThumbNail))
{
gGraphicsContext.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
gGraphicsContext.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
gGraphicsContext.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
System.Drawing.Rectangle rThumbnailDimension = new System.Drawing.Rectangle(0, 0, sThumbNailSizeToUse.Width, sThumbNailSizeToUse.Height);
gGraphicsContext.DrawImage(imgSourceImage, rThumbnailDimension);
ms = new System.IO.MemoryStream();
imgThumbNail.Save(ms, ifOutputFormat);
ms.Position = 0;
} // End Using gGraphicsContext
} // End Using imgThumbNail
} // End Using bmpThumbnail
/*
byte[] buffer = null;
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
{
imgThumbNail.Save(ms, ifOutputFormat);
buffer = ms.ToArray();
}
*/
// Exerts from Page_Load method
//Response.ContentType = "image/" + extension;
//Response.OutputStream.Write(pBuffer, 0, pBuffer.Length);
//Response.End();
//imgThumbNail.Save(System.IO.Path.Combine(strPhysicalPath, strThumbnailFileName), ifOutputFormat);
} // End Using imgSourceImage
} // End Try
catch (Exception ex)
{
//Console.WriteLine(ex.Message);
System.Windows.Forms.MessageBox.Show(ex.Message);
//Response.Write(ex.Message);
} // End Catch
//System.Windows.Forms.MessageBox.Show("image/" + ifOutputFormat.ToString().ToLower());
return ms;
} // End Function GenerateThumbNail
} // End Class Imaging
} // End Namespace Tools