Frage

Hat jemand die Geheimformel zur Größenänderung transparenter Bilder (hauptsächlich GIFs)? ohne Irgendwelche Qualitätsverluste – was auch immer?

Ich habe eine Menge Sachen ausprobiert, aber das, was mir am nächsten kommt, ist nicht gut genug.

Schauen Sie sich mein Hauptbild an:

http://www.thewallcompany.dk/test/main.gif

Und dann das skalierte Bild:

http://www.thewallcompany.dk/test/ScaledImage.gif

//Internal resize for indexed colored images
void IndexedRezise(int xSize, int ySize)
{
  BitmapData sourceData;
  BitmapData targetData;

  AdjustSizes(ref xSize, ref ySize);

  scaledBitmap = new Bitmap(xSize, ySize, bitmap.PixelFormat);
  scaledBitmap.Palette = bitmap.Palette;
  sourceData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
    ImageLockMode.ReadOnly, bitmap.PixelFormat);
  try
  {
    targetData = scaledBitmap.LockBits(new Rectangle(0, 0, xSize, ySize),
      ImageLockMode.WriteOnly, scaledBitmap.PixelFormat);
    try
    {
      xFactor = (Double)bitmap.Width / (Double)scaledBitmap.Width;
      yFactor = (Double)bitmap.Height / (Double)scaledBitmap.Height;
      sourceStride = sourceData.Stride;
      sourceScan0 = sourceData.Scan0;
      int targetStride = targetData.Stride;
      System.IntPtr targetScan0 = targetData.Scan0;
      unsafe
      {
        byte* p = (byte*)(void*)targetScan0;
        int nOffset = targetStride - scaledBitmap.Width;
        int nWidth = scaledBitmap.Width;
        for (int y = 0; y < scaledBitmap.Height; ++y)
        {
          for (int x = 0; x < nWidth; ++x)
          {
            p[0] = GetSourceByteAt(x, y);
            ++p;
          }
          p += nOffset;
        }
      }
    }
    finally
    {
      scaledBitmap.UnlockBits(targetData);
    }
  }
  finally
  {
    bitmap.UnlockBits(sourceData);
  }
}

Ich verwende den obigen Code, um die indizierte Größenänderung durchzuführen.

Hat jemand Verbesserungsvorschläge?

War es hilfreich?

Lösung

Wenn nach der Skalierung keine Anforderung besteht, den Dateityp beizubehalten, würde ich den folgenden Ansatz empfehlen.

using (Image src = Image.FromFile("main.gif"))
using (Bitmap dst = new Bitmap(100, 129))
using (Graphics g = Graphics.FromImage(dst))
{
   g.SmoothingMode = SmoothingMode.AntiAlias;
   g.InterpolationMode = InterpolationMode.HighQualityBicubic;
   g.DrawImage(src, 0, 0, dst.Width, dst.Height);
   dst.Save("scale.png", ImageFormat.Png);
}

Das Ergebnis werden wirklich schöne Anti-Aliasing-Kanten sein

  • Image Shack-Bild entfernt, das durch eine Anzeige ersetzt wurde

Wenn Sie das Bild als GIF exportieren müssen, sind Sie auf der sicheren Seite.GDI+ funktioniert nicht gut mit GIF.Sehen dieser Blogbeitrag Weitere Informationen finden Sie hier

Bearbeiten: Ich habe vergessen, die Bitmaps im Beispiel zu entsorgen;es wurde korrigiert

Andere Tipps

Dies ist eine grundlegende Größenänderungsfunktion, die ich für einige meiner Anwendungen verwendet habe und die GDI+ nutzt

