2

私はPDFアノテーターを作成しています。ページを切り替えると、以前に描画されたすべてのOpenGLコンテンツ(JSON形式でファイルに保存されたもの)を再描画する必要があります。問題は、描画するコンテンツが多いほど時間がかかることです。ページごとにUIImageをディスクに保存しているので、そのUIImageをEAGLContextに1回の大きなストロークで描画することで、このプロセスを高速化したいと考えていました。

UIImage(またはJPEG / PNGファイル)を取得して画面に直接描画する方法を知りたいです。EAGLViewに配置する必要がある理由は、消しゴムをサポートする必要があり、通常のUIKitの方法を使用しても機能しないためです。

画像全体としてブラシを設定し、画面に一度だけスタンプを押す方法があると思います。助言がありますか?

4

1 に答える 1

3

衒学的な注意として、EAGLViewという名前の標準クラスはありませんが、OpenGLESコンテンツをホストするAppleのサンプルUIViewサブクラスの1つを参照していると思います。

これを行うための最初のステップは、UIImageをテクスチャにロードすることです。newImageSource以下は、画像処理フレームワーク(入力UIImage)でこれに使用したコードです。

CGSize pointSizeOfImage = [newImageSource size];
CGFloat scaleOfImage = [newImageSource scale];
pixelSizeOfImage = CGSizeMake(scaleOfImage * pointSizeOfImage.width, scaleOfImage * pointSizeOfImage.height);
CGSize pixelSizeToUseForTexture = pixelSizeOfImage;

BOOL shouldRedrawUsingCoreGraphics = YES;

// For now, deal with images larger than the maximum texture size by resizing to be within that limit
CGSize scaledImageSizeToFitOnGPU = [GPUImageOpenGLESContext sizeThatFitsWithinATextureForSize:pixelSizeOfImage];
if (!CGSizeEqualToSize(scaledImageSizeToFitOnGPU, pixelSizeOfImage))
{
    pixelSizeOfImage = scaledImageSizeToFitOnGPU;
    pixelSizeToUseForTexture = pixelSizeOfImage;
    shouldRedrawUsingCoreGraphics = YES;
}

if (self.shouldSmoothlyScaleOutput)
{
    // In order to use mipmaps, you need to provide power-of-two textures, so convert to the next largest power of two and stretch to fill
    CGFloat powerClosestToWidth = ceil(log2(pixelSizeOfImage.width));
    CGFloat powerClosestToHeight = ceil(log2(pixelSizeOfImage.height));

    pixelSizeToUseForTexture = CGSizeMake(pow(2.0, powerClosestToWidth), pow(2.0, powerClosestToHeight));

    shouldRedrawUsingCoreGraphics = YES;
}

GLubyte *imageData = NULL;
CFDataRef dataFromImageDataProvider;

if (shouldRedrawUsingCoreGraphics)
{
    // For resized image, redraw
    imageData = (GLubyte *) calloc(1, (int)pixelSizeToUseForTexture.width * (int)pixelSizeToUseForTexture.height * 4);

    CGColorSpaceRef genericRGBColorspace = CGColorSpaceCreateDeviceRGB();    
    CGContextRef imageContext = CGBitmapContextCreate(imageData, (int)pixelSizeToUseForTexture.width, (int)pixelSizeToUseForTexture.height, 8, (int)pixelSizeToUseForTexture.width * 4, genericRGBColorspace,  kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
    CGContextDrawImage(imageContext, CGRectMake(0.0, 0.0, pixelSizeToUseForTexture.width, pixelSizeToUseForTexture.height), [newImageSource CGImage]);
    CGContextRelease(imageContext);
    CGColorSpaceRelease(genericRGBColorspace);
}
else
{
    // Access the raw image bytes directly
    dataFromImageDataProvider = CGDataProviderCopyData(CGImageGetDataProvider([newImageSource CGImage]));
    imageData = (GLubyte *)CFDataGetBytePtr(dataFromImageDataProvider);
}    

glBindTexture(GL_TEXTURE_2D, outputTexture);
if (self.shouldSmoothlyScaleOutput)
{
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int)pixelSizeToUseForTexture.width, (int)pixelSizeToUseForTexture.height, 0, GL_BGRA, GL_UNSIGNED_BYTE, imageData);

if (self.shouldSmoothlyScaleOutput)
{
    glGenerateMipmap(GL_TEXTURE_2D);
}

if (shouldRedrawUsingCoreGraphics)
{
    free(imageData);
}
else
{
    CFRelease(dataFromImageDataProvider);
}

ご覧のとおり、これには、デバイスの最大テクスチャサイズを超える画像のサイズを変更するためのいくつかの関数(上記のコードのクラスメソッドは単に最大テクスチャサイズをクエリするだけです)と、ミップマップを生成するかどうかのブールフラグがありますよりスムーズなダウンサンプリングのためのテクスチャー。これらのケースを気にしない場合は、これらを削除できます。これもOpenGLES2.0コードであるためOES、1.1で機能させるには、上記の関数の一部に追加する必要のあるサフィックスが1つか2つある場合があります。

UIImageをテクスチャに配置したら、テクスチャクワッド(長方形を構成する2つの三角形、コーナーに適切なテクスチャ座標)を使用して、UIImageを画面に描画できます。これを行う方法は、OpenGLES1.1と2.0で異なります。2.0の場合は、テクスチャ内のその場所から色を読み取り、それを画面に描画するパススルーシェーダープログラムを使用します。1.1の場合は、ジオメトリのテクスチャ座標を設定し、2つの三角形を描画します。

この回答には、このためのOpenGLES2.0コードがいくつかあります。

于 2012-08-14T18:50:08.983 に答える