public virtual Bitmap view() { if (isDirty) { clean(); } if (state != null && (state.type == DataBlob.Type.Image || state.bmp != null)) { return(state.bmp); } if (state != null && state.type == DataBlob.Type.Channels && state.channels != null) { Size s = Subsample.deduceCbCrSize(state); Bitmap bmp = new Bitmap(state.channelWidth, state.channelHeight, PixelFormat.Format24bppRgb); BitmapData bmpData = bmp.LockBits( new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat); IntPtr ptr = bmpData.Scan0; //copy bytes int nBytes = Math.Abs(bmpData.Stride) * bmp.Height; byte[] rgbValues = new byte[nBytes]; System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, nBytes); //order: B,G,R, B,G,R, ... int channelIndex = 0; int counter = 0; int channelIndexRB = 0; for (int y = 0; y < state.imageHeight; y++) { channelIndex = y * state.channelWidth; channelIndexRB = y * s.Width; counter = y * bmpData.Stride; for (int x = 0; x < state.imageWidth; x++) { rgbValues[counter + 2] = state.channels[0][channelIndex]; if (y < s.Height && x < s.Width) { rgbValues[counter + 1] = state.channels[1][channelIndexRB]; rgbValues[counter + 0] = state.channels[2][channelIndexRB]; channelIndexRB++; } counter += 3; channelIndex++; } } System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, nBytes); bmp.UnlockBits(bmpData); state.bmp = bmp; return(bmp); } //Debug.Write("View missing in " + properties["name"].getString() + "\n"); return(null); }
private void reassemble(byte[][] past, byte[][] diff, byte[][] vectors) { Chunker c = new Chunker(chunkSize, state.channelWidth, state.channelHeight, state.channelWidth, 1); int pixelTL; for (int i = 0; i < c.getNumChunks(); i++) { pixelTL = c.chunkIndexToPixelIndex(i); //update channels to be difference. restoreChunk(state.channels[0], past[0], diff[0], vectors[0][i], pixelTL, state.channelWidth); } //Do the second two channels Size smaller = Subsample.deduceCbCrSize(state); c = new Chunker(chunkSize, smaller.Width, smaller.Height, smaller.Width, 1); for (int i = 0; i < c.getNumChunks(); i++) { pixelTL = c.chunkIndexToPixelIndex(i); restoreChunk(state.channels[1], past[1], diff[1], vectors[1][i], pixelTL, smaller.Width); restoreChunk(state.channels[2], past[2], diff[2], vectors[2][i], pixelTL, smaller.Width); } }
private void setupBlobs(DataBlob metadata) { C1 = new DataBlob(); C2 = new DataBlob(); C3 = new DataBlob(); V2 = new DataBlob(); V3 = new DataBlob(); C1.type = C2.type = C3.type = DataBlob.Type.Channels; V2.type = V3.type = DataBlob.Type.Vectors; //import metadata onto channels C1.imageWidth = C2.imageWidth = C3.imageWidth = metadata.imageWidth; C1.imageHeight = C2.imageHeight = C3.imageHeight = metadata.imageHeight; C1.channelWidth = C2.channelWidth = C3.channelWidth = metadata.channelWidth; C1.channelHeight = C2.channelHeight = C3.channelHeight = metadata.channelHeight; C1.quantizeQuality = C2.quantizeQuality = C3.quantizeQuality = metadata.quantizeQuality; C1.samplingMode = C2.samplingMode = C3.samplingMode = metadata.samplingMode; Chunker c = new Chunker(8, metadata.channelWidth, metadata.channelHeight, metadata.channelWidth, 1); V2.imageWidth = V3.imageWidth = metadata.imageWidth; V2.imageHeight = V3.imageHeight = metadata.imageHeight; V2.channelWidth = V3.channelWidth = c.getChunksWide(); V2.channelHeight = V3.channelHeight = c.getChunksHigh(); V2.quantizeQuality = V3.quantizeQuality = metadata.quantizeQuality; V2.samplingMode = V3.samplingMode = metadata.samplingMode; //Allocate space for incoming data C1.channels = new byte[3][]; C2.channels = new byte[3][]; C3.channels = new byte[3][]; V2.channels = new byte[3][]; V3.channels = new byte[3][]; int cMajor = C1.channelWidth * C1.channelHeight; Size sizeMinor = Subsample.getPaddedCbCrSize(new Size(C1.channelWidth, C1.channelHeight), C1.samplingMode); int cMinor = sizeMinor.Width * sizeMinor.Height; C1.channels[0] = new byte[cMajor]; C2.channels[0] = new byte[cMajor]; C3.channels[0] = new byte[cMajor]; C1.channels[1] = new byte[cMinor]; C2.channels[1] = new byte[cMinor]; C3.channels[1] = new byte[cMinor]; C1.channels[2] = new byte[cMinor]; C2.channels[2] = new byte[cMinor]; C3.channels[2] = new byte[cMinor]; cMajor = V2.channelWidth * V2.channelHeight; sizeMinor = Subsample.getCbCrSize(new Size(V2.channelWidth, V2.channelHeight), V2.samplingMode); cMinor = sizeMinor.Width * sizeMinor.Height; V2.channels[0] = new byte[cMajor]; V3.channels[0] = new byte[cMajor]; V2.channels[1] = new byte[cMinor]; V3.channels[1] = new byte[cMinor]; V2.channels[2] = new byte[cMinor]; V3.channels[2] = new byte[cMinor]; }
private void readChannels(BinaryReader reader, DataBlob ch) { Chunker c = new Chunker(8, ch.channelWidth, ch.channelHeight, ch.channelWidth, 1); readChannel(reader, ch.channels[0], c); Size s = Subsample.deduceCbCrSize(ch); c = new Chunker(8, s.Width, s.Height, s.Width, 1); readChannel(reader, ch.channels[1], c); readChannel(reader, ch.channels[2], c); }
protected static void writeChannels(BinaryWriter writer, DataBlob ch) { Chunker c = new Chunker(8, ch.channelWidth, ch.channelHeight, ch.channelWidth, 1); writeChannel(writer, ch.channels[0], c); Size s = Subsample.deduceCbCrSize(ch); c = new Chunker(8, s.Width, s.Height, s.Width, 1); writeChannel(writer, ch.channels[1], c); writeChannel(writer, ch.channels[2], c); }
private void calcMoVec(byte[][] chOld, byte[][] chNew) { //for each channel //chunk state.channels into 8x8 blocks //compare each block with blocks surrounding them in the arg channels //over x = [-7,7] (range 15 values) //and y = [-7,7] (range 15 values) //Do the first channel Chunker c = new Chunker(chunkSize, state.channelWidth, state.channelHeight, state.channelWidth, 1); int pixelTL; byte offset; //need to set vState.channelWidth and vState.channelHeight correctly, I think.... vState.channels[0] = new byte[c.getNumChunks()]; vState.channelWidth = c.getChunksWide(); vState.channelHeight = c.getChunksHigh(); for (int i = 0; i < c.getNumChunks(); i++) { pixelTL = c.chunkIndexToPixelIndex(i); //find best match given search area offset = findOffsetVector(chNew[0], chOld[0], pixelTL, state.channelWidth); //save best match vector vState.channels[0][i] = offset; //update channels to be difference. if (i == 20) { i = 20; } setDiff(state.channels[0], chNew[0], chOld[0], pixelTL, offset, state.channelWidth); } //Do the second two channels Size smaller = Subsample.deduceCbCrSize(state); c = new Chunker(chunkSize, smaller.Width, smaller.Height, smaller.Width, 1); vState.channels[1] = new byte[c.getNumChunks()]; vState.channels[2] = new byte[c.getNumChunks()]; for (int i = 0; i < c.getNumChunks(); i++) { pixelTL = c.chunkIndexToPixelIndex(i); offset = findOffsetVector(chNew[1], chOld[1], pixelTL, smaller.Width); vState.channels[1][i] = offset; setDiff(state.channels[1], chNew[1], chOld[1], pixelTL, offset, smaller.Width); //offset = findOffsetVector(state.channels[2], channels[2], pixelTL, state.channelWidth); //Just use the same vectors for channel 3 as channel 2. Probably okay. vState.channels[2][i] = offset; setDiff(state.channels[2], chNew[2], chOld[2], pixelTL, offset, smaller.Width); } }
private void padChannels() { //pad the size Size ySize = new Size(state.channelWidth, state.channelHeight); Size brOldSize = Subsample.deduceCbCrSize(state); Size brNewSize = Subsample.getPaddedCbCrSize(ySize, state.samplingMode); if (ySize.Width % 8 != 0) { ySize.Width += 8 - (ySize.Width % 8); } if (ySize.Height % 8 != 0) { ySize.Height += 8 - (ySize.Height % 8); } //create padded container byte[][] newChannels = new byte[3][]; newChannels[0] = new byte[ySize.Width * ySize.Height]; newChannels[1] = new byte[brNewSize.Width * brNewSize.Height]; newChannels[2] = new byte[newChannels[1].Length]; //copy array into larger container for (int y = 0; y < state.channelHeight; y++) { Array.Copy(state.channels[0], y * state.channelWidth, newChannels[0], y * ySize.Width, state.channelWidth); } for (int y = 0; y < brOldSize.Height; y++) { Array.Copy(state.channels[1], y * brOldSize.Width, newChannels[1], y * brNewSize.Width, brOldSize.Width); Array.Copy(state.channels[2], y * brOldSize.Width, newChannels[2], y * brNewSize.Width, brOldSize.Width); for (int x = brOldSize.Width; x < brNewSize.Width; x++) { newChannels[1][y * brNewSize.Width + x] = 127; newChannels[2][y * brNewSize.Width + x] = 127; } } //update state state.channelWidth = ySize.Width; state.channelHeight = ySize.Height; state.channels = newChannels; }
protected override void clean() { base.clean(); if (state == null || state.channels == null) { return; } if (!isInverse) { state.quantizeQuality = properties["quality"].nValue; } generateQTables(state.quantizeQuality); padChannels(); Chunker c = new Chunker(chunkSize, state.channelWidth, state.channelHeight, state.channelWidth, 1); byte[] data = new byte[chunkSize * chunkSize]; for (int i = 0; i < c.getNumChunks(); i++) { c.getBlock(state.channels[0], data, i); data = isInverse ? doIDCT(data, quantizationY) : doDCT(data, quantizationY); c.setBlock(state.channels[0], data, i); } Size tempS = Subsample.getPaddedCbCrSize(new Size(state.channelWidth, state.channelHeight), state.samplingMode); c = new Chunker(chunkSize, tempS.Width, tempS.Height, tempS.Width, 1); for (int i = 0; i < c.getNumChunks(); i++) { c.getBlock(state.channels[1], data, i); data = isInverse ? doIDCT(data, quantizationC) : doDCT(data, quantizationC); c.setBlock(state.channels[1], data, i); c.getBlock(state.channels[2], data, i); data = isInverse ? doIDCT(data, quantizationC) : doDCT(data, quantizationC); c.setBlock(state.channels[2], data, i); } }
private void open(object sender, EventArgs e) { soil(); clean(); state = new DataBlob(); state.type = DataBlob.Type.Channels; state.channels = new byte[3][]; using (Stream stream = new FileStream(inPath, FileMode.Open, FileAccess.Read, FileShare.Read)) { using (BinaryReader reader = new BinaryReader(stream, Encoding.Default)) { state.imageWidth = reader.ReadUInt16(); state.imageHeight = reader.ReadUInt16(); state.channelWidth = reader.ReadUInt16(); state.channelHeight = reader.ReadUInt16(); state.quantizeQuality = reader.ReadByte(); state.samplingMode = (DataBlob.Samples)reader.ReadByte(); state.channels[0] = new byte[state.channelWidth * state.channelHeight]; byte[] data = new byte[64]; byte count, val; //====================== //===== Y Channel ====== //====================== Chunker c = new Chunker(8, state.channelWidth, state.channelHeight, state.channelWidth, 1); var indexer = Chunker.zigZag8Index(); for (int iChunk = 0; iChunk < c.getNumChunks(); iChunk++) { for (int iPixel = 0; iPixel < 64;) { val = reader.ReadByte(); if (val != rleToken) { data[iPixel++] = val; } else { count = reader.ReadByte(); val = reader.ReadByte(); while (count > 0) { data[iPixel++] = val; count--; } } } c.setZigZag8Block(state.channels[0], data, iChunk); } //=========================== //===== Cr, Cb Channels ===== //=========================== Size len = Subsample.getPaddedCbCrSize(new Size(state.channelWidth, state.channelHeight), state.samplingMode); state.channels[1] = new byte[len.Width * len.Height]; state.channels[2] = new byte[state.channels[1].Length]; c = new Chunker(8, len.Width, len.Height, len.Width, 1); indexer = Chunker.zigZag8Index(); for (int channel = 1; channel < state.channels.Length; channel++) { for (int iChunk = 0; iChunk < c.getNumChunks(); iChunk++) { for (int iPixel = 0; iPixel < 64;) { val = reader.ReadByte(); if (val != rleToken) { data[iPixel++] = val; } else { count = reader.ReadByte(); val = reader.ReadByte(); while (count > 0) { data[iPixel++] = val; count--; } } } c.setZigZag8Block(state.channels[channel], data, iChunk); } } } } //close file }
public static Bitmap channelsToBitmap(DataBlob data) { if (data == null || data.channels == null) { return(null); } Bitmap bmp = new Bitmap(data.imageWidth, data.imageHeight, PixelFormat.Format24bppRgb); BitmapData bmpData = bmp.LockBits( new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat); IntPtr ptr = bmpData.Scan0; //copy bytes int nBytes = Math.Abs(bmpData.Stride) * bmp.Height; byte[] rgbValues = new byte[nBytes]; System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, nBytes); int pixel; int iY, iCrb; int channelYStride = data.channelWidth; //TODO: don't assume padded. :P int channelCRBStride = Subsample.getCbCrStride(data); for (int y = 0; y < data.imageHeight; y++) { pixel = y * bmpData.Stride; iY = y * channelYStride; iCrb = (data.samplingMode == DataBlob.Samples.s420 ? y / 2 : y) * channelCRBStride; for (int x = 0; x < data.imageWidth; x++) { rgbValues[pixel + 2] = data.channels[0][iY]; rgbValues[pixel + 1] = data.channels[1][iCrb]; rgbValues[pixel] = data.channels[2][iCrb]; pixel += 3; iY++; if (data.samplingMode == DataBlob.Samples.s420 || data.samplingMode == DataBlob.Samples.s422) { if (x % 2 == 1) { iCrb++; } } else if (data.samplingMode == DataBlob.Samples.s444) { iCrb++; } else if (data.samplingMode == DataBlob.Samples.s411) { if (x % 4 == 3) { iCrb++; } } } } System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, nBytes); bmp.UnlockBits(bmpData); return(bmp); }