Отрисовка CGImage в контексте Bitmap с заранее нарисованным UIBezierPath в контексте

это мой первый вопрос, так что терпите меня!

Я пытаюсь написать простое приложение для рисования в основном, я использовал Core Graphics раньше, и единственная проблема заключалась в том, что оно было слишком медленным, и когда я рисовал пальцем, оно отставало, черт возьми!

Итак, теперь я пытаюсь использовать пути UIBezier для рисования, как я понял, это намного быстрее, и это так!

Когда я использовал Core Graphics, чтобы поддерживать скорость рисования, я рисовал в созданном мной настраиваемом контексте растрового изображения, который постоянно обновлялся по мере того, как я рисовал.

Итак, я нарисовал свой собственный контекст Bitmap, затем CGImageRef был установлен на то, что было нарисовано в этом контексте, используя -

cacheImage = CGBitmapContextCreateImage(imageContext); 

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

CGContextDrawImage(imageContext, self.bounds, cacheImage); )

Я также сделал это, чтобы, когда я изменил цвет рисуемой линии, остальная часть рисунка осталась такой же, как была нарисована ранее, если это имеет смысл.

Проблема, с которой я столкнулся, заключается в следующем.

Я пытаюсь нарисовать путь UIBezier к моему контексту изображения, используя -

imageContext = UIGraphicsGetCurrentContext();

UIGraphicsPushContext(imageContext);


[path stroke];


if(imageContext != nil){
    cacheImage = CGBitmapContextCreateImage(imageContext);  //invalid context here so added to solve

}


CGContextScaleCTM(imageContext, 1, -1); // using this as UIBezier 

CGContextDrawImage(imageContext, self.bounds, cacheImage); // draws the current context;

[path removeAllPoints];

CGImageRelease(cacheImage); // releases the image to solve memory errors.

с путем, являющимся моим UIBezierPath. Все настройки пути выполняются в начале касания и перемещении касания с последующим вызовом [self setNeedsDisplay]; вызвать drawRect.

Что происходит, когда я рисую, он либо не рисует CGImageRef в контексте должным образом, либо это так, но когда он захватывает изображение кеша, он захватывает откуда-то белый фон, а не только путь, и поэтому его вставка по всему изображение с последним контуром, нарисованным вместе с белой заливкой фона, поэтому вы не можете увидеть последний путь, который был нарисован для построения изображения, даже если цвет фона представлений - clearColor.

Я действительно надеюсь, что у меня есть смысл, я просто потратил на это слишком много часов, и это полностью меня истощило. Вот метод рисования, который я использую -

Это для создания контекста изображения -

 -(CGContextRef) myCreateBitmapContext: (int) pixelsWide:(int) pixelsHigh{


    imageContext = NULL;

    CGColorSpaceRef colorSpace; // creating a colorspaceref
    void *          bitmapData; // creating bitmap data
    int             bitmapByteCount; // the bytes per count
    int             bitmapBytesPerRow; // number of bytes per row

    bitmapBytesPerRow   = (pixelsWide * 4); // calculating how many bytes per row the context     needs
    bitmapByteCount     = (bitmapBytesPerRow * pixelsHigh); // how many bytes there are in     total

    colorSpace = CGColorSpaceCreateDeviceRGB(); // setting the colourspaceRef

    bitmapData = malloc( bitmapByteCount ); // calculating the data

    if (bitmapData == NULL)
    {
        //NSLog(@"Memory not allocated!");
        return NULL;
    }


    imageContext = CGBitmapContextCreate (bitmapData,
                                          pixelsWide,
                                          pixelsHigh,
                                          8, // bits per component
                                          bitmapBytesPerRow,
                                          colorSpace,kCGImageAlphaPremultipliedLast);

    if (imageContext== NULL)
    {
        free (bitmapData);
        NSLog(@"context not created allocated!");
        return NULL;
    }
    CGColorSpaceRelease( colorSpace ); //releasing the colorspace

    CGContextSetRGBFillColor(imageContext, 1.0, 1.0, 1.0, 0.0); // filling the bitmap with a     white background
    CGContextFillRect(imageContext, self.bounds);
    CGContextSetShouldAntialias(imageContext, YES); 




    return imageContext; 
    }

