Пример #1
0
        public static void SaveJpeg(string aFilename, int aQuality, Bitmap aImage)
        {
            if (aImage.PixelFormat != System.Drawing.Imaging.PixelFormat.Format24bppRgb)
            {
                throw new ArgumentException("Only three channel color images are supported.");
            }

            if (aImage.Width % 16 != 0 || aImage.Height % 16 != 0)
            {
                throw new ArgumentException("The provided bitmap must have a height and width of a multiple of 16.");
            }

            JPEGCompression compression = new JPEGCompression();

            NPPImage_8uC3 src = new NPPImage_8uC3(aImage.Width, aImage.Height);
            NPPImage_8uC1 srcY = new NPPImage_8uC1(aImage.Width, aImage.Height);
            NPPImage_8uC1 srcCb = new NPPImage_8uC1(aImage.Width / 2, aImage.Height / 2);
            NPPImage_8uC1 srcCr = new NPPImage_8uC1(aImage.Width / 2, aImage.Height / 2);
            src.CopyToDevice(aImage);

            //System.Drawing.Bitmap is ordered BGR not RGB
            //The NPP routine BGR to YCbCR outputs the values in clamped range, following the YCbCr standard.
            //But JPEG uses unclamped values ranging all from [0..255], thus use our own color matrix:
            float[,] BgrToYCbCr = new float[3, 4]
            {{0.114f,     0.587f,    0.299f,   0},
             {0.5f,      -0.33126f, -0.16874f, 128},
             {-0.08131f, -0.41869f,  0.5f,     128}};

            src.ColorTwist(BgrToYCbCr);

            //Reduce size of of Cb and Cr channel
            src.Copy(srcY, 2);
            srcY.Resize(srcCr, 0.5, 0.5, InterpolationMode.SuperSampling);
            src.Copy(srcY, 1);
            srcY.Resize(srcCb, 0.5, 0.5, InterpolationMode.SuperSampling);
            src.Copy(srcY, 0);

            FrameHeader oFrameHeader = new FrameHeader();
            oFrameHeader.nComponents = 3;
            oFrameHeader.nHeight = (ushort)aImage.Height;
            oFrameHeader.nSamplePrecision = 8;
            oFrameHeader.nWidth = (ushort)aImage.Width;
            oFrameHeader.aComponentIdentifier = new byte[] { 1, 2, 3 };
            oFrameHeader.aSamplingFactors = new byte[] { 34, 17, 17 }; //Y channel is twice the sice of Cb/Cr channel
            oFrameHeader.aQuantizationTableSelector = new byte[] { 0, 1, 1 };

            //Get quantization tables from JPEG standard with quality scaling
            QuantizationTable[] aQuantizationTables = new QuantizationTable[2];
            aQuantizationTables[0] = new QuantizationTable(QuantizationTable.QuantizationType.Luminance, aQuality);
            aQuantizationTables[1] = new QuantizationTable(QuantizationTable.QuantizationType.Chroma, aQuality);

            CudaDeviceVariable<byte>[] pdQuantizationTables = new CudaDeviceVariable<byte>[2];
            pdQuantizationTables[0] = aQuantizationTables[0].aTable;
            pdQuantizationTables[1] = aQuantizationTables[1].aTable;

            //Get Huffman tables from JPEG standard
            HuffmanTable[] aHuffmanTables = new HuffmanTable[4];
            aHuffmanTables[0] = new HuffmanTable(HuffmanTable.HuffmanType.LuminanceDC);
            aHuffmanTables[1] = new HuffmanTable(HuffmanTable.HuffmanType.ChromaDC);
            aHuffmanTables[2] = new HuffmanTable(HuffmanTable.HuffmanType.LuminanceAC);
            aHuffmanTables[3] = new HuffmanTable(HuffmanTable.HuffmanType.ChromaAC);

            //Set header
            ScanHeader oScanHeader = new ScanHeader();
            oScanHeader.nA = 0;
            oScanHeader.nComponents = 3;
            oScanHeader.nSe = 63;
            oScanHeader.nSs = 0;
            oScanHeader.aComponentSelector = new byte[] { 1, 2, 3 };
            oScanHeader.aHuffmanTablesSelector = new byte[] { 0, 17, 17 };

            NPPImage_16sC1[] apdDCT = new NPPImage_16sC1[3];

            NPPImage_8uC1[] apDstImage = new NPPImage_8uC1[3];
            NppiSize[] aDstSize = new NppiSize[3];
            aDstSize[0] = new NppiSize(srcY.Width, srcY.Height);
            aDstSize[1] = new NppiSize(srcCb.Width, srcCb.Height);
            aDstSize[2] = new NppiSize(srcCr.Width, srcCr.Height);

            // Compute channel sizes as stored in the output JPEG (8x8 blocks & MCU block layout)
            NppiSize oDstImageSize = new NppiSize();
            float frameWidth = (float)Math.Floor((float)oFrameHeader.nWidth);
            float frameHeight = (float)Math.Floor((float)oFrameHeader.nHeight);

            oDstImageSize.width = (int)Math.Max(1.0f, frameWidth);
            oDstImageSize.height = (int)Math.Max(1.0f, frameHeight);

            //Console.WriteLine("Output Size: " + oDstImageSize.width + "x" + oDstImageSize.height + "x" + (int)(oFrameHeader.nComponents));

            apDstImage[0] = srcY;
            apDstImage[1] = srcCb;
            apDstImage[2] = srcCr;

            int nMCUBlocksH = 0;
            int nMCUBlocksV = 0;

            // Compute channel sizes as stored in the JPEG (8x8 blocks & MCU block layout)
            for (int i = 0; i < oFrameHeader.nComponents; ++i)
            {
                nMCUBlocksV = Math.Max(nMCUBlocksV, oFrameHeader.aSamplingFactors[i] >> 4);
                nMCUBlocksH = Math.Max(nMCUBlocksH, oFrameHeader.aSamplingFactors[i] & 0x0f);
            }

            for (int i = 0; i < oFrameHeader.nComponents; ++i)
            {
                NppiSize oBlocks = new NppiSize();
                NppiSize oBlocksPerMCU = new NppiSize(oFrameHeader.aSamplingFactors[i] & 0x0f, oFrameHeader.aSamplingFactors[i] >> 4);

                oBlocks.width = (int)Math.Ceiling((oFrameHeader.nWidth + 7) / 8 *
                                          (float)(oBlocksPerMCU.width) / nMCUBlocksH);
                oBlocks.width = DivUp(oBlocks.width, oBlocksPerMCU.width) * oBlocksPerMCU.width;

                oBlocks.height = (int)Math.Ceiling((oFrameHeader.nHeight + 7) / 8 *
                                           (float)(oBlocksPerMCU.height) / nMCUBlocksV);
                oBlocks.height = DivUp(oBlocks.height, oBlocksPerMCU.height) * oBlocksPerMCU.height;

                // Allocate Memory
                apdDCT[i] = new NPPImage_16sC1(oBlocks.width * 64, oBlocks.height);

            }

            /***************************
            *
            *   Output
            *
            ***************************/

            // Forward DCT
            for (int i = 0; i < 3; ++i)
            {
                compression.DCTQuantFwd8x8LS(apDstImage[i], apdDCT[i], aDstSize[i], pdQuantizationTables[oFrameHeader.aQuantizationTableSelector[i]]);
            }

            // Huffman Encoding
            CudaDeviceVariable<byte> pdScan = new CudaDeviceVariable<byte>(BUFFER_SIZE);
            int nScanLength = 0;

            int nTempSize = JPEGCompression.EncodeHuffmanGetSize(aDstSize[0], 3);
            CudaDeviceVariable<byte> pJpegEncoderTemp = new CudaDeviceVariable<byte>(nTempSize);

            NppiEncodeHuffmanSpec[] apHuffmanDCTableEnc = new NppiEncodeHuffmanSpec[3];
            NppiEncodeHuffmanSpec[] apHuffmanACTableEnc = new NppiEncodeHuffmanSpec[3];

            for (int i = 0; i < 3; ++i)
            {
                apHuffmanDCTableEnc[i] = JPEGCompression.EncodeHuffmanSpecInitAlloc(aHuffmanTables[(oScanHeader.aHuffmanTablesSelector[i] >> 4)].aCodes, NppiHuffmanTableType.nppiDCTable);
                apHuffmanACTableEnc[i] = JPEGCompression.EncodeHuffmanSpecInitAlloc(aHuffmanTables[(oScanHeader.aHuffmanTablesSelector[i] & 0x0f) + 2].aCodes, NppiHuffmanTableType.nppiACTable);
            }

            JPEGCompression.EncodeHuffmanScan(apdDCT, 0, oScanHeader.nSs, oScanHeader.nSe, oScanHeader.nA >> 4, oScanHeader.nA & 0x0f, pdScan, ref nScanLength, apHuffmanDCTableEnc, apHuffmanACTableEnc, aDstSize, pJpegEncoderTemp);

            for (int i = 0; i < 3; ++i)
            {
                JPEGCompression.EncodeHuffmanSpecFree(apHuffmanDCTableEnc[i]);
                JPEGCompression.EncodeHuffmanSpecFree(apHuffmanACTableEnc[i]);
            }

            // Write JPEG to byte array, as in original sample code
            byte[] pDstOutput = new byte[BUFFER_SIZE];
            int pos = 0;

            oFrameHeader.nWidth = (ushort)oDstImageSize.width;
            oFrameHeader.nHeight = (ushort)oDstImageSize.height;

            writeMarker(0x0D8, pDstOutput, ref pos);
            writeJFIFTag(pDstOutput, ref pos);
            writeQuantizationTable(aQuantizationTables[0], pDstOutput, ref pos);
            writeQuantizationTable(aQuantizationTables[1], pDstOutput, ref pos);
            writeFrameHeader(oFrameHeader, pDstOutput, ref pos);
            writeHuffmanTable(aHuffmanTables[0], pDstOutput, ref pos);
            writeHuffmanTable(aHuffmanTables[1], pDstOutput, ref pos);
            writeHuffmanTable(aHuffmanTables[2], pDstOutput, ref pos);
            writeHuffmanTable(aHuffmanTables[3], pDstOutput, ref pos);
            writeScanHeader(oScanHeader, pDstOutput, ref pos);

            pdScan.CopyToHost(pDstOutput, 0, pos, nScanLength);

            pos += nScanLength;
            writeMarker(0x0D9, pDstOutput, ref pos);

            FileStream fs = new FileStream(aFilename, FileMode.Create, FileAccess.Write);
            fs.Write(pDstOutput, 0, pos);
            fs.Close();

            //cleanup:
            fs.Dispose();
            pJpegEncoderTemp.Dispose();
            pdScan.Dispose();
            apdDCT[2].Dispose();
            apdDCT[1].Dispose();
            apdDCT[0].Dispose();
            pdQuantizationTables[1].Dispose();
            pdQuantizationTables[0].Dispose();

            srcCr.Dispose();
            srcCb.Dispose();
            srcY.Dispose();
            src.Dispose();
            compression.Dispose();
        }
