private static ColorData BuildHistogram(Bitmap sourceImage, int alphaThreshold, int alphaFader) { int bitmapWidth = sourceImage.Width; int bitmapHeight = sourceImage.Height; BitmapData data = sourceImage.LockBits( Rectangle.FromLTRB(0, 0, bitmapWidth, bitmapHeight), ImageLockMode.ReadOnly, sourceImage.PixelFormat); ColorData colorData = new ColorData(MaxSideIndex, bitmapWidth, bitmapHeight); try { var bitDepth = Image.GetPixelFormatSize(sourceImage.PixelFormat); if (bitDepth != 32) { throw new QuantizationException(string.Format("Thie image you are attempting to quantize does not contain a 32 bit ARGB palette. This image has a bit depth of {0} with {1} colors.", bitDepth, sourceImage.Palette.Entries.Length)); } var byteLength = data.Stride < 0 ? -data.Stride : data.Stride; var byteCount = Math.Max(1, bitDepth >> 3); var offset = 0; var buffer = new Byte[byteLength * sourceImage.Height]; var value = new Byte[byteCount]; Marshal.Copy(data.Scan0, buffer, 0, buffer.Length); for (int y = 0; y < bitmapHeight; y++) { var index = 0; for (int x = 0; x < bitmapWidth; x++) { var indexOffset = index >> 3; for (var valueIndex = 0; valueIndex < byteCount; valueIndex++) { value[valueIndex] = buffer[offset + valueIndex + indexOffset]; } var indexAlpha = (byte)((value[Alpha] >> 3) + 1); var indexRed = (byte)((value[Red] >> 3) + 1); var indexGreen = (byte)((value[Green] >> 3) + 1); var indexBlue = (byte)((value[Blue] >> 3) + 1); if (value[Alpha] > alphaThreshold) { if (value[Alpha] < 255) { var alpha = value[Alpha] + (value[Alpha] % alphaFader); value[Alpha] = (byte)(alpha > 255 ? 255 : alpha); indexAlpha = (byte)((value[Alpha] >> 3) + 1); } colorData.Weights[indexAlpha, indexRed, indexGreen, indexBlue]++; colorData.MomentsRed[indexAlpha, indexRed, indexGreen, indexBlue] += value[Red]; colorData.MomentsGreen[indexAlpha, indexRed, indexGreen, indexBlue] += value[Green]; colorData.MomentsBlue[indexAlpha, indexRed, indexGreen, indexBlue] += value[Blue]; colorData.MomentsAlpha[indexAlpha, indexRed, indexGreen, indexBlue] += value[Alpha]; colorData.Moments[indexAlpha, indexRed, indexGreen, indexBlue] += (value[Alpha] * value[Alpha]) + (value[Red] * value[Red]) + (value[Green] * value[Green]) + (value[Blue] * value[Blue]); } colorData.AddPixel( new Pixel(value[Alpha], value[Red], value[Green], value[Blue]), BitConverter.ToInt32(new[] { indexAlpha, indexRed, indexGreen, indexBlue }, 0)); index += bitDepth; } offset += byteLength; } } finally { sourceImage.UnlockBits(data); } return(colorData); }
private bool Cut(ColorData data, ref Box first, ref Box second) { int direction; var wholeAlpha = Volume(first, data.MomentsAlpha); var wholeRed = Volume(first, data.MomentsRed); var wholeGreen = Volume(first, data.MomentsGreen); var wholeBlue = Volume(first, data.MomentsBlue); var wholeWeight = Volume(first, data.Weights); var maxAlpha = Maximize(data, first, Alpha, (byte)(first.AlphaMinimum + 1), first.AlphaMaximum, wholeAlpha, wholeRed, wholeGreen, wholeBlue, wholeWeight); var maxRed = Maximize(data, first, Red, (byte)(first.RedMinimum + 1), first.RedMaximum, wholeAlpha, wholeRed, wholeGreen, wholeBlue, wholeWeight); var maxGreen = Maximize(data, first, Green, (byte)(first.GreenMinimum + 1), first.GreenMaximum, wholeAlpha, wholeRed, wholeGreen, wholeBlue, wholeWeight); var maxBlue = Maximize(data, first, Blue, (byte)(first.BlueMinimum + 1), first.BlueMaximum, wholeAlpha, wholeRed, wholeGreen, wholeBlue, wholeWeight); if ((maxAlpha.Value >= maxRed.Value) && (maxAlpha.Value >= maxGreen.Value) && (maxAlpha.Value >= maxBlue.Value)) { direction = Alpha; if (maxAlpha.Position == null) { return(false); } } else if ((maxRed.Value >= maxAlpha.Value) && (maxRed.Value >= maxGreen.Value) && (maxRed.Value >= maxBlue.Value)) { direction = Red; } else { if ((maxGreen.Value >= maxAlpha.Value) && (maxGreen.Value >= maxRed.Value) && (maxGreen.Value >= maxBlue.Value)) { direction = Green; } else { direction = Blue; } } second.AlphaMaximum = first.AlphaMaximum; second.RedMaximum = first.RedMaximum; second.GreenMaximum = first.GreenMaximum; second.BlueMaximum = first.BlueMaximum; switch (direction) { case Alpha: second.AlphaMinimum = first.AlphaMaximum = (byte)maxAlpha.Position; second.RedMinimum = first.RedMinimum; second.GreenMinimum = first.GreenMinimum; second.BlueMinimum = first.BlueMinimum; break; case Red: second.RedMinimum = first.RedMaximum = (byte)maxRed.Position; second.AlphaMinimum = first.AlphaMinimum; second.GreenMinimum = first.GreenMinimum; second.BlueMinimum = first.BlueMinimum; break; case Green: second.GreenMinimum = first.GreenMaximum = (byte)maxGreen.Position; second.AlphaMinimum = first.AlphaMinimum; second.RedMinimum = first.RedMinimum; second.BlueMinimum = first.BlueMinimum; break; case Blue: second.BlueMinimum = first.BlueMaximum = (byte)maxBlue.Position; second.AlphaMinimum = first.AlphaMinimum; second.RedMinimum = first.RedMinimum; second.GreenMinimum = first.GreenMinimum; break; } first.Size = (first.AlphaMaximum - first.AlphaMinimum) * (first.RedMaximum - first.RedMinimum) * (first.GreenMaximum - first.GreenMinimum) * (first.BlueMaximum - first.BlueMinimum); second.Size = (second.AlphaMaximum - second.AlphaMinimum) * (second.RedMaximum - second.RedMinimum) * (second.GreenMaximum - second.GreenMinimum) * (second.BlueMaximum - second.BlueMinimum); return(true); }
protected abstract QuantizedPalette GetQuantizedPalette(int colorCount, ColorData data, IEnumerable <Box> cubes, int alphaThreshold);
private static ColorData CalculateMoments(ColorData data) { for (var alphaIndex = 1; alphaIndex <= MaxSideIndex; ++alphaIndex) { var xarea = new long[SideSize, SideSize, SideSize]; var xareaAlpha = new long[SideSize, SideSize, SideSize]; var xareaRed = new long[SideSize, SideSize, SideSize]; var xareaGreen = new long[SideSize, SideSize, SideSize]; var xareaBlue = new long[SideSize, SideSize, SideSize]; var xarea2 = new float[SideSize, SideSize, SideSize]; for (var redIndex = 1; redIndex <= MaxSideIndex; ++redIndex) { var area = new long[SideSize]; var areaAlpha = new long[SideSize]; var areaRed = new long[SideSize]; var areaGreen = new long[SideSize]; var areaBlue = new long[SideSize]; var area2 = new float[SideSize]; for (var greenIndex = 1; greenIndex <= MaxSideIndex; ++greenIndex) { long line = 0; long lineAlpha = 0; long lineRed = 0; long lineGreen = 0; long lineBlue = 0; var line2 = 0.0f; for (var blueIndex = 1; blueIndex <= MaxSideIndex; ++blueIndex) { line += data.Weights[alphaIndex, redIndex, greenIndex, blueIndex]; lineAlpha += data.MomentsAlpha[alphaIndex, redIndex, greenIndex, blueIndex]; lineRed += data.MomentsRed[alphaIndex, redIndex, greenIndex, blueIndex]; lineGreen += data.MomentsGreen[alphaIndex, redIndex, greenIndex, blueIndex]; lineBlue += data.MomentsBlue[alphaIndex, redIndex, greenIndex, blueIndex]; line2 += data.Moments[alphaIndex, redIndex, greenIndex, blueIndex]; area[blueIndex] += line; areaAlpha[blueIndex] += lineAlpha; areaRed[blueIndex] += lineRed; areaGreen[blueIndex] += lineGreen; areaBlue[blueIndex] += lineBlue; area2[blueIndex] += line2; xarea[redIndex, greenIndex, blueIndex] = xarea[redIndex - 1, greenIndex, blueIndex] + area[blueIndex]; xareaAlpha[redIndex, greenIndex, blueIndex] = xareaAlpha[redIndex - 1, greenIndex, blueIndex] + areaAlpha[blueIndex]; xareaRed[redIndex, greenIndex, blueIndex] = xareaRed[redIndex - 1, greenIndex, blueIndex] + areaRed[blueIndex]; xareaGreen[redIndex, greenIndex, blueIndex] = xareaGreen[redIndex - 1, greenIndex, blueIndex] + areaGreen[blueIndex]; xareaBlue[redIndex, greenIndex, blueIndex] = xareaBlue[redIndex - 1, greenIndex, blueIndex] + areaBlue[blueIndex]; xarea2[redIndex, greenIndex, blueIndex] = xarea2[redIndex - 1, greenIndex, blueIndex] + area2[blueIndex]; data.Weights[alphaIndex, redIndex, greenIndex, blueIndex] = data.Weights[alphaIndex - 1, redIndex, greenIndex, blueIndex] + xarea[redIndex, greenIndex, blueIndex]; data.MomentsAlpha[alphaIndex, redIndex, greenIndex, blueIndex] = data.MomentsAlpha[alphaIndex - 1, redIndex, greenIndex, blueIndex] + xareaAlpha[redIndex, greenIndex, blueIndex]; data.MomentsRed[alphaIndex, redIndex, greenIndex, blueIndex] = data.MomentsRed[alphaIndex - 1, redIndex, greenIndex, blueIndex] + xareaRed[redIndex, greenIndex, blueIndex]; data.MomentsGreen[alphaIndex, redIndex, greenIndex, blueIndex] = data.MomentsGreen[alphaIndex - 1, redIndex, greenIndex, blueIndex] + xareaGreen[redIndex, greenIndex, blueIndex]; data.MomentsBlue[alphaIndex, redIndex, greenIndex, blueIndex] = data.MomentsBlue[alphaIndex - 1, redIndex, greenIndex, blueIndex] + xareaBlue[redIndex, greenIndex, blueIndex]; data.Moments[alphaIndex, redIndex, greenIndex, blueIndex] = data.Moments[alphaIndex - 1, redIndex, greenIndex, blueIndex] + xarea2[redIndex, greenIndex, blueIndex]; } } } } return(data); }