Точное пиксельное наложение сетки в Core Graphics? - PullRequest
1 голос
/ 26 мая 2011

В своих экспериментах с созданием пиксельно-центрированного редактора изображений я пытался нарисовать точное наложение сетки, чтобы помочь пользователям при попытке доступа к определенным пикселям. Однако сетка, которую я рисую, не очень ровная, особенно при меньших размерах. Это обычный шаблон одного столбца чуть большего размера для каждых нескольких обычных столбцов, поэтому я думаю, что это проблема округления, но я не вижу ее в своем коде. Вот мой код:

    - (void)drawRect:(NSRect)dirtyRect
{
    context = [[NSGraphicsContext currentContext] graphicsPort];
    CGContextAddRect(context, NSRectToCGRect(self.bounds));
    CGContextSetRGBStrokeColor(context, 1.0f, 0.0f, 0.0f, 1.0f);
    CGContextStrokePath(context);
    CGContextSetInterpolationQuality(context, kCGInterpolationNone);
    CGContextSetShouldAntialias(context, NO);

    if (image)
    {

        NSRect imageRect = NSZeroRect;
        imageRect.size = CGImageGetSize([image CGImage]);
        drawRect = [self bounds];
        NSRect viewRect = drawRect;
        CGFloat aspectRatio = imageRect.size.width / imageRect.size.height;
        if (viewRect.size.width / viewRect.size.height <= aspectRatio)
        {
            drawRect.size.width = viewRect.size.width;
            drawRect.size.height = imageRect.size.height * (viewRect.size.width / imageRect.size.width);
        }
        else
        {
            drawRect.size.height = viewRect.size.height;
            drawRect.size.width = imageRect.size.width * (viewRect.size.height / imageRect.size.height);
        }

        drawRect.origin.x += (viewRect.size.width - drawRect.size.width) / 2.0;
        drawRect.origin.y += (viewRect.size.height - drawRect.size.height) / 2.0;

        CGContextDrawImage(context, drawRect, [image CGImage]);

        if (showPixelGrid)
        {
            //Draw grid by creating start and end points for vertical and horizontal lines.
            //FIXME: Grid is uneven, especially at smaller sizes. 
            CGContextSetStrokeColorWithColor(context, CGColorGetConstantColor(kCGColorBlack));
            CGContextAddRect(context, drawRect);
            CGContextStrokePath(context);
            NSUInteger numXPoints = (NSUInteger)imageRect.size.width * 2;
            NSUInteger numYPoints = (NSUInteger)imageRect.size.height * 2;
            CGPoint xPoints[numXPoints];
            CGPoint yPoints[numYPoints];
            CGPoint startPoint;
            CGPoint endPoint;
            CGFloat widthRatio = drawRect.size.width / imageRect.size.width;
            CGFloat heightRatio = drawRect.size.height / imageRect.size.height;
            startPoint.x  = drawRect.origin.x;
            startPoint.y = drawRect.origin.y;
            endPoint.x = drawRect.origin.x;
            endPoint.y = drawRect.size.height + drawRect.origin.y;
            for (NSUInteger i = 0; i < numXPoints; i += 2)
            {
                startPoint.x += widthRatio;
                endPoint.x += widthRatio;
                xPoints[i] = startPoint;
                xPoints[i + 1] = endPoint;
            }
            startPoint.x  = drawRect.origin.x;
            startPoint.y = drawRect.origin.y;
            endPoint.x = drawRect.size.width + drawRect.origin.x;
            endPoint.y = drawRect.origin.y;
            for (NSUInteger i = 0; i < numYPoints; i += 2)
            {
                startPoint.y += heightRatio;
                endPoint.y += heightRatio;
                yPoints[i] = startPoint;
                yPoints[i + 1] = endPoint;
            }
            CGContextStrokeLineSegments(context, xPoints, numXPoints);
            CGContextStrokeLineSegments(context, yPoints, numYPoints);
        }
    }

}

Есть идеи?

1 Ответ

7 голосов
/ 26 мая 2011

ОБНОВЛЕНИЕ: Мне удалось запустить ваш код с помощью нескольких настроек - откуда взялся CGImageGetSize ()?- и я действительно не вижу проблемы, кроме столбцов не все точно даже в очень маленьких размерах.Вот только как это должно работать.Единственный способ обойти это - либо исправить масштабирование, чтобы оно было кратным целому числу размера изображения - другими словами, получить наибольшее целое число, кратное размеру изображения, меньшему, чем размер представления, или уменьшить количество линий, нарисованных на экране, на оченьнебольшие размеры, чтобы избавиться от этого артефакта.Есть причина, по которой пиксельная сетка становится видимой только при большом увеличении в большинстве редакторов.Не говоря уже о том, что если сетка все еще видна с разрешением 3-4x, вы делаете просмотр слишком занятым.


Я не смог запустить предоставленный вами код, потому что есть куча классовивары там, но с беглого взгляда я бы сказал, что это как-то связано с рисованием на границах пикселей.После округления до целого числа, чтобы избавиться от нечетких артефактов АА (я заметил, что вы отключили АА, но в идеале вам не нужно этого делать), вам нужно добавить 0,5 к исходной точке, чтобы нарисовать линию в центр пикселя, а не на границе .

Примерно так:

+---X---+---+---+---+---+
|   |   |   | Y |   |   |
+---+---+---+---+---+---+

X : CGPoint (1, 1)
Y : CGPoint (3.5, 0.5)

Вы хотите нарисовать из центра пикселя,потому что в противном случае ваша линия пересекает два пикселя.

Другими словами, где вы устанавливаете xPoints и yPoints, убедитесь, что floor () или round () ваши значения, а затем добавьте 0.5.

...