/// <summary>
///    Resize image with GDI+ so that image is nice and clear with required size.
/// </summary>
/// <param name="SourceImage">Image to resize</param>
/// <param name="NewHeight">New height to resize to.</param>
/// <param name="NewWidth">New width to resize to.</param>
/// <returns>Image object resized to new dimensions.</returns>
/// <remarks></remarks>
public static Image ImageResize(Image SourceImage, Int32 NewHeight, Int32 NewWidth)
{
   System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(NewWidth, NewHeight, SourceImage.PixelFormat);

   if (bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Format1bppIndexed | bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Format4bppIndexed | bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Format8bppIndexed | bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Undefined | bitmap.PixelFormat == Drawing.Imaging.PixelFormat.DontCare | bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Format16bppArgb1555 | bitmap.PixelFormat == Drawing.Imaging.PixelFormat.Format16bppGrayScale) 
   {
      throw new NotSupportedException("Pixel format of the image is not supported.");
   }

   System.Drawing.Graphics graphicsImage = System.Drawing.Graphics.FromImage(bitmap);

   graphicsImage.SmoothingMode = Drawing.Drawing2D.SmoothingMode.HighQuality;
   graphicsImage.InterpolationMode = Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
   graphicsImage.DrawImage(SourceImage, 0, 0, bitmap.Width, bitmap.Height);
   graphicsImage.Dispose();
   return bitmap; 
}

Ich weiß nicht mehr genau, ob es mit GIFs funktionieren wird, aber Sie können es versuchen.

Notiz:Ich kann diese Funktion nicht in vollem Umfang anerkennen.Ich habe ein paar Dinge aus einigen anderen Beispielen online zusammengestellt und es an meine Bedürfnisse angepasst 8^D

Ich denke, das Problem besteht darin, dass Sie eine auf der Scanlinie basierende Größenänderung durchführen, die zu Unebenheiten führt, egal wie stark Sie sie anpassen.Für eine gute Bildgrößenänderungsqualität müssen Sie etwas mehr Arbeit leisten, um die durchschnittliche Farbe der vorab verkleinerten Pixel zu ermitteln, die Ihr verkleinertes Pixel abdeckt.

Der Betreiber dieser Website hat einen Blogbeitrag veröffentlicht, in dem einige Algorithmen zur Bildgrößenänderung besprochen werden.Sie möchten wahrscheinlich einen bikubischen Bildskalierungsalgorithmus.

Bessere Bildgrößenänderung

Für alle, die möglicherweise versuchen, die Lösung von Markus Olsson zu verwenden, um die Größe von Bildern dynamisch zu ändern und sie in den Response Stream zu schreiben.

Das wird nicht funktionieren:

Response.ContentType = "image/png";
dst.Save( Response.OutputStream, ImageFormat.Png );

Aber das wird:

Response.ContentType = "image/png";
using (MemoryStream stream = new MemoryStream())
{
    dst.Save( stream, ImageFormat.Png );

    stream.WriteTo( Response.OutputStream );
}

Obwohl PNG definitiv besser ist als GIF, gibt es gelegentlich einen Anwendungsfall, bei dem das GIF-Format beibehalten werden muss.

Bei GIF oder 8-Bit-PNG müssen Sie sich mit dem Problem der Quantisierung befassen.

Bei der Quantisierung wählen Sie aus, welche 256 (oder weniger) Farben das Bild am besten erhalten und darstellen, und wandeln die RGB-Werte dann wieder in Indizes um.Wenn Sie einen Größenänderungsvorgang durchführen, ändert sich die ideale Farbpalette, da Sie Farben mischen und die Balance ändern.

Bei geringfügigen Größenänderungen, z. B. 10–30 %, ist es möglicherweise in Ordnung, die ursprüngliche Farbpalette beizubehalten.

In den meisten Fällen müssen Sie jedoch eine Neuquantisierung durchführen.

Die beiden wichtigsten Algorithmen zur Auswahl sind Octree und nQuant.Octree ist sehr schnell und leistet sehr gute Arbeit, insbesondere wenn Sie einen intelligenten Dithering-Algorithmus überlagern können.nQuant benötigt mindestens 80 MB RAM, um eine Kodierung durchzuführen (es erstellt ein vollständiges Histogramm) und ist normalerweise 20–30 Mal langsamer (1–5 Sekunden pro Kodierung bei einem durchschnittlichen Bild).Es erzeugt jedoch manchmal eine höhere Bildqualität als Octree, da die Werte nicht „gerundet“ werden, um eine gleichbleibende Leistung aufrechtzuerhalten.

Bei der Implementierung der Unterstützung für transparentes GIF und animiertes GIF im imageresizing.net Projekt habe ich mich für Octree entschieden.Die Unterstützung von Transparenz ist kein Problem mehr, sobald Sie die Kontrolle über die Bildpalette haben.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top