首页 文章

C#:在单个文件中保存并加载两个JPEG图像

提问于
浏览
1

我的Windows Phone应用程序保存由一些文本/数字信息(如图像捕获日期等)和一些JPEG图像组成的对象 . 例如,简单,单个文件可以由以下数据顺序组成:

from byte 0 to 3 -----> INT NUMBER
from byte 4 to 11 ----> TWO INTs DESCRIBING THE SIZE OF THE NEXT IMAGE
from byte 12 to X ----> FIRST JPEG IMAGE
from byte X+1 to X+7 -> TWO INTs DESCRIBING THE SIZE OF THE NEXT IMAGE
from byte X+8 to Y ---> SECOND JPEG IMAGE

我用这种方式实现了保存方法:

public bool SaveDataToMemory(string filename) 
{
    try
    {
        IsolatedStorageFile appStorage = IsolatedStorageFile.GetUserStoreForApplication();
        if (!appStorage.DirectoryExists(App.USER_FOLDER))
        {
            appStorage.CreateDirectory(App.USER_FOLDER);
        }

        if (appStorage.FileExists(filename))
        {
            appStorage.DeleteFile(filename);
        }

        IsolatedStorageFileStream fs = null;
        using (fs = appStorage.CreateFile(filename))
        {
            int thumbW = (int)this.thumbnail.PixelWidth;
            int thumbH = (int)this.thumbnail.PixelHeight;
            int thumbLength = thumbW * thumbH;

            int imageW = (int)this.imageSize.Width;
            int imageH = (int)this.imageSize.Height;
            int imageLength = imageW * imageH;

            byte[] byteToWrite;
            int bufferCount;

            byteToWrite = BitConverter.GetBytes(DATA_VERSION); // THE FIRST INT NUMBER
            fs.Write(byteToWrite, 0, byteToWrite.Length);

            byteToWrite = BitConverter.GetBytes(thumbW); // THE FIRST COUPLE OF INTs
            fs.Write(byteToWrite, 0, byteToWrite.Length);
            byteToWrite = BitConverter.GetBytes(thumbH);
            fs.Write(byteToWrite, 0, byteToWrite.Length);

            this.thumbnail.SaveJpeg(fs, thumbW, thumbH, 0, 75); // THE FIRST IMAGE (WriteableBitmap)


            byteToWrite = BitConverter.GetBytes(imageW); // THE SECOND COUPLE OF INTs
            fs.Write(byteToWrite, 0, byteToWrite.Length);
            byteToWrite = BitConverter.GetBytes(imageH);
            fs.Write(byteToWrite, 0, byteToWrite.Length);

            this.image.SaveJpeg(fs, imageW, imageH, 0, 92); // THE SECOND IMAGE
        }

        return true;
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine(ex);
        return false;
    }
}

该方法应该工作,至少没有抛出异常 . 现在的问题是当我尝试加载它们时 . 我按照之前描述的数据顺序访问流,我可以使用 WriteableBitmap.LoadJpeg 检索并查看第一个图像("thumbnail"),但是当我继续以便检索下一个整数时,它们看起来是0,而第二个图像无法加载例外 .

