private static Dictionary <int, int> findTileSizeEfficiencies(byte[] raw16BitImageData, int fullImageWidth, int minTileSize = 10, int maxTileSize = 3000, int StepSize = 10) { Dictionary <int, int> retVal = new Dictionary <int, int>(); UInt16[] data = new UInt16[raw16BitImageData.Length / 2]; Buffer.BlockCopy(raw16BitImageData, 0, data, 0, raw16BitImageData.Length); int fullImageHeight = data.Length / fullImageWidth; for (int tileSize = minTileSize; tileSize <= maxTileSize; tileSize += StepSize) { int tilesHCount = (int)Math.Ceiling((double)fullImageWidth / (double)tileSize); int tilesVCount = (int)Math.Ceiling((double)fullImageHeight / (double)tileSize); UInt16[] tileData = new UInt16[tileSize * tileSize]; byte[] encodedTile; int encodedFileSizeHere = 0; for (int x = 0; x < tilesHCount; x++) { for (int y = 0; y < tilesVCount; y++) { tileData = new UInt16[tileSize * tileSize]; for (int row = 0; row < (Math.Min(fullImageHeight, ((y + 1) * tileSize)) - (y * tileSize)); row++) { Array.Copy(data, (y * tileSize + row) * fullImageWidth + x * tileSize, tileData, row * tileSize, Math.Min(fullImageWidth, ((x + 1) * tileSize)) - x * tileSize); } // Tile is prepared now. Let's encode it. dng_stream whatever = new dng_stream(); DNGLosslessEncoder.EncodeLosslessJPEG(tileData, (uint)tileSize, (uint)tileSize / 2, 2, 16, tileSize, 2, whatever); encodedTile = whatever.toByteArray(); encodedFileSizeHere += encodedTile.Length; //File.WriteAllBytes("encodedTest.jpg", whatever.toByteArray()); } } retVal.Add(tileSize, encodedFileSizeHere); Console.WriteLine("tileSize " + tileSize + ": " + encodedFileSizeHere + "bytes"); } return(retVal); }
/* * public: * * dng_lossless_encoder(const uint16* srcData, * uint32 srcRows, * uint32 srcCols, * uint32 srcChannels, * uint32 srcBitDepth, * int32 srcRowStep, * int32 srcColStep, * dng_stream &stream); * * void Encode(); * * private: * * void EmitByte(uint8 value); * * void EmitBits(int code, int size); * * void FlushBits(); * * void CountOneDiff(int diff, uint32* countTable); * * void EncodeOneDiff(int diff, HuffmanTable* dctbl); * * void FreqCountSet(); * * void HuffEncode(); * * void GenHuffCoding(HuffmanTable* htbl, uint32* freq); * * void HuffOptimize(); * * void EmitMarker(JpegMarker mark); * * void Emit2bytes(int value); * * void EmitDht(int index); * * void EmitSof(JpegMarker code); * * void EmitSos(); * * void WriteFileHeader(); * * void WriteScanHeader(); * * void WriteFileTrailer(); * * }; * * /*****************************************************************************/ public DNGLosslessEncoder(uint16[] srcData, uint32 srcRows, uint32 srcCols, uint32 srcChannels, uint32 srcBitDepth, int32 srcRowStep, int32 srcColStep, dng_stream stream) { fSrcData = srcData; fSrcRows = srcRows; fSrcCols = srcCols; fSrcChannels = srcChannels; fSrcBitDepth = srcBitDepth; fSrcRowStep = srcRowStep; fSrcColStep = srcColStep; fStream = stream; huffPutBuffer = 0; huffPutBits = 0; // Initialize number of bits lookup table. numBitsTable[0] = 0; for (int i = 1; i < 256; i++) { int temp = i; int nbits = 1; while ((temp >>= 1) != 0) { nbits++; } numBitsTable[i] = nbits; } }
private static void testAdobeJPGEncode() { int tileWidth = 256; int tileHeight = 240; byte[] rawReferenceData = File.ReadAllBytes("rawToEncode-DNG.raw"); UInt16[] rawReferenceDataUInt16 = new UInt16[rawReferenceData.Length / 2]; for (int i = 0; i < rawReferenceDataUInt16.Length; i++) { rawReferenceDataUInt16[i] = BitConverter.ToUInt16(rawReferenceData, i * 2); } dng_stream whatever = new dng_stream(); DNGLosslessEncoder.EncodeLosslessJPEG(rawReferenceDataUInt16, (uint)tileHeight, (uint)tileWidth / 2, 2, 16, tileWidth, 2, whatever); File.WriteAllBytes("encodedTest.jpg", whatever.toByteArray()); // Try decode again JpegDecoder jpegLibraryDecoder = new JpegDecoder(); byte[] rawTileBuffer = File.ReadAllBytes("encodedTest.jpg"); byte[] tileBuff = new byte[tileWidth * tileHeight * 2]; ReadOnlyMemory <byte> rawTileReadOnlyMemory; rawTileReadOnlyMemory = new ReadOnlyMemory <byte>(rawTileBuffer); jpegLibraryDecoder.SetInput(rawTileReadOnlyMemory); //jpegLibraryDecoder.SetFrameHeader() jpegLibraryDecoder.Identify(); // fails to identify. missing markers or whatever: Failed to decode JPEG data at offset 91149. No marker found.' jpegLibraryDecoder.SetOutputWriter(new JpegDecode.JpegBufferOutputWriterGreaterThan8Bit(tileWidth / 2, tileHeight, jpegLibraryDecoder.Precision, 2, tileBuff, 16)); jpegLibraryDecoder.Decode(); File.WriteAllBytes("sof3-encodedecodetest.raw", tileBuff); }
/*****************************************************************************/ static public void EncodeLosslessJPEG(uint16[] srcData, uint32 srcRows, uint32 srcCols, uint32 srcChannels, uint32 srcBitDepth, int32 srcRowStep, int32 srcColStep, dng_stream stream) { DNGLosslessEncoder encoder = new DNGLosslessEncoder(srcData, srcRows, srcCols, srcChannels, srcBitDepth, srcRowStep, srcColStep, stream); encoder.Encode(); }
private static Dictionary <int, int> findTileSizeEfficienciesAndWriteDNGs(byte[] raw16BitImageData, int fullImageWidth, int minTileSize = 10, int maxTileSize = 3000, int StepSize = 10) { char[] bayerSubstitution = { "\x0"[0], "\x1"[0], "\x2"[0] }; string bayerPatternTag = bayerSubstitution[0].ToString() + bayerSubstitution[1] + bayerSubstitution[1] + bayerSubstitution[2]; Dictionary <int, int> retVal = new Dictionary <int, int>(); UInt16[] data = new UInt16[raw16BitImageData.Length / 2]; Buffer.BlockCopy(raw16BitImageData, 0, data, 0, raw16BitImageData.Length); int fullImageHeight = data.Length / fullImageWidth; for (int tileSize = minTileSize; tileSize <= maxTileSize; tileSize += StepSize) { int tilesHCount = (int)Math.Ceiling((double)fullImageWidth / (double)tileSize); int tilesVCount = (int)Math.Ceiling((double)fullImageHeight / (double)tileSize); UInt16[] tileData = new UInt16[tileSize * tileSize]; byte[, ][] encodedTile = new byte[tilesHCount, tilesVCount][]; int encodedFileSizeHere = 0; int width = fullImageWidth; int height = fullImageHeight; for (int x = 0; x < tilesHCount; x++) { for (int y = 0; y < tilesVCount; y++) { tileData = new UInt16[tileSize * tileSize]; for (int row = 0; row < (Math.Min(fullImageHeight, ((y + 1) * tileSize)) - (y * tileSize)); row++) { Array.Copy(data, (y * tileSize + row) * fullImageWidth + x * tileSize, tileData, row * tileSize, Math.Min(fullImageWidth, ((x + 1) * tileSize)) - x * tileSize); } // Tile is prepared now. Let's encode it. dng_stream whatever = new dng_stream(); DNGLosslessEncoder.EncodeLosslessJPEG(tileData, (uint)tileSize, (uint)tileSize / 2, 2, 16, tileSize, 2, whatever); encodedTile[x, y] = whatever.toByteArray(); encodedFileSizeHere += encodedTile.Length; //File.WriteAllBytes("encodedTest.jpg", whatever.toByteArray()); } } using (Tiff output = Tiff.Open("tiletest-" + tileSize + ".dng", "w")) { // Basic TIFF functionality output.SetField(TiffTag.IMAGEWIDTH, width); output.SetField(TiffTag.IMAGELENGTH, height); output.SetField(TiffTag.SAMPLESPERPIXEL, 1); output.SetField(TiffTag.BITSPERSAMPLE, 16); //rawImageData = DataFormatConverter.convert16bitIntermediateTo12paddedto16bit(rawImageData); //output.SetField(TiffTag.BASELINEEXPOSURE, 4); output.SetField(TiffTag.ORIENTATION, Orientation.TOPLEFT); //output.SetField(TiffTag.ROWSPERSTRIP, height); output.SetField(TiffTag.PHOTOMETRIC, Photometric.MINISBLACK); output.SetField(TiffTag.FILLORDER, FillOrder.MSB2LSB); output.SetField(TiffTag.PLANARCONFIG, PlanarConfig.CONTIG); float[] cam_xyz = { 3.2404542f, -1.5371385f, -0.4985314f, -0.9692660f, 1.8760108f, 0.0415560f, 0.0556434f, -0.2040259f, 1.0572252f }; // my sRGB hack //float[] cam_xyz = { 0f, 1f,0f,0f,0f,1f,1f,0f,0f }; // my sRGB hack float[] neutral = { 1f, 1f, 1f }; // my sRGB hack int[] bpp = { 8, 8, 8 }; // my sRGB hack short[] bayerpatterndimensions = { 2, 2 }; // my sRGB hack //float[] neutral = { 0.807133f, 1.0f, 0.913289f }; //DNG output.SetField(TiffTag.SUBFILETYPE, 0); output.SetField(TiffTag.MAKE, "Point Grey"); output.SetField(TiffTag.MODEL, "Chameleon3"); output.SetField(TiffTag.SOFTWARE, "FlyCapture2"); output.SetField(TiffTag.DNGVERSION, "\x1\x4\x0\x0"); output.SetField(TiffTag.DNGBACKWARDVERSION, "\x1\x4\x0\x0"); output.SetField(TiffTag.UNIQUECAMERAMODEL, "USB3"); output.SetField(TiffTag.COLORMATRIX1, 9, cam_xyz); output.SetField(TiffTag.ASSHOTNEUTRAL, 3, neutral); output.SetField(TiffTag.CALIBRATIONILLUMINANT1, 21); output.SetField(TiffTag.PHOTOMETRIC, 32803); output.SetField(TiffTag.SAMPLESPERPIXEL, 1); //output.SetField(TiffTag.EXIF_CFAPATTERN, 4, "\x1\x0\x2\x1"); output.SetField(TiffTag.EXIF_CFAPATTERN, 4, bayerPatternTag); output.SetField(TIFFTAG_CFAREPEATPATTERNDIM, bayerpatterndimensions); //output.SetField(TIFFTAG_CFAPATTERN, "\x1\x0\x2\x1"); //0=Red, 1=Green, 2=Blue, 3=Cyan, 4=Magenta, 5=Yellow, and 6=White output.SetField(TIFFTAG_CFAPATTERN, bayerPatternTag); //0=Red, 1=Green, 2=Blue, 3=Cyan, 4=Magenta, 5=Yellow, and 6=White // Maybe use later if necessary: //output.SetField(TiffTag.SAMPLESPERPIXEL, 1); //output.SetField(TiffTag.BITSPERSAMPLE, 3, bpp); //output.SetField(TiffTag.LINEARIZATIONTABLE, 256, linearizationTable); //output.SetField(TiffTag.WHITELEVEL, 1); output.SetField(TiffTag.COMPRESSION, Compression.JPEG); //output.WriteRawStrip(0, jpegData, jpegData.Length); //output.WriteRawTile(); output.SetField(TiffTag.TILELENGTH, tileSize); output.SetField(TiffTag.TILEWIDTH, tileSize); output.SetField(TiffTag.IMAGELENGTH, fullImageHeight); for (int x = 0; x < tilesHCount; x++) { for (int y = 0; y < tilesVCount; y++) { int tileNubmer = output.ComputeTile(x * tileSize, y * tileSize, 0, 0); output.WriteRawTile(tileNubmer, encodedTile[x, y], encodedTile[x, y].Length); } } } retVal.Add(tileSize, encodedFileSizeHere); Console.WriteLine("tileSize " + tileSize + ": " + encodedFileSizeHere + "bytes"); } return(retVal); }