public static int FindMatch(this ColorPalette pal, ARGBPixel pixel) { int bestDist = Int32.MaxValue, bestIndex = 0; for (int i = 0, c = pal.Entries.Length; i < c; i++) { int dist = pixel.DistanceTo(pal.Entries[i]); if (dist < bestDist) { bestIndex = i; if (dist == 0) { break; } bestDist = dist; } } return(bestIndex); }
public static unsafe Bitmap IndexColors(this Bitmap src, ColorPalette palette, PixelFormat format) { int w = src.Width, h = src.Height; int entries = palette.Entries.Length; switch (format) { case PixelFormat.Format4bppIndexed: { entries = Math.Min(entries, 16); break; } case PixelFormat.Format8bppIndexed: { entries = Math.Min(entries, 256); break; } default: { throw new ArgumentException("Pixel format is not an indexed format."); } } Bitmap dst = new Bitmap(w, h, format); dst.Palette = palette; BitmapData sData = src.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); BitmapData dData = dst.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, format); ARGBPixel *sPtr = (ARGBPixel *)sData.Scan0; for (int y = 0; y < h; y++) { byte *dPtr = (byte *)dData.Scan0 + (y * dData.Stride); for (int x = 0; x < w; x++) { ARGBPixel p = *sPtr++; int bestDist = Int32.MaxValue, bestIndex = 0; for (int z = 0; z < entries; z++) { int dist = p.DistanceTo(palette.Entries[z]); if (dist < bestDist) { bestDist = dist; bestIndex = z; } } if (format == PixelFormat.Format4bppIndexed) { byte val = *dPtr; if ((x % 2) == 0) { *dPtr = (byte)((bestIndex << 4) | (val & 0x0F)); } else { *dPtr++ = (byte)((val & 0xF0) | (bestIndex & 0x0F)); } } else { *dPtr++ = (byte)bestIndex; } } } dst.UnlockBits(dData); src.UnlockBits(sData); return(dst); }
public static CMPRBlock Encode(ARGBPixel *block, int width, bool fast) { CMPRBlock p = new CMPRBlock(); uint * pData = stackalloc uint[16]; ARGBPixel *pColor = (ARGBPixel *)pData; bool isSingle = true, hasAlpha = false, allAlpha = true; for (int y = 0, i = 0; y < 4; y++, block += width) { for (int x = 0; x < 4; i++) { pColor[i] = block[x++]; if (pData[i] != pData[0]) { isSingle = false; } if (pColor[i].A < 0x80) { hasAlpha = true; } else { allAlpha = false; } } } /* * Foreach block: * copy block to buffer * mirror remaning colors? * * If block is single color: * run optiml compress? * else * Initialize color set * Compress block using color set * * */ //BlockDecoder decoder = new BlockDecoder(width, 4, 4, 4); //bool isSingle = true, hasAlpha = false, allAlpha = true; //for (int i = 0; i < 16; i++) //{ // int index = decoder[i]; // pColor[i] = block[index]; // if (pData[i] != pData[0]) isSingle = false; // if (pColor[i].A < 0x80) hasAlpha = true; // else allAlpha = false; //} //bool isSingle = true, hasAlpha = false, allAlpha = true; //ARGBPixel* ptr = block; //int index = 0; //for (int y = 0; y < 4; y++, ptr += width - 4) //{ // for (int x = 0; x < 4; x++, ptr++, index++) // { // pColor[index] = block[(y * width) + x]; // if (pData[0] != pData[index]) isSingle = false; // if (pColor[index].A < 0x80) hasAlpha = true; // else allAlpha = false; // } //} //if (allAlpha) //{ // p._root0._data = 0; // p._root1._data = 0xFFFF; // p._lookup = 0xFFFFFFFF; //} //else if (isSingle) //{ // p._root0 = (RGB565Pixel)(*block); // p._root1._data = 0; // p._lookup = 0x00000000; //} //else //{ uint * palData = stackalloc uint[4]; ARGBPixel *palCol = (ARGBPixel *)palData; int bestDist = -1; for (int i = 0; i < 16; i++) { ARGBPixel p1 = pColor[i]; for (int x = i + 1; x < 16; x++) { ARGBPixel p2 = pColor[x]; int d = p1.DistanceTo(p2); if (d > bestDist) { bestDist = d; palCol[2] = p1; palCol[3] = p2; } } } wRGB565Pixel smax = (wRGB565Pixel)palCol[2]; wRGB565Pixel smin = (wRGB565Pixel)palCol[3]; if (smax < smin) { smax = (wRGB565Pixel)palCol[3]; smin = (wRGB565Pixel)palCol[2]; } if (hasAlpha) { p._root0 = smin; p._root1 = smax; palCol[0] = (ARGBPixel)smin; palCol[1] = (ARGBPixel)smax; palCol[2] = new ARGBPixel(255, (byte)((palCol[0].R + palCol[1].R) >> 1), (byte)((palCol[0].G + palCol[1].G) >> 1), (byte)((palCol[0].B + palCol[1].B) >> 1)); palCol[3] = new ARGBPixel(); } else { p._root0 = smax; p._root1 = smin; palCol[0] = (ARGBPixel)smax; palCol[1] = (ARGBPixel)smin; palCol[2] = new ARGBPixel(255, (byte)(((palCol[0].R << 1) + palCol[1].R) / 3), (byte)(((palCol[0].G << 1) + palCol[1].G) / 3), (byte)(((palCol[0].B << 1) + palCol[1].B) / 3)); palCol[3] = new ARGBPixel(255, (byte)(((palCol[1].R << 1) + palCol[0].R) / 3), (byte)(((palCol[1].G << 1) + palCol[0].G) / 3), (byte)(((palCol[1].B << 1) + palCol[0].B) / 3)); } uint indicies = 0; for (int i = 0, shift = 30; i < 16; i++, shift -= 2) { uint index = 3; if (pColor[i].A >= 0x80) { int bd = int.MaxValue; for (int x = 0; x < ((hasAlpha) ? 4 : 3); x++) { int dist = palCol[x].DistanceTo(pColor[i]); if (dist < bd) { bd = dist; index = (uint)x; } } } indicies |= index << shift; } p._lookup = indicies; //p = DXT1Fast.Compress(pColor); //} return(p); }