【问题标题】:How to combine several JPEGs into a bigger JPEG in a lossless way programmaticaly (.net)如何以编程方式(.net)以无损方式将多个 JPEG 组合成一个更大的 JPEG
【发布时间】:2011-04-11 12:27:15
【问题描述】:

我有几张 JPEG 图片,我想将它们合并成一张大的 JPEG 图片。

我可以通过创建一个Bitmap 然后将它们组合在那里来做到这一点,但是如果我再次将其保存为 JPEG,图像会变质。

那么,有什么方法可以让我在解码/编码时不损失质量吗?

在 ACDSee 程序中,我看到了一个可以旋转 JPEG 而不会降低质量的选项,因此可能有一种方法可以组合多张图像而不会降低质量。

谢谢

【问题讨论】:

    标签: c# image image-manipulation jpeg


    【解决方案1】:

    根据Wikipedia/Jpeg 的说法,如果您的图片尺寸是 16 的倍数,则有可能。

    Wikipedia/Lossless editing/JPEG 还谈到了可以组合多个图像的 JPEGJoin。

    .NET Framework 中没有内置任何内容,但您可以使用 C# 中的上述工具。

    【讨论】:

    • 我的图像是 16 的倍数。jpegjoin 是一个程序,但我需要一个库,因为我需要自动化这个过程。
    • 我正在寻找@LibJpeg.Net 库bitmiracle.com/libjpeg。我在维基百科文章中找到的,但仍然看不到任何可以让我将几个 jpeg 合并在一起的东西。
    【解决方案2】:

    几乎所有无损 JPEG 工具都基于来自http://sylvana.net/jpegcrop/jpegtran/ 的 jpegtran(提供源代码)。

    您需要扩展 jpeg 画布,然后使用仍处于实验阶段的“拖放”功能将图像放入另一个图像中。

    对此我不确定,但我认为图像需要使用相同的量化表(~编码质量)才能无损连接。

    【讨论】:

    • 非常感谢。但是该页面上有几个源文件。你能指导我哪一个确切地实现了这个功能吗?
    • 你可能应该从 droppatch8.zip 开始,虽然我自己没有尝试过。
    • 谢谢,会尝试的,希望仍然能找到能做到这一点的 .net 代码,也许还有关于如何做到这一点的解释:)
    【解决方案3】:

    我已经编写了代码,所以我想在这里分享它:)
    请注意,该代码不适用于所有情况,但适合我的使用。
    我正在使用 LibJpeg.Net 库 http://bitmiracle.com/libjpeg .
    库中还有一个错误(或我的错误:))您无法获得组件 height_in_blocks 这就是该代码仅适用于方形图块的原因。
    我认为图像需要具有与 Vlasta 提到的相同的量化表。
    我认为可以扩展此代码以支持该代码,但是我不需要这种支持。
    现在代码来了:)

    public void CreateBigImage()
    {
        const int iTileWidth = 256;
        const int iTileHeigth = 256;
        int iImageWidthInTiles = 2;
        int iImageHeigthInTiles = 2;
    
        //Open Image to read its header in the new image
        BitMiracle.LibJpeg.Classic.jpeg_decompress_struct objJpegDecompressHeader = new BitMiracle.LibJpeg.Classic.jpeg_decompress_struct();
        System.IO.FileStream objFileStreamHeaderImage = new System.IO.FileStream(GetImagePath(0), System.IO.FileMode.Open, System.IO.FileAccess.Read);
        objJpegDecompressHeader.jpeg_stdio_src(objFileStreamHeaderImage);
        objJpegDecompressHeader.jpeg_read_header(true);
    
        BitMiracle.LibJpeg.Classic.jvirt_array<BitMiracle.LibJpeg.Classic.JBLOCK>[] varrJBlockBigImage = new BitMiracle.LibJpeg.Classic.jvirt_array<BitMiracle.LibJpeg.Classic.JBLOCK>[10];
        for (int i = 0; i < 3; i++)//3 compounds per image (YCbCr)
        {
            int iComponentWidthInBlocks = objJpegDecompressHeader.Comp_info[i].Width_in_blocks;
            int iComponentHeigthInBlocks = iComponentWidthInBlocks;//there is no Height_in_blocks in the library so will use widht for heigth also (wont work if image is not rectangular)
            varrJBlockBigImage[i] = BitMiracle.LibJpeg.Classic.jpeg_common_struct.CreateBlocksArray(iComponentWidthInBlocks * iImageWidthInTiles, iComponentHeigthInBlocks * iImageHeigthInTiles);
        }
    
        for (int iX = 0; iX < iImageWidthInTiles; iX++)
        {
            for (int iY = 0; iY < iImageHeigthInTiles; iY++)
            {
                WriteImageToJBlockArr(varrJBlockBigImage, GetImagePath(iY*iImageHeigthInTiles+iX), iX, iY);
            }
        }
    
        System.IO.FileStream objFileStreamMegaMap = System.IO.File.Create(GetImagePath(999));
        BitMiracle.LibJpeg.Classic.jpeg_compress_struct objJpegCompress = new BitMiracle.LibJpeg.Classic.jpeg_compress_struct();
        objJpegCompress.jpeg_stdio_dest(objFileStreamMegaMap);
        objJpegDecompressHeader.jpeg_copy_critical_parameters(objJpegCompress);//will copy the critical parameter from the header image
        objJpegCompress.Image_height = iTileHeigth * iImageHeigthInTiles;
        objJpegCompress.Image_width = iTileWidth * iImageWidthInTiles;
        objJpegCompress.jpeg_write_coefficients(varrJBlockBigImage);
        objJpegCompress.jpeg_finish_compress();
        objFileStreamMegaMap.Close();
    
        objJpegDecompressHeader.jpeg_abort_decompress();
        objFileStreamHeaderImage.Close();
    }
    
    public void WriteImageToJBlockArr(BitMiracle.LibJpeg.Classic.jvirt_array<BitMiracle.LibJpeg.Classic.JBLOCK>[] varrJBlockNew, string strImagePath, int iTileX, int iTileY)
    {
        BitMiracle.LibJpeg.Classic.jpeg_decompress_struct objJpegDecompress = new BitMiracle.LibJpeg.Classic.jpeg_decompress_struct();
        System.IO.FileStream objFileStreamImage = new System.IO.FileStream(strImagePath, System.IO.FileMode.Open, System.IO.FileAccess.Read);
        objJpegDecompress.jpeg_stdio_src(objFileStreamImage);
        objJpegDecompress.jpeg_read_header(true);
        BitMiracle.LibJpeg.Classic.jvirt_array<BitMiracle.LibJpeg.Classic.JBLOCK>[] varrJBlockOrg = objJpegDecompress.jpeg_read_coefficients();
        for (int i = 0; i < 3; i++)//3 compounds per image (YCbCr)
        {
            int iComponentWidthInBlocks = objJpegDecompress.Comp_info[i].Width_in_blocks;
            int iComponentHeigthInBlocks = iComponentWidthInBlocks;//there is no Height_in_blocks in the library so will use widht for heigth also (wont work if image is not rectangular)
            for (int iY = 0; iY < iComponentHeigthInBlocks; iY++)
            {
                for (int iX = 0; iX < iComponentWidthInBlocks; iX++)
                {
                    varrJBlockNew[i].Access(iY + iTileY * iComponentHeigthInBlocks, 1)[0][iX + iTileX * iComponentWidthInBlocks] = varrJBlockOrg[i].Access(iY, 1)[0][iX];
                }
            }
        }
        objJpegDecompress.jpeg_finish_decompress();
        objFileStreamImage.Close();
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-13
      • 1970-01-01
      • 2017-10-27
      • 1970-01-01
      • 1970-01-01
      • 2015-11-20
      相关资源
      最近更新 更多