Domanda

Qualcuno ha la formula segreta per ridimensionare le immagini trasparenti (principalmente GIF) senza QUALSIASI perdita di qualità: cosa mai?

Ho provato un sacco di cose, il più vicino che ottengo non è abbastanza buono.

Dai un'occhiata alla mia immagine principale:

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

E poi l'immagine in scala:

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);
  }
}

Sto utilizzando il codice sopra riportato per eseguire il ridimensionamento indicizzato.

Qualcuno ha idee di miglioramento?

È stato utile?

Soluzione

Se non è necessario preservare il tipo di file dopo il ridimensionamento, consiglierei il seguente approccio.

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);
}

Il risultato avrà bordi anti-alias davvero belli

  • rimossa l'immagine della baracca che era stata sostituita da una pubblicità

Se devi esportare l'immagine in gif sei a posto;GDI+ non funziona bene con GIF.Vedere questo post del blog a riguardo per ulteriori informazioni

Modificare: Ho dimenticato di eliminare le bitmap nell'esempio;è stato corretto

Altri suggerimenti

Questa è una funzione di ridimensionamento di base che ho utilizzato per alcune delle mie applicazioni che sfrutta GDI+

/// <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; 
}

Non ricordo assolutamente se funzionerà con le GIF, ma puoi provarlo.

Nota:Non posso prendermi tutto il merito di questa funzione.Ho messo insieme alcune cose da altri campioni online e l'ho fatto funzionare in base alle mie esigenze 8^D

Penso che il problema sia che stai eseguendo un ridimensionamento basato sulla linea di scansione, che porterà a frastagliature, non importa quanto lo modifichi.Una buona qualità di ridimensionamento dell'immagine richiede che tu faccia un po' più di lavoro per capire il colore medio dei pixel pre-ridimensionati che copre il pixel ridimensionato.

Il ragazzo che gestisce questo sito Web ha un post sul blog in cui discute alcuni algoritmi di ridimensionamento delle immagini.Probabilmente desideri un algoritmo di ridimensionamento delle immagini bicubico.

Migliore ridimensionamento delle immagini

Per chiunque stia tentando di utilizzare la soluzione di Markus Olsson per ridimensionare dinamicamente le immagini e scriverle nel flusso di risposta.

Questo non funzionerà:

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

Ma questo:

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

    stream.WriteTo( Response.OutputStream );
}

Sebbene PNG sia decisamente migliore di GIF, occasionalmente è necessario mantenere il formato GIF.

Con GIF o PNG a 8 bit devi affrontare il problema della quantizzazione.

La quantizzazione è il punto in cui scegli quali 256 (o meno) colori conserveranno e rappresenteranno meglio l'immagine, quindi trasformerai nuovamente i valori RGB in indici.Quando esegui un'operazione di ridimensionamento, la tavolozza dei colori ideale cambia, mentre mescoli i colori e modifichi i bilanciamenti.

Per ridimensionamenti leggeri, come il 10-30%, potresti essere d'accordo nel preservare la tavolozza dei colori originale.

Tuttavia, nella maggior parte dei casi dovrai riquantizzare.

I due algoritmi principali tra cui scegliere sono Octree e nQuant.Octree è molto veloce e fa un ottimo lavoro, soprattutto se puoi sovrapporre un algoritmo di dithering intelligente.nQuant richiede almeno 80 MB di RAM per eseguire una codifica (crea un istogramma completo) ed è in genere 20-30 volte più lento (1-5 secondi per codifica su un'immagine media).Tuttavia, a volte produce una qualità dell'immagine superiore rispetto a Octree poiché non "arrotonda" i valori per mantenere prestazioni costanti.

Quando si implementa il supporto per GIF trasparenti e GIF animate in imageresizing.net progetto, ho scelto Octree.Il supporto della trasparenza non è difficile una volta che hai il controllo della tavolozza delle immagini.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top