И вот мой рисунок -

 -(void)drawRect:(CGRect)rect
{

    DataClass *data = [DataClass sharedInstance];



    [data.lineColor setStroke];
    [path setLineWidth:data.lineWidth];
    imageContext = UIGraphicsGetCurrentContext();

    UIGraphicsPushContext(imageContext);


    [path stroke];


    if(imageContext != nil){
        cacheImage = CGBitmapContextCreateImage(imageContext);  
    }


    CGContextScaleCTM(imageContext, 1, -1); // this one


    CGContextDrawImage(imageContext, self.bounds, cacheImage); // draws the current     context;



    [path removeAllPoints];

    CGImageRelease(cacheImage); // releases the image to solve memory errors.



}





 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{


    DataClass *data = [DataClass sharedInstance];

    CGContextSetStrokeColorWithColor(imageContext, [data.lineColor CGColor]);

    ctr = 0;
    UITouch *touch2 = [touches anyObject];
    pts[0] = [touch2 locationInView:self];

}


 -(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {

    UITouch *touch = [touches anyObject];
    CGPoint p = [touch locationInView:self];


    ctr++;
    pts[ctr] = p;
    if (ctr == 4)
    {

        pts[3] = CGPointMake((pts[2].x + pts[4].x)/2.0, (pts[2].y + pts[4].y)/2.0); // move     the endpoint to the middle of the line joining the second control point of the first Bezier     segment and the first control point of the second Bezier segment
        [path moveToPoint:pts[0]];
        [path addCurveToPoint:pts[3] controlPoint1:pts[1] controlPoint2:pts[2]]; // add a     cubic Bezier from pt[0] to pt[3], with control points pt[1] and pt[2]
        //[data.lineColor setStroke];

        [self setNeedsDisplay];
        // replace points and get ready to handle the next segment
        pts[0] = pts[3];
        pts[1] = pts[4];
        ctr = 1;
    }
}


 -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{

    [path removeAllPoints];
    [self setNeedsDisplay];
    ctr = 0;
}

'path' - это мой UIBezierPath 'cacheImage' - это CGImageRef 'imageContext' - это CGContextRef

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

РЕДАКТИРОВАТЬ Также я каждый раз удаляю точки, чтобы ускорить рисование, просто чтобы вы знали!

Заранее спасибо :)


person thebigpeeler    schedule 02.11.2012    source источник


Ответы (1)


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

person justin    schedule 02.11.2012
comment
Не совсем уверен, что вы имеете в виду, на самом деле, я новичок в xcode, что действительно раздражает, так это то, что он отлично работает в графике Core, но только на старом iPod Touch 3-го поколения, что-то более новое заставляет его отставать, как сумасшедшее, я просто не понимаю, почему: / - person thebigpeeler; 03.11.2012
comment
в порядке. есть технология под названием CALayers, и я предложил вам отделить ваши инвариантные растровые изображения / изображения от ваших изменяющихся растровых изображений. делая это правильно, вы можете локализовать все обновления / перерисовки на то, что было изменено (и не более). Стоит задуматься: ваш ipod touch 3-го поколения, вероятно, имеет наименьшее количество видимых пикселей для отображения при представлении вашего приложения. Профилирование с помощью инструментов может помочь, но я уже указывал, что ваша программа, вероятно, тратит много времени на перерисовку. - person justin; 03.11.2012
comment
да, он, должно быть, тратит слишком много времени на рисование новых растровых изображений, что он делает после того, как каждый путь от точки к точке нарисован в моем предыдущем графическом коде Core. Итак, вы предлагаете создать сетку слоев и рисовать обновленные изображения только в тех прямоугольниках, которые были нарисованы? извините, я действительно новичок в этом. - person thebigpeeler; 03.11.2012
comment
Есть ли что-нибудь, что вы можете предложить с текущим кодом, который у меня выше? он работает хорошо, так как я могу просто перерисовать изображение после того, как нарисую путь пальцем, поэтому я мог просто нарисовать обновленное изображение при вызове touchesEnded, а затем удалить все точки на пути, если вы понимаете, иногда ужасно при объяснении вещей . - person thebigpeeler; 03.11.2012
comment
Я прочитал про рисунок основного графического слоя, и теперь я думаю, что понимаю вас! Я попробую :) Спасибо, что хорошо прочитали мой длинный вопрос и нашли время, чтобы помочь мне - person thebigpeeler; 03.11.2012
comment
На самом деле @thebigpeeler, я не предлагал плитку, хотя ее можно было бы эффективно использовать в этом контексте. все, что я предлагал в то время, - это разделить ваш неизменный материал на один или несколько слоев, а затем перебросить ваши живые обновления на другой слой. тогда вам нужно только сделать недействительным прямоугольник, который действительно изменяется. что означает, что это часто будет в несколько раз быстрее, потому что вам обычно нужно обновлять / перерисовывать / перекомпоновывать часть представления при каждом обновлении. это частично стратегия кэширования, а частично обновляется только то, что изменяется. рад, что вы выяснили, что сработало :) - person justin; 04.11.2012