Пример #2
0
        /// <summary>
        /// Huffman Encoding of the JPEG Encoding.<para/>
        /// Input is expected to be 64x1 macro blocks and output is expected as byte stuffed huffman encoded JPEG scan.
        /// </summary>
        /// <param name="pSrc">Source image.</param>
        /// <param name="restartInterval">Restart Interval, see JPEG standard.</param>
        /// <param name="Ss">Start Coefficient, see JPEG standard.</param>
        /// <param name="Se">End Coefficient, see JPEG standard.</param>
        /// <param name="Ah">Bit Approximation High, see JPEG standard.</param>
        /// <param name="Al">Bit Approximation Low, see JPEG standard.</param>
        /// <param name="pDst">Byte-stuffed huffman encoded JPEG scan.</param>
        /// <param name="nLength">Byte length of the huffman encoded JPEG scan.</param>
        /// <param name="pHuffmanTableDC">DC Huffman table.</param>
        /// <param name="pHuffmanTableAC">AC Huffman table.</param>
        /// <param name="oSizeROI">ROI</param>
        /// <param name="buffer">Scratch buffer</param>
        public static void EnodeHuffmanScan(NPPImage_16sC1 pSrc, int restartInterval, int Ss, int Se, int Ah, int Al,
					CudaDeviceVariable<byte> pDst, ref int nLength, NppiEncodeHuffmanSpec pHuffmanTableDC, NppiEncodeHuffmanSpec pHuffmanTableAC, NppiSize oSizeROI, CudaDeviceVariable<byte> buffer)
        {
            NppStatus status;
            status = NPPNativeMethods.NPPi.CompressionDCT.nppiEncodeHuffmanScan_JPEG_8u16s_P1R(pSrc.DevicePointer, pSrc.Pitch, restartInterval, Ss, Se, Ah, Al, pDst.DevicePointer, ref nLength, pHuffmanTableDC, pHuffmanTableAC, oSizeROI, buffer.DevicePointer);
            Debug.WriteLine(String.Format("{0:G}, {1}: {2}", DateTime.Now, "nppiEncodeHuffmanScan_JPEG_8u16s_P1R", status));
            NPPException.CheckNppStatus(status, null);
        }
