Как я могу увеличить это изображение быстрее? - PullRequest
2 голосов
/ 01 августа 2011

У меня есть трекбар, который увеличивает или уменьшает изображение при его перемещении, но оно не масштабируется плавно, с задержкой в ​​доли секунды для увеличения 200% или более.

private void trackBar1_ValueChanged(object sender, EventArgs e)
{
    zoom = trackBar1.Value;
    zoomValue = (float)(zoom / 10.0f);
    newBitmap = new Bitmap((int)(currWidth * zoomValue), (int)(currHeight * zoomValue));

    g = Graphics.FromImage(newBitmap);
    Matrix mx = new Matrix();
    mx.Scale(zoomValue, zoomValue);

    g.InterpolationMode = InterpolationMode.HighQualityBicubic;
    g.Transform = mx;
    g.DrawImage(currImage, new Rectangle(0, 0, currWidth, currHeight));
    g.Dispose();
    mx.Dispose();
    panel1.BackgroundImage = newBitmap;
}

Iнашел пользовательский элемент управления, который кто-то сделал http://www.codeproject.com/KB/graphics/YLScsImagePanel.aspx, который очень плавно увеличивает масштаб.Лагов нет вообще.

private void trackBar1_Scroll(object sender, EventArgs e)
{
    imagePanel1.Zoom = trackBar1.Value * 0.02f;
}

Это из пользовательского элемента управления ImagePanel.cs

public float Zoom
{
    get { return zoom; }
    set
    {
        if (value < 0.001f) value = 0.001f;
        zoom = value;

        displayScrollbar();
        setScrollbarValues();
        Invalidate();
    }
}

protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);

    //draw image
    if(image!=null)
    {
        Rectangle srcRect,distRect;
        Point pt=new Point((int)(hScrollBar1.Value/zoom),(int)(vScrollBar1.Value/zoom));
        if (canvasSize.Width * zoom < viewRectWidth && canvasSize.Height * zoom < viewRectHeight)
            srcRect = new Rectangle(0, 0, canvasSize.Width, canvasSize.Height);  // view all image
        else srcRect = new Rectangle(pt, new Size((int)(viewRectWidth / zoom), (int)(viewRectHeight / zoom))); // view a portion of image

        distRect=new Rectangle((int)(-srcRect.Width/2),-srcRect.Height/2,srcRect.Width,srcRect.Height); // the center of apparent image is on origin

        Matrix mx=new Matrix(); // create an identity matrix
        mx.Scale(zoom,zoom); // zoom image
        mx.Translate(viewRectWidth/2.0f,viewRectHeight/2.0f, MatrixOrder.Append); // move image to view window center

        Graphics g=e.Graphics;
        g.InterpolationMode=interMode;
        g.Transform=mx;
        g.DrawImage(image,distRect,srcRect, GraphicsUnit.Pixel);
    }

}

Это потому, что я создаю новое растровое изображение каждый раз, когда оно задерживается?Как мне сделать так, чтобы он плавно увеличивал изображение, как этот?

1 Ответ

1 голос
/ 30 ноября 2011

, как упомянул @CodingBarfield, вычислять масштабированное изображение в методе trackBar1_ValueChanged() не очень хорошая идея. Причина в том, что если вы увеличиваете изображение слишком быстро, вы все равно вычисляете масштабированное изображение на каждом промежуточном шаге (даже в тех, которые никогда не будут отображаться). Поэтому измените метод, чтобы он выглядел так:

private void trackBar1_ValueChanged(object sender, EventArgs e)
{
    panel1.Invalidate();
}

И поместите само масштабирование в метод OnPaint(), чтобы он выглядел примерно так:

protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);

    zoom = trackBar1.Value;
    if (lastZoom != zoom)
    {
        // the zoom has changed, clear the cache
        lastZoom = zoom;
        imageCache = null;
    }

    if (imageCache == null && image != null)
    {
        // compute scaled image
        imageCache = scaleImage(image, zoom);
    }

    //draw image
    if(image!=null)
    {
        ...
    }
}

Метод масштабирования в OnPaint() не является 100% чистым решением, потому что он все еще может немного сдерживать ваш поток GUI. Лучше было бы использовать фоновый поток, но я думаю, что этого будет достаточно, и это может сэкономить вам время на кодирование.

Также вы можете получить дополнительный прирост производительности, масштабируя только ту часть изображения, которая вам нужна. Этот метод сэкономит вам квадрат увеличения, поэтому чем больше масштаб, тем больше вычислений будет сохранено.

Другой вариант - выбрать менее затратный в вычислительном отношении режим интерполяции. Или вы можете даже вычислить некоторую аппроксимацию низкого качества, отобразить ее, а затем вычислить более качественное изображение, используя фоновый поток.

Или, может быть, вы можете выбросить весь этот код и немного изменить пример CodePlex , чтобы он соответствовал вашим потребностям:).

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...