iphone: применить текстуру к CGContextStrokePath - PullRequest
3 голосов
/ 09 июля 2011

Я ищу все вопросы и ответы в StackOverflow, но не могу получить желаемый результат.Я хотел бы использовать файл PNG, чтобы отображать как штрих в точке касания пользователя и перемещения.Это файл в формате PNG:

enter image description here

Но я сделал все, что касается StackOverflow, даже используя CGPatternRef, но у меня нет нужного результата.Результат, который я имею здесь:

enter image description here

Но результат, который я хочу получить, здесь:

enter image description here

Этот результат Iсделали в OpenGL ES, но я не могу сделать это в Core Graphics.Я думаю, что я могу использовать CGContextDrawImage в каждой точке, но этот способ вызывает низкую производительность, потому что я должен нарисовать изображение всех точек между 2 точками, которых коснулся пользователь.Я думаю, что вы сталкивались с этой проблемой раньше.Как вы думаете, я могу применить текстуру для рисования обводки, как это в Core Graphics?Я очень ценю.

Ответы [ 3 ]

4 голосов
/ 14 сентября 2011

Когда вы создаете линию, используя шаблон, она будет выглядеть как первое изображение, а не как второе. Линия - это просто мозаичное изображение текстуры, которое вы предоставляете, обрезанное в форме линии. У него нет возможности узнать, что вы хотели объединить круги, чтобы они выглядели как сплошная линия. Для этого вам, вероятно, следует просто нарисовать линию сплошного черного цвета.

Для тех, кто пытается получить узорную линию на первом изображении, есть отличное руководство, объясняющее, как это сделать здесь: http://blog.robertturrall.com/tag/cgcontextsetstrokepattern/

По сути, вам нужно:

// first define the pattern width and height
const float kPatternWidth = 8;
const float kPatternHeight = 8;

void DrawPatternCellCallback(void *info, CGContextRef cgContext) 
{
    // Create a CGImage and use CGContextDrawImage() to draw it into the graphics context provided by the callback function.
    UIImage *patternImage = [UIImage imageNamed:@"yourtextureimage.png"];
    CGContextDrawImage(cgContext, CGRectMake(0, 0, kPatternWidth, kPatternHeight), patternImage.CGImage);
}

Убедитесь, что в пустоте нет круглых скобок. Также убедитесь, что часть DrawPatternCellCallback находится перед drawRect, иначе она не будет работать.

Тогда вашему drawRect нужно следующее:

- (void)drawRect:(CGRect)rect {
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    const CGRect patternBounds = CGRectMake(0, 0, kPatternWidth, kPatternHeight);
    const CGPatternCallbacks kPatternCallbacks = {0, DrawPatternCellCallback, NULL};

    CGAffineTransform patternTransform = CGAffineTransformIdentity;
    CGPatternRef strokePattern = CGPatternCreate(
                                             NULL,
                                             patternBounds,
                                             patternTransform,
                                             kPatternWidth, // horizontal spacing
                                             kPatternHeight, // vertical spacing
                                             kCGPatternTilingNoDistortion,
                                             true,
                                             &kPatternCallbacks);
    CGFloat color1[] = {1.0, 1.0, 1.0, 1.0};

    CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(NULL);
    CGContextSetStrokeColorSpace(ctx, patternSpace);
    CGContextSetStrokePattern(ctx, strokePattern, color1);
    CGContextSetLineWidth(ctx, 4.0);
    CGContextDrawPath(ctx);

    // If you aren't using ARC:
    CGPatternRelease(strokePattern);
    strokePattern = NULL;
    CGColorSpaceRelease(patternSpace);
    patternSpace = NULL;
}
2 голосов
/ 01 января 2014

критическое ...

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

Вы почтиконечно, нужен код, подобный этому ...

float isf;
isf = [[UIScreen mainScreen] bounds].size.width / wholeImageWidth;

(это если вы рисуете полноэкранный режим; настраивайте очевидным образом, если рисуете в окне), где wholeImageWidth - реальная ширина редактируемого изображения.

затем, когда вы создаете шаблон обводки, вы используете его, как этот

CGAffineTransformScale( CGAffineTransformIdentity, isf, -isf)

, но, к сожалению, вам, возможно, придется пересобирать его по-разному для камеры и альбома.Так что-то вроде .......

if ( self.wasFromCameraNotAlbum )
  {
  strokePattern = CGPatternCreate(
     NULL,
     CGRectMake(0,0,wholeWidth,wholeHeight),

     CGAffineTransformConcat(
         CGAffineTransformScale( CGAffineTransformIdentity, isf, -isf),
         CGAffineTransformRotate( CGAffineTransformIdentity, 90*M_PI/180 )
         ),

     wholeWidth,wholeHeight,
     kCGPatternTilingNoDistortion, true, &kPatternCallbacks);
  }
else
  {
  strokePattern = CGPatternCreate(
     NULL,
     CGRectMake(0,0,wholeWidth,wholeHeight),

     CGAffineTransformScale( CGAffineTransformIdentity, isf, -isf),

     wholeWidth,wholeHeight,
     kCGPatternTilingNoDistortion, true, &kPatternCallbacks);
  }

Для поиска в Google это связано с камерой, вращением, iPhone 6+, iOS8, альбомом.


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

Это прекрасно работает в Xcode5 / iOS7 (это январь 2014 г.):

Вот несколько очень типичных кодов для рисованияэто рисует СИНИЙ ЛИНИИ:

