Изменение размера изображения обрезает изображение на один пиксель справа и снизу

Asked
Viewd2215

4

Я обнаружил, что при изменении размера изображения с помощью класса System.Drawing.Graphics в результирующем изображении пропущен один пиксель от правой и нижней границ. Это ошибка где-то в моем коде или проблема .Net? Тестовый код:

 public static void Resize(string imagePath,int width) {
  InterpolationMode[] interpolationModes = new InterpolationMode[]{InterpolationMode.Bicubic, InterpolationMode.Bilinear, InterpolationMode.Default, InterpolationMode.High,
    InterpolationMode.HighQualityBicubic, InterpolationMode.HighQualityBilinear, InterpolationMode.Low, InterpolationMode.NearestNeighbor};
  SmoothingMode[] smoothingModes = new SmoothingMode[]{SmoothingMode.AntiAlias, SmoothingMode.Default, SmoothingMode.HighQuality, SmoothingMode.HighSpeed,
    SmoothingMode.None};

  for(int i = 0; i < interpolationModes.Length; i++) {
    for(int j = 0; j < smoothingModes.Length; j++) {
      Resize(imagePath, width, interpolationModes[i], smoothingModes[j]);
    }
  }
}


public static void Resize(string imagePath,int width, InterpolationMode interpolationMode, SmoothingMode smoothingMode) {
  Image imgPhoto = Image.FromFile(imagePath);
  float percent = (float)width / (float)imgPhoto.Width;
  int height = (int)(imgPhoto.Height * percent);

  Bitmap bmPhoto = new Bitmap(width, height, PixelFormat.Format24bppRgb);
  bmPhoto.SetResolution(imgPhoto.HorizontalResolution, imgPhoto.VerticalResolution);

  Graphics grPhoto = Graphics.FromImage(bmPhoto);
  grPhoto.InterpolationMode = interpolationMode;
  grPhoto.SmoothingMode = smoothingMode;

  grPhoto.DrawImage(imgPhoto,
  new Rectangle(0, 0, width, height),
  new Rectangle(0, 0, imgPhoto.Width, imgPhoto.Height ),
  GraphicsUnit.Pixel);

  grPhoto.Dispose();

  string fileName = Path.GetFileName(imagePath);
  string path = Path.GetDirectoryName(imagePath)+"\resized";

  if (!Directory.Exists(path))
    Directory.CreateDirectory(path);

  bmPhoto.Save(String.Format("{0}\{1}_{2}_{3}", path, interpolationMode.ToString(), smoothingMode.ToString(),fileName));
}
 

Исходное изображение: Исходное изображение http://img110.imageshack.us/img110/4876/sampleaa2.jpg а>

Результат: Результат http://img110.imageshack.us/img110/2050/resizedsamplesy4.pngа>

P.S. Я перепробовал все существующие комбинации InterpolationMode и SmoothingMode. Ни один из них не дал приемлемого результата.

5 ответов

2

Это ошибка графики .NET, и она очень раздражает. Это не ошибка округления или проблема алгоритма. Вы можете увидеть вариант той же проблемы, если вы создадите растровое изображение 100x100, а затем вызовете DrawRectangle, используя прямоугольник 100x100 в качестве одного из параметров: вы не увидите нижнюю или правую сторону нарисованного прямоугольника.

0

Учитывая, что процент, на который вы выполняете масштабирование, не всегда дает интегральный результат, это приведет к ошибке округления, которая приведет к появлению границы.

Вам нужно будет определить, добавит ли округление в каком-либо измерении границу в пикселях (вы можете проверить округление). Если да, то вы можете создать новое растровое изображение, а затем скопировать часть изображения поверх, не включающую границу.

  • Sadly, but this is not a problem of percentage. You could try any height and width(add or subtract any number of pixels after applying percentage) but result will be the same.

    Michael Baranov22 января 2009, 07:44
  • Я не думал об округлении. Отлично!

    strager21 января 2009, 19:49
1

Это произойдет, если ширина вашей линии в оригинале составляет всего 1 пиксель. Когда он изменяет размер, алгоритм заставляет границу справа и снизу казаться «обрезанной», тогда как на самом деле происходит то, что алгоритм придает степень важности, основанную на оттенке / цвете / насыщенности / размещении пикселя. Считается, что внутренние ячейки имеют приоритет и граница теряется. Различные графические приложения, такие как Adobe Photoshop и Corel PaintShop Pro, предоставляют вам различные варианты изменения размера [режимы интерполяции], чтобы избежать подобных вещей. Вам нужно изменить режим interpolationMode на другой. Я давно не использовал GDI +, поэтому забыл, какие есть доступные режимы. Попробуйте каждый из режимов, чтобы выбрать наиболее подходящий для вас.

Скорее всего, я бы сделал следующее, чтобы гарантировать целостность границы:

  • Снимите границу с исходного изображения.
  • Измените размер оставшейся части изображения.
  • Добавьте границу к получившемуся изображению.

Таким образом, ваша граница останется неизменной - единственный красный пиксель, окружающий измененное изображение.

  • It’s not a problem of the border- it’s question how to save this one pixel from right and bottom edges. In you approach on last step I’ll have border(with original size) and rest of image(already scaled). To Add border back I should scale it to the size of image and this is vicious circle :-(

    Michael Baranov22 января 2009, 07:52