public bool LoadDataFromMemory(string filename)
{
    try
    {
        IsolatedStorageFile appStorage = IsolatedStorageFile.GetUserStoreForApplication();
        IsolatedStorageFileStream fs = null;

        if (!appStorage.FileExists(filename)) return false;

        using (fs = appStorage.OpenFile(filename, FileMode.Open))
        {
            if (fs == null) return false;

            byte[] dataVersionBuf = new byte[sizeof(Int32)]; // FIRST INTEGER
            fs.Read(dataVersionBuf, 0, dataVersionBuf.Length);
            int dataVersion = BitConverter.ToInt32(dataVersionBuf, 0);

            System.Diagnostics.Debug.WriteLine("Data version:" + dataVersion);

            byte[] thumbSizeBuf = new byte[8];
            fs.Read(thumbSizeBuf, 0, thumbSizeBuf.Length); // SIZE OF THE NEXT IMAGE

            int thumbW = BitConverter.ToInt32(thumbSizeBuf, 0);
            int thumbH = BitConverter.ToInt32(thumbSizeBuf, 4);

            this.thumbnail = new WriteableBitmap(thumbW, thumbH);
            this.thumbnail.LoadJpeg(fs); // FIRST IMAGE

            // (this prints the correct information)
            System.Diagnostics.Debug.WriteLine("Loaded thumbnail " + this.thumbnail.PixelWidth + "x" + this.thumbnail.PixelHeight); 

            byte[] leftSizeBuf = new byte[sizeof(Int32) * 2];
            fs.Read(leftSizeBuf, 0, leftSizeBuf.Length); // <<--- PROBLEMS READING HERE!

            int imageW = BitConverter.ToInt32(leftSizeBuf, 0);
            int imageH = BitConverter.ToInt32(leftSizeBuf, 4);
            // imageW and imageH are equal to 0!!!!

            System.Diagnostics.Debug.WriteLine("Loading left " + imageW + "x" + imageH);

            WriteableBitmap wb = new WriteableBitmap(imageW, imageH);
            wb.LoadJpeg(fs); // <--- EXCEPTION HERE!

            return true;
        }
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine(ex);
        return false;
    }
}

抛出的异常是 System.ArgumentException: incorrect parameter . 我是否实施了错误的方法将两个图像存储在同一个流/文件中?

2 回答

  • 1

    这可能是由于 WriteableBitmap.LoadJpeg 方法中的意外行为造成的 . 它可能会覆盖您的流,这可能会导致您的其余流处于不可预测的位置 . 我建议更新你的格式以添加jpeg的FileSize(以字节为单位),并从 FileStream 中拉出 MemoryStream 以传递给 WriteableBitmap.LoadJpeg .

    有些事情:(可能有编译问题,我不是在开发机器上检查)

    //...
    byte[] jpegSizeBytes = new byte[sizeof(Int32)]; // GET THE JPEG SIZE
    fs.Read(jpegSizeBytes , 0, jpegSizeBytes.Length);
    int jpegSize = BitConverter.ToInt32(jpegSizeBytes , 0);
    
    byte[] jpegData = new byte[jpegSize];
    fs.Read(jpegData, 0, jpegSize);
    
    using(var ms = new MemoryStream(jpegData))
    {
        this.thumbnail = new WriteableBitmap(thumbW, thumbH);
        this.thumbnail.LoadJpeg(ms); // FIRST IMAGE
    }
    //...
    

    使用与上面相同的技术来加载第二个图像 .

  • 0

    完成!从Xenolightning的回答开始,首先我将JPEG数据保存到单独的 MemoryStream 中,这样我就能用 MemoryStream.Length 得到它的最终长度 . 我将 IsolatedStorageFileStream 的长度写为一个简单的整数,然后用 MemoryStream.WriteTo(). 从前一个MemoryStream中写出全部内容 .

    // preparing thumbnail stream & length
    ms = new MemoryStream();
    this.thumbnail.SaveJpeg(ms, thumbW, thumbH, 0, 80);
    thumbLength = (int)ms.Length;
    
    // THUMB FILESIZE
    byteToWrite = BitConverter.GetBytes(thumbLength);
    fs.Write(byteToWrite, 0, byteToWrite.Length);
    
    // THUMB DATA
    ms.WriteTo(fs);
    

    当加载回来时,我首先读取文件大小数据块,然后将 fs.Read() 的适当数据量传输到MemoryStream,然后将其转换为位图对象 .

    // THUMB FILESIZE
    byteToRead = new byte[sizeof(Int32)];
    fs.Read(byteToRead, 0, byteToRead.Length);
    int thumbSize = BitConverter.ToInt32(byteToRead, 0);
    
    // GET RAW DATA
    jpegData = new byte[thumbSize];
    fs.Read(jpegData, 0, thumbSize);
    
    // CREATE IMAGE OBJECT
    ms = new MemoryStream(jpegData);
    this.thumbnail = new WriteableBitmap(thumbW, thumbH);
    this.thumbnail.LoadJpeg(ms);
    

相关问题