Пример #3
0
 /// <summary>
 /// Creates a Huffman table in a format that is suitable for the encoder.
 /// </summary>
 /// <param name="pRawHuffmanTable">Huffman table formated as specified in the JPEG standard.</param>
 /// <param name="eTableType">Enum specifying type of table (nppiDCTable or nppiACTable).</param>
 /// <param name="pHuffmanSpec">Pointer to the Huffman table for the decoder</param>
 /// <returns>Huffman table for the encoder</returns>
 public static void EncodeHuffmanSpecInit_JPEG(byte[] pRawHuffmanTable, NppiHuffmanTableType eTableType, NppiEncodeHuffmanSpec pHuffmanSpec)
 {
     NppStatus status;
     status = NPPNativeMethods.NPPi.CompressionDCT.nppiEncodeHuffmanSpecInit_JPEG(pRawHuffmanTable, eTableType, pHuffmanSpec);
     Debug.WriteLine(String.Format("{0:G}, {1}: {2}", DateTime.Now, "nppiEncodeHuffmanSpecInit_JPEG", status));
     NPPException.CheckNppStatus(status, null);
 }
Пример #4
0
 /// <summary>
 /// Allocates memory and creates a Huffman table in a format that is suitable for the encoder.
 /// </summary>
 /// <param name="pRawHuffmanTable">Huffman table formated as specified in the JPEG standard.</param>
 /// <param name="eTableType">Enum specifying type of table (nppiDCTable or nppiACTable).</param>
 /// <returns>Huffman table for the encoder.</returns>
 public static NppiEncodeHuffmanSpec EncodeHuffmanSpecInitAllocHost_JPEG(byte[] pRawHuffmanTable, NppiHuffmanTableType eTableType)
 {
     NppiEncodeHuffmanSpec spec = new NppiEncodeHuffmanSpec();
     NppStatus status;
     status = NPPNativeMethods.NPPi.CompressionDCT.nppiEncodeHuffmanSpecInitAlloc_JPEG(pRawHuffmanTable, eTableType, ref spec);
     Debug.WriteLine(String.Format("{0:G}, {1}: {2}", DateTime.Now, "nppiEncodeHuffmanSpecInitAlloc_JPEG", status));
     NPPException.CheckNppStatus(status, null);
     return spec;
 }
