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

时间:2013-11-28 01:21:53

标签: c# stream windows-phone isolatedstorage

我的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检索并查看第一个图像(“缩略图”),但是当我继续以便检索下一个整数时,它们看起来是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 个答案:

答案 0 :(得分:1)

这可能是由于WriteableBitmap.LoadJpeg方法中的意外行为造成的。它可能会覆盖您的流,这可能会导致您的其余流处于不可预测的位置。我建议您更新格式以添加jpeg的FileSize(以字节为单位),然后从MemoryStream中提取FileStream以传递给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
}
//...

使用与上面相同的技术加载第二张图片。

答案 1 :(得分: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);