2013-08-07 4 views
3

У меня есть код, который принимает PNG, который представляет собой изображение в оттенках серого с прозрачностью, и пытается создать новое изображение с заданным фоном (смотрится из базы данных) и накладывает оригинал изображение на нем, чтобы создать изображение требуемого цвета с подсветкой и затенением. Код запускается в контексте ASP.NET, но я не думаю, что это имеет значение.Graphics.DrawImage неожиданно изменяет размер изображения

Код отлично работает на моем локальном компьютере, но когда он развертывается на нашем сервере UAT, он дает неожиданные результаты. На UAT создается изображение нужного размера, но затененная/выделенная область, по-видимому, уменьшилась в каждом измерении на 20%. Таким образом, основным изображением, которое я просматриваю, является первоначально 5x29, а выходное изображение - 5x29, а заштрихованная область - 4x23.2 (24-я строка очень немного отличается, но главным образом цвет фона, поэтому я предположил, что делает интерполяцию с изменением размера).

Мой код, который не удается выглядит следующим образом:

private byte[] GetImageData(CacheKey key) 
{ 
    byte[] imageData; 
    using (Image image = Image.FromFile(key.FilePath)) 
    using (Bitmap newImage = new Bitmap(image.Width, image.Height)) 
    { 
     using (Graphics graphic = Graphics.FromImage(newImage)) 
     { 
      using (SolidBrush brush = new SolidBrush(ColorTranslator.FromHtml(key.BackgroundColour))) 
      { 
       graphic.FillRectangle(brush, 0, 0, image.Width, image.Height); 
      } 
      graphic.DrawImage(image, 0, 0); 

      /* 
      The following lines see if there is a transparency mask to create final 
      transparency. It does this using GetPixel and SetPixel and just modifying 
      the alpha of newImage with the alpha of mask. I don't think this should make a difference but code below anyway. 
      */ 

      Bitmap mask; 
      if (TryGetMask(key.FilePath, out mask)) 
      { 
       ApplyMask(newImage, mask); 
      } 


      using (var memoryStream = new MemoryStream()) 
      { 
       newImage.Save(memoryStream, ImageFormat.Png); 
       imageData = memoryStream.ToArray(); 
      } 
     } 
    } 
    return imageData; 
} 

private void ApplyMask(Bitmap Bitmap, Bitmap mask) 
{ 
    if (mask.Width != Bitmap.Width || mask.Height != Bitmap.Height) 
    { 
     throw new ArgumentException("Bitmap sizes do not match"); 
    } 
    for (int y = 0; y < Bitmap.Height; y++) 
    { 
     for (int x = 0; x < Bitmap.Width; x++) 
     { 
      Color colour = Bitmap.GetPixel(x, y); 
      colour = Color.FromArgb(mask.GetPixel(x, y).A, colour); 
      Bitmap.SetPixel(x, y, colour); 
     } 
    } 
} 

Вот изображения я получаю (повторяется четыре раза, чтобы лучше продемонстрировать этот вопрос). Первое - это правильное изображение, которое я получаю с моего локального компьютера. Второе - это то, что появляется у моего сервера UAT, который демонстрирует странную проблему с «уменьшением на 20%». Они используются аналогично тому, как повторяющийся фон, поэтому вы можете понять, почему эффект настолько заметен. Они были сгенерированы на белом фоне, чтобы облегчить эту проблему. У меня есть похожие изображения в других цветах, если кто-то их хочет. :)

enter image description hereenter image description hereenter image description hereenter image description here

enter image description hereenter image description hereenter image description hereenter image description here

В окончательном разъяснении изображения используются, должны быть идентичными (UAT был развернут от того, что я проверил в наше GIT Repro и там никогда не было более одной версии этих изображений, поэтому он не может использовать неправильную версию.

Я думаю, что, возможно, что GDI делает что-то другое на сервере, чем на моем компьютере, но я не могу думать, что это будет или почему.

Любые объяснения этого поведения или еще исправления были бы наиболее ценными. В противном случае мне придется идти и делать все это вручную пиксель за пикселем, делая прозрачность и накладывая себя, что кажется немного глупым.

ответ

7
graphic.DrawImage(image, 0, 0); 

Это не так уж странно, когда вы используете эту перегрузку DrawImage(). Он попытается отобразить изображение на исходном физическом. На что влияет установка DPI (точек на дюйм) видеоадаптера. Самые распространенные настройки сегодня - 96, 120 и 144 dpi, очень легко изменить с помощью апплета Display в Windows. Эти значения dpi соответствуют 100%, 125% и 150% в апплете.

Если вы хотите убедиться, что этого не происходит, и вы получаете точный размер в пикселях, вам необходимо использовать перегрузку DrawImage (изображение, прямоугольник).

Обратите внимание, что имеет значение физический размер. Если вы когда-либо используете свою программу на мониторе «сетчатки», этот день становится все ближе и ближе, тогда изображение размером 5x29 пикселей будет выглядеть, как пыль на этом приятном дисплее. Создание программ DpiAware игнорировалось в течение последних 30 лет, но это становится очень важным.

+0

А, это имеет смысл. Я думал о DPI, но думал, что с использованием того же образа, что это не может быть проблемой. Я не думал, что он может использовать настройку сервера. Спасибо за указатель. И хотя это звучит как правильный ответ, я подожду, чтобы получить код, развернутый в UAT, и протестировать его до фактического тикания. :) – Chris

+0

Отличное решение. Это сводило меня с ума. –

+0

graphic.DrawImage (изображение, x, y, ширина, высота); –

0

Вы сохранили и сравнили сгенерированные изображения с обеих сторон? Это немного похоже на проблему с 24-битным/32-битным цветом.

Что произойдет, если вы используете этот конструктор:

общественного Bitmap ( ширина ИНТ, INT высота, формат PixelFormat )

using (Bitmap newImage = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppArgb)) 

Как я прочитал замечания по MSDN:

Remarks 
This constructor creates a Bitmap with a PixelFormat enumeration value of Format32bppArgb. 

Это не должно иметь значения.

+0

http://msdn.microsoft.com/en-us/library/vstudio/7we6s1x3(v=vs.100).aspx предполагает, что используемый мной конструктор «создает битмап с значением перечисления PixelFormat Format32bppArgb», поэтому Я не вижу, как может помочь ваша строка кода. Не могли бы вы пояснить, что вы подразумеваете под проблемой 24-битного/32-битного цвета? – Chris

+0

Может быть, серверная платформа не поддерживается? http://msdn.microsoft.com/en-us/library/system.drawing.imaging.imageformat.png.aspx –

1

Возможно, у вас есть проблема с graphics.DpiX и графика.DpiY, проверяет, если оба свойства имеют одинаковые значения в вашем компьютере и на сервере

+0

Похоже, правильная идея, но я думаю, что предложение Ганса просто не полагаться на dpi - это правильный способ идти. :) Спасибо хоть. – Chris

Смежные вопросы