Пример #5
0
 /// <summary>
 /// Frees the memory allocated by nppiEncodeHuffmanSpecInitAlloc_JPEG.
 /// </summary>
 /// <param name="pHuffmanSpec">Pointer to the Huffman table for the encoder</param>
 public static void EncodeHuffmanSpecFree_JPEG(NppiEncodeHuffmanSpec pHuffmanSpec)
 {
     NppStatus status;
     status = NPPNativeMethods.NPPi.CompressionDCT.nppiEncodeHuffmanSpecFree_JPEG(pHuffmanSpec);
     Debug.WriteLine(String.Format("{0:G}, {1}: {2}", DateTime.Now, "nppiEncodeHuffmanSpecFree_JPEG", status));
     NPPException.CheckNppStatus(status, null);
 }
Пример #6
0
        /// <summary>
        /// Huffman Encoding of the JPEG Encoding.<para/>
        /// Input is expected to be 64x1 macro blocks and output is expected as byte stuffed huffman encoded JPEG scan.
        /// </summary>
        /// <param name="pSrc">Source image.</param>
        /// <param name="restartInterval">Restart Interval, see JPEG standard.</param>
        /// <param name="Ss">Start Coefficient, see JPEG standard.</param>
        /// <param name="Se">End Coefficient, see JPEG standard.</param>
        /// <param name="Ah">Bit Approximation High, see JPEG standard.</param>
        /// <param name="Al">Bit Approximation Low, see JPEG standard.</param>
        /// <param name="pDst">Byte-stuffed huffman encoded JPEG scan.</param>
        /// <param name="nLength">Byte length of the huffman encoded JPEG scan.</param>
        /// <param name="pHuffmanTableDC">DC Huffman table.</param>
        /// <param name="pHuffmanTableAC">AC Huffman table.</param>
        /// <param name="oSizeROI">ROI</param>
        /// <param name="buffer">Scratch buffer</param>
        public static void EncodeHuffmanScan(NPPImage_16sC1[] pSrc, int restartInterval, int Ss, int Se, int Ah, int Al,
					CudaDeviceVariable<byte> pDst, ref int nLength, NppiEncodeHuffmanSpec[] pHuffmanTableDC, NppiEncodeHuffmanSpec[] pHuffmanTableAC, NppiSize[] oSizeROI, CudaDeviceVariable<byte> buffer)
        {
            NppStatus status;

            CUdeviceptr[] srcs = new CUdeviceptr[] { pSrc[0].DevicePointer, pSrc[1].DevicePointer, pSrc[2].DevicePointer };
            int[] steps = new int[] { pSrc[0].Pitch, pSrc[1].Pitch, pSrc[2].Pitch };

            status = NPPNativeMethods.NPPi.CompressionDCT.nppiEncodeHuffmanScan_JPEG_8u16s_P3R(srcs, steps, restartInterval, Ss, Se, Ah, Al, pDst.DevicePointer, ref nLength, pHuffmanTableDC, pHuffmanTableAC, oSizeROI, buffer.DevicePointer);
            Debug.WriteLine(String.Format("{0:G}, {1}: {2}", DateTime.Now, "nppiEncodeHuffmanScan_JPEG_8u16s_P3R", status));
            NPPException.CheckNppStatus(status, null);
        }