2

現在、職場で画像をスキャンして表示するためのアプリケーションを開発しています。

私のアプリケーションは複数のフォームで構築されています。ここで最も重要なフォームはmainForm、現在のスキャンに関する統計と、さまざまな機能を備えたメニューストリップを表示するフォームです。また、現在スキャンされている画像を表示するために、セカンダリ モニターに表示される がありますImageViewerFormPictureBox

を使用してTimer、画像がスキャンされるフォルダーをポーリングしています。新しい画像がスキャンされ、画像のロックが解除されたら、それを に取り込み、FileStreamに表示しPictureBoxます。以下を参照してください。

public static void SetPicture(string filename, PictureBox pb)
{
    try
    {
        Image currentImage;

        //currentImage = ImageFast.FromFile(filename);
        using (FileStream fsImage = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
        {
            currentImage = ScaleImage(Image.FromStream(fsImage), new Size(pb.Width, pb.Height));

            if (pb.InvokeRequired)
            {
                pb.Invoke(new MethodInvoker(
                delegate()
                {
                    pb.Image = currentImage;
                }));
            }
            else
            {
                pb.Image = currentImage;
            }
        }
    }
    catch (Exception imageEx)
    {
        throw new ExceptionHandler("Error when showing image", imageEx);
    }
}

public static Image ScaleImage(Image imgToResize, Size size)
{
    int sourceWidth = imgToResize.Width;
    int sourceHeight = imgToResize.Height;

    float nPercent = 0;
    float nPercentW = 0;
    float nPercentH = 0;

    nPercentW = ((float)size.Width / (float)sourceWidth);
    nPercentH = ((float)size.Height / (float)sourceHeight);

    if (nPercentH < nPercentW)
        nPercent = nPercentH;
    else
        nPercent = nPercentW;

    int destWidth = (int)(sourceWidth * nPercent);
    int destHeight = (int)(sourceHeight * nPercent);

    Bitmap b = new Bitmap(destWidth, destHeight);

    using (Graphics g = Graphics.FromImage(b))
    {
        g.InterpolationMode = InterpolationMode.HighQualityBicubic;
        g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
    }

    return b;
}

この方法では、 に表示されているイメージはPictureBoxロックされるべきではありませんが、ロックされています。問題は、スキャンした画像を再スキャンする必要がある場合があることです。そうすると、スキャン ソフトウェアから画像ファイルを上書きしようとすると、共有違反エラーが発生します。

私に何ができるかについて答えを持っている人はいますか?

解決

@SPFiredrake のおかげで、元の画像のロックを解除したまま、PictureBox に表示する一時ファイルを作成するソリューションが得られました。

public static void SetPicture(string filename, PictureBox pb)
{
    try
    {
        Image currentImage;

        //currentImage = ImageFast.FromFile(filename);
        using (FileStream fsImage = new FileStream(CreateTempFile(filename), FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
        {
            currentImage = ScaleImage(Image.FromStream(fsImage), new Size(pb.Width, pb.Height));

            if (pb.InvokeRequired)
            {
                pb.Invoke(new MethodInvoker(
                delegate()
                {
                    pb.Image = currentImage;
                }));
            }
            else
            {
                pb.Image = currentImage;
            }
        }
    }
    catch (Exception imageEx)
    {
        throw new ExceptionHandler("Error when showing image", imageEx);
    }
}

public static string CreateTempFile(string fileName)
{
    if (string.IsNullOrEmpty(fileName))
        throw new ArgumentNullException("fileName");
    if (!File.Exists(fileName))
        throw new ArgumentException("Specified file must exist!", "fileName");
    string tempFile = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + Path.GetExtension(fileName));
    File.Copy(fileName, tempFile);

    Log.New("Temp file created: " + tempFile);

    return tempFile;
}
4

7 に答える 7

4

ここでの問題は、ストリームへの参照を保持しているため、PictureBox によってロックされている FileStream からイメージが読み込まれていることです。あなたがしなければならないことは、最初に画像を(byte []配列を介して)ローカルメモリにロードし、代わりにMemoryStreamから画像をロードすることです。SetPictureメソッドで、次の変更を試して、それが機能するかどうかを確認する必要があります。

public static void SetPicture(string filename, PictureBox pb)
{
    try
    {
        Image currentImage;
        byte[] imageBytes = File.ReadAllBytes(filename);
        using(MemoryStream msImage = new MemoryStream(imageBytes))
        {
            currentImage = ScaleImage(Image.FromStream(msImage), new Size(pb.Width, pb.Height));
        ....
}

編集:チャットでの会話の後、あなたが最終的に使用した修正で更新します:

public static void SetPicture(string filename, PictureBox pb)
{
    try
    {
        Image currentImage;
        string tempFile = Path.Combine(Path.GetTempDirectory(), Guid.NewGuid().ToString() + Path.GetExtension(filename));
        File.Copy(filename, tempFile);
        //currentImage = ImageFast.FromFile(filename);
        using (FileStream fsImage = new FileStream(tempFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
        {
            ...

このように、一時ファイルを使用して画像ボックスを実際にロードし、元のファイルはそのままにしておきます (最初のコピーの外側)。

于 2012-05-07T13:52:50.060 に答える
1

ビットマップが読み込まれると、ファイルストリームを保持しなくなるため、すべてが機能するはずです。ただし、ロードが行われ、スキャンがそのファイルを上書きしようとする瞬間について話している場合は、常に「一時」またはジャンクという名前のファイルをスキャンします (名前として GUID を使用します)。スキャンが完了したら、そのファイルの名前を JPG に変更します。これにより、表示フォームが取得され、適切に表示されます。

このように、再スキャンでは、一時ファイルの名前を複数回変更して「待機」するだけで、重複する小さな領域を防ぐことができます。

于 2012-05-03T14:20:12.120 に答える
1

あなたのコードは私にとってはうまくいきます。正確なコピーを取り、同じ画像ファイルで繰り返し呼び出しました。

SetPicture(@"c:\temp\logo.png", pictureBox1);

他の何かがファイルをロックしています。通話コードを共有できますか?

于 2012-05-03T15:32:47.077 に答える
0

これは Jack コードですが、Visual Basic .NET ではキャストが関数内で行われます。

 Private Function CloneImage(aImagePath As String) As Image
        ' create original image
        Dim originalImage As Image = New Bitmap(aImagePath)

        ' create an empty clone of the same size of original
        Dim clone As Bitmap = New Bitmap(originalImage.Width, originalImage.Height)

        ' get the object representing clone's currently empty drawing surface
        Dim g As Graphics = Graphics.FromImage(clone)

        g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None
        g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor
        g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighSpeed

        ' copy the original image onto this surface
        g.DrawImage(originalImage, 0, 0, originalImage.Width, originalImage.Height)

        ' free graphics and original image
        g.Dispose()
        originalImage.Dispose()

        Return CType(clone, Image)
    End Function

したがって、呼び出しは

picture.Image = CloneImage(imagePath)

ありがとうジャック、

于 2013-04-01T23:41:47.060 に答える
0

あなたはもう仕事を終えていると思います。
それでも、他の誰かが同じ問題を抱えている場合に備えて投稿しています。
私は同じ問題を抱えていました:PictureBoxコントロールに画像をロードします

picture.Image = new Bitmap(imagePath);  

そして動かそうとすると

File.Move(source, destination);  

mscorlib は例外をスローします:
別のプロセスによって使用されているため、プロセスはファイルにアクセスできません

私は解決策を見つけました(ただし、C#ではなくVB.Netにあります)ここでPictureBoxの「ロック」ファイル、移動/削除できません

投稿の作成者は、元の画像を複製し、複製した画像を PictureBox コントロールに読み込みます。
コードを少し変更して、これを思いつきました:

private Bitmap CloneImage(string aImagePath) {  
    // create original image
    Image originalImage = new Bitmap(aImagePath);

    // create an empty clone of the same size of original
    Bitmap clone = new Bitmap(originalImage.Width, originalImage.Height);

    // get the object representing clone's currently empty drawing surface
    Graphics g = Graphics.FromImage(clone);

    g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;
    g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
    g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighSpeed;

    // copy the original image onto this surface
    g.DrawImage(originalImage, 0, 0, originalImage.Width, originalImage.Height);

    // free graphics and original image
    g.Dispose();
    originalImage.Dispose();

    return clone;
    }

したがって、コードは次のようになります。

picture.Image = (Image)CloneImage(imagePath);  

そうすることで、ファイルを移動するときに例外がなくなりました。
それを行うための良い代替方法だと思います。一時ファイルは必要ありません。

于 2013-01-03T17:08:52.077 に答える
0

MSからのこの質問への回答...

私にとっては大丈夫です...

internal void UpdateLastImageDownloaded(string fullfilename)
{
    this.BeginInvoke((MethodInvoker)delegate()
    {
        try
        {
            //pictureBoxImage.Image = Image.FromFile(fullfilename);

            //Bitmap bmp = new Bitmap(fullfilename);
            //pictureBoxImage.Image = bmp;

            System.IO.FileStream fs;
            // Specify a valid picture file path on your computer.
            fs = new System.IO.FileStream(fullfilename, System.IO.FileMode.Open, System.IO.FileAccess.Read);
            pictureBoxImage.Image = System.Drawing.Image.FromStream(fs);
            fs.Close();
        }
        catch (Exception exc)
        {
            Logging.Log.WriteException(exc);
        }
    });
}
于 2016-03-18T15:56:17.237 に答える