DrawImage не может правильно позиционировать нарезанные изображения - PullRequest
3 голосов
/ 21 июля 2011

Уже пару дней я пытаюсь выяснить, почему мой девятисекционный код не работает должным образом.Насколько я вижу, кажется, что есть проблема с методом Graphics.DrawImage, который неправильно обрабатывает мои девять изображений среза.Поэтому моя проблема заключается в том, как компенсировать неправильное масштабирование, которое выполняется при запуске моего кода на компактной платформе.Я мог бы добавить, что этот код, конечно, отлично работает при работе в полнофункциональной среде.Проблема возникает только при масштабировании изображения на большее изображение, а не наоборот.Вот фрагмент:

public class NineSliceBitmapSnippet
{
    private Bitmap m_OriginalBitmap;

    public int CornerLength { get; set; }

    /// <summary>
    /// Initializes a new instance of the NineSliceBitmapSnippet class.
    /// </summary>
    public NineSliceBitmapSnippet(Bitmap bitmap)
    {
        CornerLength = 5;
        m_OriginalBitmap = bitmap;
    }

    public Bitmap ScaleSingleBitmap(Size size)
    {
        Bitmap scaledBitmap = new Bitmap(size.Width, size.Height);
        int[] horizontalTargetSlices = Slice(size.Width);
        int[] verticalTargetSlices = Slice(size.Height);

        int[] horizontalSourceSlices = Slice(m_OriginalBitmap.Width);
        int[] verticalSourceSlices = Slice(m_OriginalBitmap.Height);

        using (Graphics graphics = Graphics.FromImage(scaledBitmap))
        {
            using (Brush brush = new SolidBrush(Color.Fuchsia))
            {
                graphics.FillRectangle(brush, new Rectangle(0, 0, size.Width, size.Height));
            }

            int horizontalTargetOffset = 0;
            int verticalTargetOffset = 0;

            int horizontalSourceOffset = 0;
            int verticalSourceOffset = 0;

            for (int x = 0; x < horizontalTargetSlices.Length; x++)
            {
                verticalTargetOffset = 0;
                verticalSourceOffset = 0;
                for (int y = 0; y < verticalTargetSlices.Length; y++)
                {
                    Rectangle destination = new Rectangle(horizontalTargetOffset, verticalTargetOffset, horizontalTargetSlices[x], verticalTargetSlices[y]);
                    Rectangle source = new Rectangle(horizontalSourceOffset, verticalSourceOffset, horizontalSourceSlices[x], verticalSourceSlices[y]);

                    graphics.DrawImage(m_OriginalBitmap, destination, source, GraphicsUnit.Pixel);

                    verticalTargetOffset += verticalTargetSlices[y];
                    verticalSourceOffset += verticalSourceSlices[y];
                }

                horizontalTargetOffset += horizontalTargetSlices[x];
                horizontalSourceOffset += horizontalSourceSlices[x];
            }
        }
        return scaledBitmap;
    }

    public int[] Slice(int length)
    {
        int cornerLength = CornerLength;

        if (length <= (cornerLength * 2))
            throw new Exception("Image to small for sliceing up");

        int[] slices = new int[3];
        slices[0] = cornerLength;
        slices[1] = length - (2 * cornerLength);
        slices[2] = cornerLength;

        return slices;
    }
}

Итак, мой вопрос: кто-нибудь теперь знает, как я могу компенсировать неправильное масштабирование?

/ Дан

1 Ответ

1 голос
/ 25 июля 2011

После еще нескольких проб и ошибок я наконец нашел решение своей проблемы. Проблемы с масштабированием всегда были связаны с верхним центральным, правым центральным, нижним центральным и левым центральным срезами, поскольку они всегда растягиваются только в одном направлении в соответствии с логикой масштабирования из девяти срезов. Если я применяю временно квадратное растяжение к этим срезами перед применением правильного растяжения, окончательное растровое изображение будет правильным. Еще раз проблема видна только в .Net Compact Framework устройства Windows CE (Smart Device). Вот фрагмент кода с поправкой на ошибку в CF. Теперь меня беспокоит только то, что срезы, которые растягиваются на квадрат, занимают гораздо больше памяти из-за кода коррекции. С другой стороны, этот шаг - короткий промежуток времени, поэтому я могу сойти с рук. ;)

    public class NineSliceBitmapSnippet
{
    private Bitmap m_OriginalBitmap;