-(void)drawRect:(CGRect)rect
{
[curImage drawAtPoint:CGPointMake(0, 0)];
CGPoint mid1 = midPoint(previousPoint1, previousPoint2); 
CGPoint mid2 = midPoint(currentPoint, previousPoint1);
CGContextRef context = UIGraphicsGetCurrentContext(); 
[self.layer renderInContext:context];
CGContextMoveToPoint(context, mid1.x, mid1.y);
CGContextAddQuadCurveToPoint(context,
  previousPoint1.x, previousPoint1.y, mid2.x, mid2.y); 
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, 20.0);

CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);

CGContextStrokePath(context);            
[super drawRect:rect];
}

Обратите внимание на вызов CGContextSetStrokeColorWithColor , который просто устанавливает линию в сплошную линию, в данном случае синий.

Следующим здесь являетсяидентичный кодНо мы заменяем эту одну строку кода всем кодом для рисования шаблона .(И есть также новая отдельная подпрограмма обратного вызова, которая тривиальна.)

Для ясности здесь только 15 строк кода, которые заменят одну простую строку кода StrokeColor:

const CGPatternCallbacks kPatternCallbacks = {0, simplePatternCallback, NULL};
CGFloat color1[] = {1.0, 1.0, 1.0, 1.0};
CGPatternRef strokePattern = CGPatternCreate(
    NULL,
    CGRectMake(0,0,100,100),
    CGAffineTransformIdentity,
    100,100,
    kCGPatternTilingNoDistortion,
    true,
    &kPatternCallbacks);
CGContextSetStrokeColorSpace(UIGraphicsGetCurrentContext(),
        CGColorSpaceCreatePattern(NULL););
CGContextSetStrokePattern(context, strokePattern, color1);
CGPatternRelease(strokePattern);
strokePattern = NULL;

Шаблон должен быть PNG в вашем проекте, который может быть, скажем, 100x100 пикселей, здесь он называется «pattern100100.png».

Опять я заменил 1 строку кода на 15 строк кода дляшаблон.(А также есть отдельная тривиальная функция обратного вызова.) Вот и все:

-(void)drawRect:(CGRect)rect
{
[curImage drawAtPoint:CGPointMake(0, 0)];
CGPoint mid1 = midPoint(previousPoint1, previousPoint2); 
CGPoint mid2 = midPoint(currentPoint, previousPoint1);
CGContextRef context = UIGraphicsGetCurrentContext(); 
[self.layer renderInContext:context];
CGContextMoveToPoint(context, mid1.x, mid1.y);
CGContextAddQuadCurveToPoint(context,
  previousPoint1.x, previousPoint1.y, mid2.x, mid2.y); 
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, 20.0);

const CGPatternCallbacks kPatternCallbacks = {0, simplePatternCallback, NULL};
CGFloat color1[] = {1.0, 1.0, 1.0, 1.0};
CGPatternRef strokePattern = CGPatternCreate(
    NULL,
    CGRectMake(0,0,100,100),
    CGAffineTransformIdentity,
    100,100,
    kCGPatternTilingNoDistortion,
    true,
    &kPatternCallbacks);
CGContextSetStrokeColorSpace(UIGraphicsGetCurrentContext(),
        CGColorSpaceCreatePattern(NULL););
CGContextSetStrokePattern(context, strokePattern, color1);
CGPatternRelease(strokePattern);
strokePattern = NULL;

CGContextStrokePath(context);            
[super drawRect:rect];
}

void simplePatternCallback(void *info, CGContextRef ctx)
{
UIImage *brushTexture = [UIImage imageNamed:@"pattern100100.png"];
CGContextDrawImage(ctx, CGRectMake(0, 0, 100,100), brushTexture.CGImage);
}

Несколько полезных комментариев для включения в код!

// re the final argument:
// from Apple doco: "If the specified pattern is a 'colored' pattern,
// pass an alpha value."
// in fact you have to pass in an array of four values.

// note, "stencil patterns" (aka "uncolored patterns") patterns
// are basically masks, rarely used

// re the "true" in CGPatternCreate, that means "coloured pattern"
// (ie not "stencil pattern")

Я действительно надеюсь, что это поможеткто-то.

ПРИМЕЧАНИЕ: всякий раз, когда вы видите подобные примеры кода (даже в Apple).Они всегда делают все это "внутри drawRect".Обратите внимание, что «strokePattern» действительно создается каждый раз, когда вызывается drawRect!Мне это кажется сумасшедшим, я всегда просто использую переменную или свойство для «strokePattern» и других элементов.Точно так же было бы смешно использовать imageNamed каждый раз при обратном вызове, просто использовать свойство, которое вы предварительно подготовили.

Опять же, я очень надеюсь, что это кому-то поможет.Приветствия


полезная сноска: в CGPaternCreate, пример кода показывает CGAffineTransformIdentity для аргумента три.

Часто вы используете какое-либо фото или другое динамическое изображение.В этом случае почти наверняка было бы ...

CGAffineTransformScale(CGAffineTransformIdentity,1,-1),

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

0 голосов
/ 15 января 2012

Спасибо за ссылку, llama591.

Haisergeant, если то, что вы ищете, это хорошая толстая линия, использующая текстуру, которая была у вас в первом примере, тогда вам нужно поиграться со значениями kPatternWidth и kPatternHeight, а также со значением, которое вы передаетечерез строку CGContextSetLineWidth (ctx, 4.0);.

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

...