/// <summary> /// Decodes Huffman encoded image back to gray scale image /// </summary> /// <param name="encodedImage"></param> /// <returns></returns> public static ImageFrameGrayScale AsImageGrayScaleFrame(this HuffmanImageFrame encodedImage) { //---------- generate tree from color codes ----------------- var maxNodes = 0; for (int i = 0; i <= encodedImage.MaxCodeBitsLength + 1; i++) { maxNodes = 1 << i; } //simple help table for tree generation var nodeTree = new HuffmanTreeNode <int> [maxNodes - 1]; var rootNode = new HuffmanTreeNode <int>(); nodeTree[0] = rootNode; for (int i = 0; i < encodedImage.ColorCodeCount; i++) { var colorCodeItem = encodedImage.GetColorCodeItemFromHeader(i); var huffmanNode = new HuffmanTreeNode <int>(colorCodeItem.Symbol, colorCodeItem.Code, colorCodeItem.CodeBitsCount); huffmanNode.PopulateBitTable(); //start always from root bit and go to leaf var parentPos = 0; var parent = nodeTree[0]; for (int j = huffmanNode.CodeBitTable.Length - 1; j >= 0; j--) { var childPos = 0; var isRightChild = huffmanNode.CodeBitTable[j]; if (isRightChild) { childPos = ((parentPos + 1) * 2 + 1) - 1; } else { childPos = ((parentPos + 1) * 2) - 1; } if (j == 0) { //leaf node nodeTree[childPos] = huffmanNode; } else if (nodeTree[childPos] == null) { //create internal node nodeTree[childPos] = new HuffmanTreeNode <int>(); } nodeTree[childPos].SetParent(parent, isRightChild); parent.SetChild(nodeTree[childPos]); parent = nodeTree[childPos]; parentPos = childPos; } } var imageHeaderSize = encodedImage.OriginalImageHeaderLength + ImageFrame.HEADER_256_COLOR_TABLE_SIZE; var imageData = new byte[imageHeaderSize + encodedImage.OriginalImageDataLength]; //------------- set header ------------------------ //copy original image non-encoded header to image encodedImage.Data.CopyBytesTo( encodedImage.FixedHeaderLength + encodedImage.ColorCodeHeaderLength, imageData, 0, encodedImage.OriginalImageHeaderLength); //--------------- decode image ----------------------- var node = rootNode; var destIndex = imageHeaderSize; //read encoded stream bit by bit and travel tree using bit value //until leaf node is reached. read original color code from leaf node for (int i = 0; i < encodedImage.CompressedBits; i++) { //read right or left child based bit in stream node = encodedImage.GetBit(i) ? node.RightChild : node.LeftChild; if (node.Leaf) { //set decoded byte to image imageData[destIndex++] = (byte)node.Symbol; //move back to root node node = rootNode; } } var ret = new ImageFrameGrayScale(imageData); //generate color table ret.SetColorTable(); return(ret); }
/// <summary> /// Converts 24 bit color image to gray scale image /// </summary> /// <param name="image">Color image</param> /// <param name="colors">How many gray colors are used in gray image</param> /// <returns></returns> public static ImageFrameGrayScale AsGrayScale(this ImageFrame image, int colors = 256) { //--------- write gray scale image header ----------------- const int headerSize = ImageFrame.HEADER_BYTES; const int colorTableSize = ImageFrame.HEADER_256_COLOR_TABLE_SIZE; var headerAndColorTable = headerSize + colorTableSize; var newImage = new byte[image.ImageWidthPx * image.ImageHeightPx + headerAndColorTable]; //magic bits image.Image.CopyBytesTo(0, newImage, 0, 2); //file size ((uint)(newImage.Length)).AsBytes().CopyBytesTo(newImage, 2); //pixel data offset 54 (old header) + 1024 (color table) = 1078 newImage[10] = 54; newImage[11] = 4; //header size newImage[14] = 40; //image width and height image.Image.CopyBytesTo(18, newImage, 18, 4); image.Image.CopyBytesTo(22, newImage, 22, 4); //planes image.Image.CopyBytesTo(26, newImage, 26, 2); //bits per pixel newImage[28] = 8; //--------- convert rgb pixels to gray scale //linear conversion consts const double redLinear = 0.2126; const double greenLinear = 0.7152; const double blueLinear = 0.0722; var colorCount = 256 / colors; var destIndex = image.HeaderBytesLength + 1024; for (int r = 0; r < image.ImageHeightPx; r++) { var rowStartPos = (r * image.ImageWidthPx * 3) + image.HeaderBytesLength; //read each pixel in row for (int p = 0; p < image.ImageWidthPx; p++) { //pixel is presented as 24 bit (3 bytes) var pixelPos = rowStartPos + p * 3; var green = image.Image[pixelPos + 1]; var blue = image.Image[pixelPos]; var red = image.Image[pixelPos + 2]; var grayIndex = (int)(red * redLinear + green * greenLinear + blue * blueLinear); var mod = (grayIndex % colorCount); grayIndex -= mod; var grayIndexByte = (byte)grayIndex; newImage[destIndex++] = grayIndexByte; } } var ret = new ImageFrameGrayScale(newImage); //color table ret.SetColorTable(); return(ret); }