    public int CornerLength { get; set; }

    public NineSliceBitmapSnippet(Bitmap bitmap)
    {
        CornerLength = 5;
        m_OriginalBitmap = bitmap;
    }

    public Bitmap Scale(Size size)
    {
        if (m_OriginalBitmap != null)
        {
            return ScaleSingleBitmap(size);
        }

        return null;
    }

    public Bitmap ScaleSingleBitmap(Size size)
    {
        Bitmap scaledBitmap = new Bitmap(size.Width, size.Height);
        int[] horizontalTargetSlices = Slice(size.Width);
        int[] verticalTargetSlices = Slice(size.Height);

        int[] horizontalSourceSlices = Slice(m_OriginalBitmap.Width);
        int[] verticalSourceSlices = Slice(m_OriginalBitmap.Height);

        using (Graphics graphics = Graphics.FromImage(scaledBitmap))
        {
            using (Brush brush = new SolidBrush(Color.Fuchsia))
            {
                graphics.FillRectangle(brush, new Rectangle(0, 0, size.Width, size.Height));
            }

            int horizontalTargetOffset = 0;
            int verticalTargetOffset = 0;

            int horizontalSourceOffset = 0;
            int verticalSourceOffset = 0;

            for (int x = 0; x < horizontalTargetSlices.Length; x++)
            {
                verticalTargetOffset = 0;
                verticalSourceOffset = 0;
                for (int y = 0; y < verticalTargetSlices.Length; y++)
                {
                    Rectangle destination = new Rectangle(horizontalTargetOffset, verticalTargetOffset, horizontalTargetSlices[x], verticalTargetSlices[y]);
                    Rectangle source = new Rectangle(horizontalSourceOffset, verticalSourceOffset, horizontalSourceSlices[x], verticalSourceSlices[y]);

                    bool isWidthAffectedByVerticalStretch = (y == 1 && (x == 0 || x == 2) && destination.Height > source.Height);
                    bool isHeightAffectedByHorizontalStretch = (x == 1 && (y == 0 || y == 2) && destination.Width > source.Width);
                    if (isHeightAffectedByHorizontalStretch)
                    {
                        BypassDrawImageError(graphics, destination, source, Orientation.Horizontal);
                    }
                    else if (isWidthAffectedByVerticalStretch)
                    {
                        BypassDrawImageError(graphics, destination, source, Orientation.Vertical);
                    }
                    else
                    {
                        graphics.DrawImage(m_OriginalBitmap, destination, source, GraphicsUnit.Pixel);
                    }

                    verticalTargetOffset += verticalTargetSlices[y];
                    verticalSourceOffset += verticalSourceSlices[y];
                }

                horizontalTargetOffset += horizontalTargetSlices[x];
                horizontalSourceOffset += horizontalSourceSlices[x];
            }
        }
        return scaledBitmap;
    }

    private void BypassDrawImageError(Graphics graphics, Rectangle destination, Rectangle source, Orientation orientationAdjustment)
    {
        Size adjustedSize = Size.Empty;
        switch (orientationAdjustment)
        {
            case Orientation.Horizontal:
                adjustedSize = new Size(destination.Width, destination.Width);
                break;
            case Orientation.Vertical:
                adjustedSize = new Size(destination.Height, destination.Height);
                break;
            default:
                break;
        }

        using (Bitmap quadScaledBitmap = new Bitmap(adjustedSize.Width, adjustedSize.Height))
        {
            using (Graphics tempGraphics = Graphics.FromImage(quadScaledBitmap))
            {
                tempGraphics.Clear(Color.Fuchsia);
                tempGraphics.DrawImage(m_OriginalBitmap, new Rectangle(0, 0, adjustedSize.Width, adjustedSize.Height), source, GraphicsUnit.Pixel);
            }
            graphics.DrawImage(quadScaledBitmap, destination, new Rectangle(0, 0, quadScaledBitmap.Width, quadScaledBitmap.Height), GraphicsUnit.Pixel);
        }
    }

    public int[] Slice(int length)
    {
        int cornerLength = CornerLength;

        if (length <= (cornerLength * 2))
            throw new Exception("Image to small for sliceing up");

        int[] slices = new int[3];
        slices[0] = cornerLength;
        slices[1] = length - (2 * cornerLength);
        slices[2] = cornerLength;

        return slices;
    }
}
...