123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- using PaintDotNet.SystemLayer;
- using System;
- using System.Drawing;
- using System.Drawing.Imaging;
- using System.IO;
- using System.Text;
- namespace PaintDotNet
- {
- public abstract class InternalFileType : FileType
- {
- /// <summary>
- /// The actual bit-depths we can save with.
- /// </summary>
- internal enum SavableBitDepths
- {
- Rgba32, // 2^24 colors, plus a full 8-bit alpha channel
- Rgb24, // 2^24 colors
- Rgb8, // 256 colors
- Rgba8 // 255 colors + 1 transparent
- }
- protected unsafe void SquishSurfaceTo24Bpp(Surface surface)
- {
- byte* dst = (byte*)surface.GetRowAddress(0);
- int byteWidth = surface.Width * 3;
- int stride24bpp = ((byteWidth + 3) / 4) * 4; // round up to multiple of 4
- int delta = stride24bpp - byteWidth;
- for (int y = 0; y < surface.Height; ++y)
- {
- ColorBgra* src = surface.GetRowAddress(y);
- ColorBgra* srcEnd = src + surface.Width;
- while (src < srcEnd)
- {
- dst[0] = src->B;
- dst[1] = src->G;
- dst[2] = src->R;
- ++src;
- dst += 3;
- }
- dst += delta;
- }
- return;
- }
- private string PrintSet<T>(Set<T> set)
- {
- StringBuilder sb = new StringBuilder();
- bool first = true;
- foreach (T item in set)
- {
- if (!first)
- {
- sb.Append(", ");
- }
- first = false;
- sb.Append(item.ToString());
- }
- string sbTS = sb.ToString();
- return sbTS;
- }
- internal SavableBitDepths ChooseBitDepth(
- Set<SavableBitDepths> allowedBitDepths,
- Set<SavableBitDepths> losslessBitDepths,
- bool allOpaque,
- bool all0Or255Alpha,
- int uniqueColorCount)
- {
- if (allowedBitDepths.Count == 0)
- {
- throw new ArgumentException("Count must be 1 or more", "allowedBitDepths");
- }
- Tracing.Ping("allowedBitDepths = " + PrintSet(allowedBitDepths));
- Tracing.Ping("losslessBitDepths = " + PrintSet(losslessBitDepths));
- if (allowedBitDepths.Count == 1)
- {
- return allowedBitDepths.ToArray()[0];
- }
- // allowedBitDepths.Count >= 2
- Set<SavableBitDepths> bestBitDepths = Set<SavableBitDepths>.Intersect(allowedBitDepths, losslessBitDepths);
- if (bestBitDepths.Count == 1)
- {
- return bestBitDepths.ToArray()[0];
- }
- Set<SavableBitDepths> candidates;
- if (bestBitDepths.Count == 0)
- {
- candidates = allowedBitDepths;
- }
- else
- {
- candidates = bestBitDepths;
- }
- // candidates.Count >= 2
- // lossless choices
- if (candidates.Contains(SavableBitDepths.Rgba8) && all0Or255Alpha && uniqueColorCount <= 255)
- {
- return SavableBitDepths.Rgba8;
- }
- if (candidates.Contains(SavableBitDepths.Rgb8) && allOpaque && uniqueColorCount <= 256)
- {
- return SavableBitDepths.Rgb8;
- }
- if (candidates.Contains(SavableBitDepths.Rgb24) && allOpaque)
- {
- return SavableBitDepths.Rgb24;
- }
- if (candidates.Contains(SavableBitDepths.Rgba32))
- {
- return SavableBitDepths.Rgba32;
- }
- // forced choices -- we wanted Rgba32 but it was not allowed
- if (candidates.IsEqualTo(Set.Create(SavableBitDepths.Rgb8, SavableBitDepths.Rgb24)))
- {
- return SavableBitDepths.Rgb24;
- }
- if (candidates.IsEqualTo(Set.Create(SavableBitDepths.Rgb8, SavableBitDepths.Rgba8)))
- {
- return SavableBitDepths.Rgba8;
- }
- if (candidates.IsEqualTo(Set.Create(SavableBitDepths.Rgba8, SavableBitDepths.Rgb24)))
- {
- return SavableBitDepths.Rgb24;
- }
- throw new ArgumentException("Could not accomodate input values -- internal error?");
- }
- protected unsafe Bitmap CreateAliased24BppBitmap(Surface surface)
- {
- int stride = surface.Width * 3;
- int realStride = ((stride + 3) / 4) * 4; // round up to multiple of 4
- return new Bitmap(surface.Width, surface.Height, realStride, PixelFormat.Format24bppRgb, new IntPtr(surface.Scan0.VoidStar));
- }
- private unsafe void Analyze(Surface scratchSurface, out bool allOpaque, out bool all0or255Alpha, out int uniqueColorCount)
- {
- allOpaque = true;
- all0or255Alpha = true;
- Set<ColorBgra> uniqueColors = new Set<ColorBgra>();
- for (int y = 0; y < scratchSurface.Height; ++y)
- {
- ColorBgra* srcPtr = scratchSurface.GetRowAddress(y);
- ColorBgra* endPtr = srcPtr + scratchSurface.Width;
- while (srcPtr < endPtr)
- {
- ColorBgra p = *srcPtr;
- if (p.A != 255)
- {
- allOpaque = false;
- }
- if (p.A > 0 && p.A < 255)
- {
- all0or255Alpha = false;
- }
- if (p.A == 255 && !uniqueColors.Contains(p) && uniqueColors.Count < 300)
- {
- uniqueColors.Add(*srcPtr);
- }
- ++srcPtr;
- }
- }
- uniqueColorCount = uniqueColors.Count;
- }
- internal InternalFileType(string name, FileTypeFlags flags, string[] extensions)
- : base(name, flags, extensions)
- {
- }
- }
- }
|