ラベル Quartz Composer の投稿を表示しています。 すべての投稿を表示
ラベル Quartz Composer の投稿を表示しています。 すべての投稿を表示

2012年6月15日金曜日

画像からMeshをつくってみる

動機
OLM Digital R&D » モーフィング応用による2次元アニメーション http://www.olm.co.jp/rd/n-way-morphing/

画からMeshを作ってみようかなと思いつくままにやってみた.
入力画像(背景は透明)

微分フィルタにて境界とおぼしき点を探索

参考: ハフ変換を使わない画像のエッジ角度 - 無作為研究所 http://www.faicha.com/vision/02edgea/, 他
適当な点から最近傍をつないでいく(境界の赤色の点上の緑色の線)

参考(NSArrayの高階関数を用いるソート): Safx: Objective-C上でブロックオブジェクトによる高階関数を用いてソートする方法について http://safx-dev.blogspot.jp/2010/11/objective-c.html
とにかく三角形となるように埋めて行く(青色の線が三角形の群れ)

参考: Javaゲーム制作記 任意多角形の三角形分割 http://javaappletgame.blog34.fc2.com/blog-entry-148.html, 他
縮退三角形を間に常に挟む事でとにかく書き出す
var v= [
 { x:0.207031, y:0.937500, z:0.0 },
…
 { x:0.205078, y:0.933594, z:0.0 },
];
var i= [
 2170, 2169, 2168,
 2169, 2168, 2168,  2168, 2168, 2168,  2168, 2168, 2168,  2168, 2168, 2167,
 2168, 2167, 2166,
…
 1, 2, 3210,
 2, 3210, 3210,  3210, 3210, 1,  3210, 1, 1,  1, 1, 3210,
 1, 3210, 0,
];
function (__structure v,__structure i) main ()
{
 var result = new Object();
 result.v= v;
 result.i= i;
 return result;
}

参考: 縮退三角形(Degenerate triangle)による最適化 - 強火で進め http://d.hatena.ne.jp/nakamura001/20100111/1263219309
書き出したコードをJavascriptパッチに入れてMesh Creater/Mesh Rendererに任せてみる


yone80さんのGLSL Shader(vertNoise)をかぶせてみる

2012年4月20日金曜日

Quartz Composer: MacPortsで入れたOpenCV2.2に関するパッチを作るテンプレート的なナニカ

たぶんもっと良い方法がある.けどメモ.
MacPortsでopencv 2.xを入れて/opt/local下に入っている前提


  • 'Project Navigator'内ルート要素を選択

    • PROJECTのBuild Settingsを開き,表示をAllとする.

      1. 'Search Paths'内の'Header Search Paths'に'/opt/local/include'を加える.

    • TARGETSのBuild Phasesを開く.

      1. 'Library Binary With Libraries'を選択し展開する.
      2. '+'ボタンを押し'Add Other …'にて直接ファイル選択を行う.
      3. /opt/local/libs以下にある'libopencv_'で始まるdylibを全て加える.

        • ('/opt/local'あたりをFinderの左ペインに加えておくと楽)



  • '.m'ファイルを'.mm'に変更する.


  • #import <opencv2/opencv.hpp>

    @implementation OpenCV_XXXPlugIn

    @dynamic inputSourceImage;
    @dynamic outputResultImage;

    @end
    @implementation OpenCV_XXXPlugIn (Execution)

    static void _BufferReleaseCallback(const void* address, void* info)
    {
    }
    +(cv::Mat)CVMatWithQCPlugInInputImageSource:(id <QCPlugInInputImageSource>)image
    {
    CGFloat cols = [image bufferPixelsWide];
    CGFloat rows = [image bufferPixelsHigh];
    cv::Mat cvMat(rows, cols, CV_8UC4);
    cvMat.data= (uchar *)[image bufferBaseAddress];
    return cvMat;
    }
    - (BOOL)execute:(id <QCPlugInContext>)context atTime:(NSTimeInterval)time withArguments:(NSDictionary *)arguments
    {
    id inputImage= self.inputSourceImage;
    self.outputResultImage = nil;

    if(inputImage) {
    if(![inputImage lockBufferRepresentationWithPixelFormat:QCPlugInPixelFormatBGRA8
    colorSpace:[inputImage imageColorSpace]
    forBounds:[inputImage imageBounds]]) {
    return NO;
    }
    cv::Mat src_img= [OpenCV_XXXPlugIn CVMatWithQCPlugInInputImageSource:inputImage];
    cv::Mat dst_img(src_img.size(), src_img.type());


    src_img.copyTo(dst_img);


    id <QCPlugInOutputImageProvider> provider= [context outputImageProviderFromBufferWithPixelFormat:QCPlugInPixelFormatBGRA8
    pixelsWide:dst_img.cols
    pixelsHigh:dst_img.rows
    baseAddress:dst_img.data
    bytesPerRow:dst_img.cols*dst_img.channels()
    releaseCallback:_BufferReleaseCallback
    releaseContext:NULL
    colorSpace:[inputImage imageColorSpace]
    shouldColorMatch:YES];

    if(provider == nil)
    return NO;

    self.outputResultImage = provider;

    [inputImage unlockBufferRepresentation];
    }
    return YES;
    }

    @end

2012年3月8日木曜日

Quartz Composer / GLSL Shader / BokehなFragment Shaderを生成するコード

参考
  • THE ART-LOG OF MARTINS UPITIS: a GLSL depth of field filter with bokeh
  • GLSL depth of field with bokeh v2.4 (update)


  • コード
    参考のコード他をよくわからないまま弄くり回していました.
    とりあえずサンプリングする点を求めるのにコードにしたのでそれをメモしておきます.

    #include <stdio.h>
    #include <stdlib.h>
    double *cross(double *p, double *q) {
    double *r;
    r= (double *)malloc(3*sizeof(double));
    r[0]= p[1]*q[2]-p[2]*q[1];
    r[1]=-p[0]*q[2]+p[2]*q[0];
    r[2]= p[0]*q[1]-p[1]*q[0];
    return r;
    }
    double *sub(double *p, double *q) {
    double *r;
    r= (double *)malloc(3*sizeof(double));
    r[0]= p[0]-q[0];
    r[1]= p[1]-q[1];
    r[2]= p[2]-q[2];
    return r;
    }
    int isinCircle(double *q) {
    return (q[0]*q[0]+q[1]*q[1]<0.25)?1:0;
    }
    int isin6(double *q)
    {
    double p[6][3]= {
    { 0.0, 0.50, 0.},
    { 0.5, 0.25, 0.},
    { 0.5,-0.25, 0.},
    { 0.0,-0.50, 0.},
    {-0.5,-0.25, 0.},
    {-0.5, 0.25, 0.}};
    double *r;
    int i, c= 0;

    for(i= 0; i<5; i++) {
    r= cross(sub(p[i], q), sub(p[i+1], q));
    c+= r[2]<0?0:1;
    }
    r= cross(sub(p[5], q), sub(p[0], q));
    c+= r[2]<0?0:1;

    return (c==0)?1:0;
    }
    int main(int argc, char* argv[]) {

    double q[3]= {0., 0., 0.};
    int j,k,c= 0;
    int r= 5;

    printf("uniform sampler2D RenderedTexture;\nuniform sampler2D DepthTexture;\n");
    printf("const float blurclamp = 1.;\nconst float bias = 10.;\nuniform float focus;\n");
    printf("uniform float pixelsWide;\nuniform float pixelsHigh;\n");
    printf("vec2 texcel = vec2(1./pixelsWide, 1./pixelsHigh);\n");
    printf("void main()\n{\n");
    printf("\tvec4 depth = texture2D(DepthTexture,gl_TexCoord[0].xy );\n");
    printf("\tfloat factor = ( depth.x - focus );\n");
    printf("\tvec2 dofblur = vec2 (clamp( factor * bias, -blurclamp, blurclamp ));\n");
    printf("\tvec4 col = vec4(0.0);\n");

    for(k= -r; k<r; k++) {
    for(j= -r; j<r; j++) {
    q[0]= k/(r*2.);
    q[1]= j/(r*2.);
    if (isin6(q)==1) {
    if (0) {
    printf("\tcol += texture2D(RenderedTexture, gl_TexCoord[0].xy + (vec2(");
    printf("%2d., %2d.", k, j);
    printf(")*texcel) * dofblur);\n");
    }
    else {
    printf("\tcol.r += texture2D(RenderedTexture, gl_TexCoord[0].xy + (vec2(");
    printf("%2d., %2d.", k, j);
    printf(")*texcel) * dofblur*vec2( .000, .50)).r;\n");
    printf("\tcol.g += texture2D(RenderedTexture, gl_TexCoord[0].xy + (vec2(");
    printf("%2d., %2d.", k, j);
    printf(")*texcel) * dofblur*vec2( .866,-.25)).g;\n");
    printf("\tcol.b += texture2D(RenderedTexture, gl_TexCoord[0].xy + (vec2(");
    printf("%2d., %2d.", k, j);
    printf(")*texcel) * dofblur*vec2(-.866,-.25)).b;\n");
    }
    c++;
    }
    }
    }

    printf("\tgl_FragColor = col/%d.;\n\tgl_FragColor.a = 1.0;\n}\n", c);
    return 0;
    }



    結果
    こんな感じ.

    2012年3月1日木曜日

    Quartz Composer / GLSL Shader / 凸多角形の内外判定

    参考
    外積の使い方 - Tari Lari Run


    やってみた

    //Fragment Shader
    uniform sampler2D texture;

    void main()
    {
    vec3 q= vec3(gl_TexCoord[0].xy+vec2(-0.5,-0.5), 0.);

    int n= 6;
    vec3 p[6];
    //反時計回りの定義
    p[0]= vec3( 0.0, 0.50, 0.);
    p[1]= vec3( 0.5, 0.25, 0.);
    p[2]= vec3( 0.5, -0.25, 0.);
    p[3]= vec3( 0.0, -0.50, 0.);
    p[4]= vec3(-0.5, -0.25, 0.);
    p[5]= vec3(-0.5, 0.25, 0.);

    int c= 0;
    for(int i=0; i<n; i++) {
    c+= cross(p[i]-q, p[(i+1)%n]-q).z>0.?0:1; //pが時計回りなら z>0?1:0
    }

    gl_FragColor = (c==n)?vec4(0):vec4(1);
    gl_FragColor.a= 1.;
    }

  • Vertex Shader側はQuartz ComposerのGLSL Shaderのデフォルトのまま
  • Shader内はGLSL Gridを置いてある


  • 結果

    (多角形の頂点を0.9倍して余白をつくってある)

    2011年11月15日火曜日

    Quartz Composer / Crosshatch shader をやってみた (あとiPod CMを思い出して)

    動機
    @yone80さんがPOSTした こちらの記事を参考にGLSL Shader パッチでやってみた.


    結果


    iPod CM
    で,ふと古いiPod CMを思い出してMMD_DM_Renderパッチに白黒反転したこのGLSL Shaderパッチをかぶせてみた.




    pmd: 'Lat式ミクVer2.3_Normal.pmd'(Lat様)('VPVP wiki - モデルデータ/VOCALOID関連'より),
    vmd: '恋愛サーキュレーション-ミク.vmd'(せっけんP様)('VPVP wiki - モーションデータ/ダンス'より)
    感謝 )
    ※Clickすると拡大します.

    っぽい?

    2011年10月29日土曜日

    Quartz Composer / Box2DJSをCustom Javascript Patch内で動かすことでQCで物理エンジンしてみた

    追記(20111101): この記事のままだと姿勢(回転)の値がとれていません.姿勢を反映した版( Box2DJS_Demo_Stack_With_Rotate.qtz
    )をこちらからdownloadしていただきコードを確認してください.



    結果








    Video streaming by Ustream

    Box2DJS - Physics Engine for JavaScript


    Custom Javascriptの中身

    //import /Users/work/Desktop/box2d-js_0.1.0/lib/prototype-1.6.0.2.js

    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/common/b2Settings.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/common/math/b2Vec2.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/common/math/b2Mat22.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/common/math/b2Math.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/b2AABB.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/b2Bound.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/b2BoundValues.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/b2Pair.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/b2PairCallback.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/b2BufferedPair.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/b2PairManager.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/b2BroadPhase.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/b2Collision.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/Features.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/b2ContactID.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/b2ContactPoint.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/b2Distance.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/b2Manifold.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/b2OBB.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/b2Proxy.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/ClipVertex.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/shapes/b2Shape.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/shapes/b2ShapeDef.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/shapes/b2BoxDef.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/shapes/b2CircleDef.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/shapes/b2CircleShape.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/shapes/b2MassData.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/shapes/b2PolyDef.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/collision/shapes/b2PolyShape.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/b2Body.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/b2BodyDef.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/b2CollisionFilter.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/b2Island.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/b2TimeStep.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/contacts/b2ContactNode.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/contacts/b2Contact.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/contacts/b2ContactConstraint.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/contacts/b2ContactConstraintPoint.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/contacts/b2ContactRegister.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/contacts/b2ContactSolver.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/contacts/b2CircleContact.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/contacts/b2Conservative.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/contacts/b2NullContact.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/contacts/b2PolyAndCircleContact.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/contacts/b2PolyContact.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/b2ContactManager.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/b2World.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/b2WorldListener.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2JointNode.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2Joint.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2JointDef.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2DistanceJoint.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2DistanceJointDef.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2Jacobian.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2GearJoint.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2GearJointDef.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2MouseJoint.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2MouseJointDef.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2PrismaticJoint.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2PrismaticJointDef.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2PulleyJoint.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2PulleyJointDef.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2RevoluteJoint.js
    //import /Users/work/Desktop/box2d-js_0.1.0/js/box2d/dynamics/joints/b2RevoluteJointDef.js

    //import /Users/work/Desktop/box2d-js_0.1.0/demos/demo_base.js
    //import /Users/work/Desktop/box2d-js_0.1.0/demos/stack.js

    //output QCPortTypeStructure posYs
    //output QCPortTypeStructure posXs

    //input QCPortTypeNumber foo
    //input QCPortTypeBoolean init
    //output QCPortTypeNumber dummy

    var world = createWorld();
    demos.InitWorlds[0](world);

    function main(foo, init) {
    if (init) {
    world = createWorld();
    demos.InitWorlds[0](world);
    }
    world.Step(1.0/60, 1);
    var aryX= new Array();
    var aryY= new Array();
    for (var b = world.m_bodyList; b; b = b.m_next) {
    for (var s = b.GetShapeList(); s != null; s = s.GetNext()) {
    var pos= s.m_position;
    aryX.push(pos.x);
    aryY.push(pos.y);
    }
    }
    var ret= new Object();
    ret.posXs= aryX;
    ret.posYs= aryY;
    ret.dummy= foo;
    return ret;
    }


    QC
    描画部

    fooはCustom JavaScriptを動かし続けるため(時刻で処理するパッチにしてないので).
    CountはposXs等のCountで良いのだがDemoのデータに動かない要素が入っていたのでそのあたりを使わないため.

    描画部(Iteratorの中)

    割り算はスケール合わせ用


    Box2DJS: Box2DJS - Physics Engine for JavaScript

    Custom Javascript Patch: Custom Javascript Patch - quartz composerのパッチとか

    2011年8月20日土曜日

    Quartz Composer / Automator / AutomatorのパッチでQCRender関連のナンカを実装してみた

    動機
    これをやったのでこれ的なQCRenderネタをやってみようかと安易に思った('Quartz コンポジションフィルタをイメージに適用'ってパッチが既にありますが).


    やってみた
    0.プロジェクトの作成
    プロジェクトの修正等はこちらを参照下さい
    xibのFile's Ownerのクラスも上記と同じクラス名で修正する(こちらの3.xibを編集を参照のこと).
    OpenGLとQuartzのframeworkを追加した.


    1.コード

    #import <Automator/AMBundleAction.h>
    #import <Quartz/Quartz.h>

    @interface QuartzComposer : AMBundleAction

    - (id)runWithInput:(id)input fromAction:(AMAction *)anAction error:(NSDictionary **)errorInfo;

    - (IBAction)openQTZ:(id)sender;

    @end



    #import "QuartzComposer.h"

    @implementation QuartzComposer
    - (IBAction)openQTZ:(id)sender
    {
    NSString *compositionPath= [[NSBundle bundleForClass:[self class]] pathForResource:@"composition" ofType:@"qtz"];
    [[NSWorkspace sharedWorkspace] openFile:compositionPath withApplication:@"Quartz Composer"];
    }

    - (id)runWithInput:(id)input fromAction:(AMAction *)anAction error:(NSDictionary **)errorInfo
    {
    NSUInteger width= 16;
    NSUInteger height= 16;
    NSString *compositionPath= [[NSBundle bundleForClass:[self class]] pathForResource:@"composition" ofType:@"qtz"];

    QCRenderer *renderer= nil;
    {
    NSOpenGLPixelFormatAttribute attributes[]= {
    NSOpenGLPFAPixelBuffer,
    NSOpenGLPFANoRecovery,
    NSOpenGLPFAAccelerated,
    NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)24,
    NSOpenGLPFASampleBuffers, (NSOpenGLPixelFormatAttribute)1,
    NSOpenGLPFASamples, (NSOpenGLPixelFormatAttribute)16,
    (NSOpenGLPixelFormatAttribute)0
    };
    NSOpenGLPixelFormat *format= [[[NSOpenGLPixelFormat alloc] initWithAttributes:attributes] autorelease];
    NSOpenGLPixelBuffer *pixelBuffer= [[NSOpenGLPixelBuffer alloc] initWithTextureTarget:GL_TEXTURE_RECTANGLE_EXT
    textureInternalFormat:GL_RGBA
    textureMaxMipMapLevel:0
    pixelsWide:width
    pixelsHigh:height];

    NSOpenGLContext *openGLContext= [[NSOpenGLContext alloc] initWithFormat:format shareContext:nil];
    if(pixelBuffer == nil || openGLContext == nil) {
    NSLog(@"no buffer or no context");
    return nil;
    }

    [openGLContext setPixelBuffer:pixelBuffer
    cubeMapFace:0
    mipMapLevel:0
    currentVirtualScreen:[openGLContext currentVirtualScreen]];

    renderer= [[QCRenderer alloc] initWithOpenGLContext:openGLContext pixelFormat:format file:compositionPath];
    }

    NSMutableArray *outputPaths= [NSMutableArray array];
    if(renderer) {
    NSMutableArray *inputPaths= [NSMutableArray array];
    if ([input isKindOfClass:[NSArray class]]) {
    [inputPaths addObjectsFromArray:input];
    }
    else if ([input isKindOfClass:[NSString class]]) {
    [inputPaths addObject:input];
    }
    int i;
    for(i=0;i<[inputPaths count];i++) {
    NSString *inputPath= [inputPaths objectAtIndex:i];
    NSImage *inputImage= [[[NSImage alloc] initWithContentsOfFile:inputPath] autorelease];
    [renderer setValue:inputImage forInputKey:@"InputImage"];

    if(![renderer renderAtTime:0.0 arguments:nil]) {
    NSLog(@"no rendering");
    return nil;
    }
    [renderer createSnapshotImageOfType:@"NSBitmapImageRep"];

    NSImage *image= (NSImage *)[renderer valueForOutputKey:@"OutputImage"];
    NSBitmapImageRep *bitmapImage= [NSBitmapImageRep imageRepWithData:[image TIFFRepresentation]];
    if(bitmapImage) {
    char *tempNameBytes = tempnam([NSTemporaryDirectory() fileSystemRepresentation], "QCComposition_Result_");
    NSString *tempName = [[[NSString alloc] initWithBytesNoCopy:tempNameBytes
    length:strlen(tempNameBytes)
    encoding:NSUTF8StringEncoding
    freeWhenDone:YES] autorelease];
    NSString *outputPath= [tempName stringByAppendingPathExtension:@"png"];


    NSDictionary *properties= [NSDictionary dictionaryWithObjectsAndKeys:
    [NSNumber numberWithFloat:1.0], NSImageCompressionFactor,
    nil];
    NSData *pngImageData= [bitmapImage representationUsingType:NSPNGFileType
    properties:properties];

    [pngImageData writeToFile:outputPath
    atomically:YES];
    [outputPaths addObject:outputPath];
    }
    }
    }
    else {
    NSLog(@"no render");
    }

    return outputPaths;
    }

    @end


    2.composition.qtzを作成する
    Quartz Composerで作成する.この際にInputImageというPublished InputとOutputImageというPublished Outputを用意する.


    3.Supporting Files(リソース)にコンポジション(composition.qtz)を加える
    Build PhasesのCopy Bundle Resourcesに含まれていること.


    4.Viewまわり
    xlbにボタンを配置して(IBAction)openQTZ:に繋ぐ.


    あとはBuildして配置(~/Library/Automator/下).



    結果


    Motion Blurなのでこんな感じ.

    2011年8月9日火曜日

    Quartz Composer / Settings の Viewをプロジェクトに追加する方法のメモ

    動機
    しばらく前からXcodeのプロジェクトテンプレートにQuartz Composer Plug-in(Patch) プロジェクト 「Settings View有り」が選べなくなってた.未来の自分の為に追加の仕方(正しいかわからないが)をまとめておく(既にどこかにある?).


    やってみた
    1.プロジェクトを作る.


    名前をSettngViewDemoとした(Settingsだったね…。).

    xibはない.


    2.xibを追加



    名前をSettingとした(Settingsだったね…。).


    3.xibを編集
    File's OwnerのClassを変更("QCPlugInViewController")


    とりあえず確認用にButtonを置いてみた.

    File's OwnerからCustom Viewを繋いで…


    (File's Ownerの)view OutletへCustom Viewを接続.


    確認.



    4.コードに追加
    @implementation SettingViewDemoPlugIn
    

    - (QCPlugInViewController*) createViewController
    {
    return [[QCPlugInViewController alloc] initWithPlugIn:self
    viewNibName:@"Setting"];
    }

    @end

    Settingはxibのファイル名

    5.コンパイル/インストール
    Build for Running



    確認



    利用する時は“File's Owner”の“plugIn.XXXXX”にバインドしてつかう.これがQCPlugInのプロパティ(getter/detter)に繋がる.

    2011年7月31日日曜日

    Quartz Composer / WebViewの画像を取得するパッチ 修正版

    前提
    前の版

    問題や課題(?)
    問題
  • 色が合わない(赤と青が入れ替わっている RGBA(BitmapImageRep)→BGRA(OutputImageProvider))
  • 大きい画像から小さい画像に切り替えた際に以前の画像サイズのままになることがある
    課題
  • Download終了時の画像のみでアニメーションしない
    ということで修正してみた.


  • やってみた
    WebViewPlugIn.h

    #import <Quartz/Quartz.h>
    #import <Webkit/WebKit.h>

    @interface WebViewPlugIn : QCPlugIn {
    @private
    WebView *aWebView;
    WebFrameView *aWebFrameView;
    NSString *oldURL;
    NSBitmapImageRep *aBitmapImageRep;
    }

    @property(assign) NSString *inputURL;
    @property(assign) id<QCPlugInOutputImageProvider> outputImage;
    @end


    WebViewPlugIn.m

    #import <OpenGL/CGLMacro.h>
    #import "WebViewPlugIn.h"

    #define kQCPlugIn_Name @"WebView"
    #define kQCPlugIn_Description @"WebView description"

    @implementation WebViewPlugIn
    @dynamic inputURL;
    @dynamic outputImage;
    + (NSDictionary *)attributes
    {
    return [NSDictionary dictionaryWithObjectsAndKeys:
    kQCPlugIn_Name, QCPlugInAttributeNameKey,
    kQCPlugIn_Description, QCPlugInAttributeDescriptionKey,
    nil];
    }

    + (NSDictionary *)attributesForPropertyPortWithKey:(NSString *)key
    {
    return nil;
    }

    + (QCPlugInExecutionMode)executionMode
    {
    return kQCPlugInExecutionModeProvider;
    }

    + (QCPlugInTimeMode)timeMode
    {
    return kQCPlugInTimeModeIdle;
    }

    - (id)init
    {
    self = [super init];
    if (self) {
    NSRect r= NSMakeRect(0,0, 16, 16);
    aWebView= [[WebView alloc] initWithFrame:r
    frameName:nil
    groupName:nil];
    NSWindow *w= [[NSWindow alloc] init];
    [w setContentView:aWebView];
    [w setFrame:r display:YES];
    [aWebView setFrameLoadDelegate:self];
    aWebFrameView= [[aWebView mainFrame] frameView];
    }
    return self;
    }
    - (void)finalize
    {
    [super finalize];
    }
    - (void)dealloc
    {
    [aWebView release];
    [oldURL release];
    [super dealloc];
    }
    @end
    @implementation WebViewPlugIn (Execution)
    - (BOOL)startExecution:(id <QCPlugInContext>)context
    {
    return YES;
    }
    - (void)enableExecution:(id <QCPlugInContext>)context
    {
    }
    static void _BufferReleaseCallback(const void* address, void* info)
    {
    CGContextRelease(info);
    }
    - (BOOL)execute:(id <QCPlugInContext>)context atTime:(NSTimeInterval)time withArguments:(NSDictionary *)arguments
    {
    if (![oldURL isEqualToString:self.inputURL]) {
    [[aWebView window] setContentSize:NSMakeSize(16,16)];
    [aWebView setMainFrameURL:self.inputURL];

    [oldURL release];
    oldURL= [self.inputURL retain];
    [aBitmapImageRep release];
    aBitmapImageRep= nil;
    }

    if (aBitmapImageRep!=nil) {
    [aWebFrameView lockFocus];
    [aWebFrameView cacheDisplayInRect:[aWebFrameView bounds] toBitmapImageRep:aBitmapImageRep];
    [aWebFrameView unlockFocus];

    NSSize aSize= [aBitmapImageRep size];

    NSUInteger i;
    char *p= (char *)[aBitmapImageRep bitmapData];
    for(i= 0; i<[aBitmapImageRep bytesPerRow]*aSize.height;i+=4){
    char cr= p[i];
    char cb= p[i+2];
    p[i]= cb;
    p[i+2]= cr;
    }


    id provider= [[context outputImageProviderFromBufferWithPixelFormat:QCPlugInPixelFormatBGRA8
    pixelsWide:aSize.width
    pixelsHigh:aSize.height
    baseAddress:[aBitmapImageRep bitmapData]
    bytesPerRow:[aBitmapImageRep bytesPerRow]
    releaseCallback:_BufferReleaseCallback
    releaseContext:NULL
    colorSpace:[[aBitmapImageRep colorSpace] CGColorSpace]
    shouldColorMatch:YES]
    retain];
    if(provider == nil)
    return NO;
    self.outputImage = provider;
    }
    else {
    self.outputImage= nil;
    }
    return YES;
    }
    - (void)disableExecution:(id <QCPlugInContext>)context
    {
    }
    - (void)stopExecution:(id <QCPlugInContext>)context
    {
    }
    @end
    @implementation WebViewPlugIn (WebView)
    - (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
    {
    NSSize size= [[aWebFrameView documentView] bounds].size;
    NSUInteger i= ((NSUInteger)size.width)%4;
    if (i!=0) {
    size.width+= 4-i;
    }
    [[aWebView window] setContentSize:size];

    [aBitmapImageRep release];
    [aWebFrameView lockFocus];
    aBitmapImageRep= [[aWebFrameView bitmapImageRepForCachingDisplayInRect:[aWebFrameView bounds]] retain];
    [aWebFrameView unlockFocus];

    }
    @end



    結果
    こちらを表示.

    動画のページで横スクロールバーがでてる…documentViewのサイズもだめなのかなぁ…。

    2011年7月29日金曜日

    Quartz Composer / WebViewの画像を取得するパッチ

    追記(2011/07/31): 修正版を書きました



    やってみた
    WebKit.frameworkを追加

    WebViewPlugIn.h

    #import <Quartz/Quartz.h>
    #import <Webkit/WebKit.h>

    @interface WebViewPlugIn : QCPlugIn {
    @private
    WebView *aWebView;
    NSString *oldURL;
    NSBitmapImageRep *aBitmapImageRep;
    }

    @property(assign) NSString *inputURL;
    @property(assign) id outputImage;
    @end

    WebViewPlugIn.m

    #import <OpenGL/CGLMacro.h>
    #import "WebViewPlugIn.h"

    #define kQCPlugIn_Name @"WebView"
    #define kQCPlugIn_Description @"WebView description"

    @implementation WebViewPlugIn
    @dynamic inputURL;
    @dynamic outputImage;
    + (NSDictionary *)attributes
    {
    return [NSDictionary dictionaryWithObjectsAndKeys:
    kQCPlugIn_Name, QCPlugInAttributeNameKey,
    kQCPlugIn_Description, QCPlugInAttributeDescriptionKey,
    nil];
    }

    + (NSDictionary *)attributesForPropertyPortWithKey:(NSString *)key
    {
    return nil;
    }

    + (QCPlugInExecutionMode)executionMode
    {
    return kQCPlugInExecutionModeProvider;
    }

    + (QCPlugInTimeMode)timeMode
    {
    return kQCPlugInTimeModeIdle;
    }

    - (id)init
    {
    self = [super init];
    if (self) {
    NSRect r= NSMakeRect(0,0, 16, 16);
    aWebView= [[WebView alloc] initWithFrame:r
    frameName:nil
    groupName:nil];
    NSWindow *w= [[NSWindow alloc] init];
    [w setContentView:aWebView];
    [w setFrame:r display:YES];
    [aWebView setFrameLoadDelegate:self];
    }
    return self;
    }
    - (void)finalize
    {
    [super finalize];
    }
    - (void)dealloc
    {
    [aWebView release];
    [oldURL release];
    [super dealloc];
    }
    @end
    @implementation WebViewPlugIn (Execution)
    - (BOOL)startExecution:(id <QCPlugInContext>)context
    {
    return YES;
    }
    - (void)enableExecution:(id <QCPlugInContext>)context
    {
    }
    static void _BufferReleaseCallback(const void* address, void* info)
    {
    free(CGBitmapContextGetData((CGContextRef)info));
    CGContextRelease(info);
    }
    - (BOOL)execute:(id <QCPlugInContext>)context atTime:(NSTimeInterval)time withArguments:(NSDictionary *)arguments
    {
    if (![oldURL isEqualToString:self.inputURL]) {
    [aWebView setMainFrameURL:self.inputURL];
    [oldURL release];
    oldURL= [self.inputURL retain];
    }
    if (aBitmapImageRep!=nil) {
    NSSize size= [aBitmapImageRep size];
    id provider= [[context outputImageProviderFromBufferWithPixelFormat:QCPlugInPixelFormatBGRA8
    pixelsWide:size.width
    pixelsHigh:size.height
    baseAddress:[aBitmapImageRep bitmapData]
    bytesPerRow:[aBitmapImageRep bytesPerRow]
    releaseCallback:_BufferReleaseCallback
    releaseContext:NULL
    colorSpace:[context colorSpace]
    shouldColorMatch:YES]
    retain];
    if(provider == nil)
    return NO;
    self.outputImage = provider;
    }
    else {
    self.outputImage= nil;
    }
    return YES;
    }
    - (void)disableExecution:(id <QCPlugInContext>)context
    {
    }
    - (void)stopExecution:(id <QCPlugInContext>)context
    {
    }
    @end
    @implementation WebViewPlugIn (WebView)
    - (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
    {
    NSView *view = [[[aWebView mainFrame] frameView] documentView];
    NSSize size= [view bounds].size;
    size.width+= (4-((NSUInteger)size.width)%4);
    [[view window] setContentSize:size];
    [aBitmapImageRep release];
    [view lockFocus];
    aBitmapImageRep = [[NSBitmapImageRep alloc] initWithFocusedViewRect:[view bounds]];
    [view unlockFocus];
    }
    @end

    bytesPerRowの値は16で割り切れないと駄目なんだって.
    1pixelで4byte(QCPlugInPixelFormatBGRA8)だから'4-(width%4)'を加えてみた.
    これだと4で割り切れたとしても無駄に4pixel増えちゃうけど.


    結果
    Editor



    View( ここを表示したもの )


    2011年7月27日水曜日

    Quartz Composer / QCRendererを用いてコマンドラインで画像の差分をとってみる(composite)

    動機
    画像の差分をとりたいなと思い,GoogleReaderに貯め込んだ記事を探してみた.

    ImageMagickという文字をみて,インストールするのめんどくさいなぁ…って逃げ出した.
    Quartz Composerでならすぐつくれるのにって思い,以前みつけたQuartz Composer Offlineを応用すれば画像も書き出せるな.ってことでこれを参考にやってみた.(既に有名な記事がありそうだけどやってみたw)

    やってみた
    1.Command Line Toolプロジェクト

    2.Cocoa.framework, OpenGL.framework, Quartz.frameworkを追加

    3.コード

    #import <Foundation/Foundation.h>
    #import <Quartz/Quartz.h>

    int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    if (argc != 3) {
    [pool drain];
    return 1;
    }
    NSString *filepath1= [NSString stringWithCString:argv[1] encoding:NSUTF8StringEncoding];
    NSString *filepath2= [NSString stringWithCString:argv[2] encoding:NSUTF8StringEncoding];
    NSImage *image1= [[NSImage alloc] initWithContentsOfFile:filepath1];
    NSImage *image2= [[NSImage alloc] initWithContentsOfFile:filepath2];

    NSUInteger width= 16;
    NSUInteger height= 16;
    NSString *compositionPath= @"./composition.qtz";
    QCRenderer *renderer= nil;
    {
    NSOpenGLPixelFormatAttribute attributes[]= {
    NSOpenGLPFAPixelBuffer,
    NSOpenGLPFANoRecovery,
    NSOpenGLPFAAccelerated,
    NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)24,
    NSOpenGLPFASampleBuffers, (NSOpenGLPixelFormatAttribute)1,
    NSOpenGLPFASamples, (NSOpenGLPixelFormatAttribute)16,
    (NSOpenGLPixelFormatAttribute)0
    };
    NSOpenGLPixelFormat *format= [[[NSOpenGLPixelFormat alloc] initWithAttributes:attributes] autorelease];
    NSOpenGLPixelBuffer *pixelBuffer= [[NSOpenGLPixelBuffer alloc] initWithTextureTarget:GL_TEXTURE_RECTANGLE_EXT
    textureInternalFormat:GL_RGBA
    textureMaxMipMapLevel:0
    pixelsWide:width
    pixelsHigh:height];

    NSOpenGLContext *openGLContext= [[NSOpenGLContext alloc] initWithFormat:format shareContext:nil];
    if(pixelBuffer == nil || openGLContext == nil) {
    [pool drain];
    return 1;
    }

    [openGLContext setPixelBuffer:pixelBuffer
    cubeMapFace:0
    mipMapLevel:0
    currentVirtualScreen:[openGLContext currentVirtualScreen]];

    renderer= [[QCRenderer alloc] initWithOpenGLContext:openGLContext pixelFormat:format file:compositionPath];
    }

    if(renderer) {
    [renderer setValue:image1 forInputKey:@"Image1"];
    [renderer setValue:image2 forInputKey:@"Image2"];

    if(![renderer renderAtTime:0.0 arguments:nil]) {
    [pool drain];
    return 1;
    }
    NSBitmapImageRep *bitmapImage = [renderer createSnapshotImageOfType:@"NSBitmapImageRep"];

    if (1){
    NSImage *image= (NSImage *)[renderer valueForOutputKey:@"Image"];
    if (image) {
    bitmapImage= [NSBitmapImageRep imageRepWithData:[image TIFFRepresentation]];
    }
    }

    if(bitmapImage) {
    NSDictionary *properties= [NSDictionary dictionaryWithObjectsAndKeys:
    [NSNumber numberWithFloat:1.0], NSImageCompressionFactor,
    nil];
    NSData *pngImageData= [bitmapImage representationUsingType:NSPNGFileType
    properties:properties];
    [pngImageData writeToFile:@"./output.png"
    atomically:YES];
    }
    }

    [pool drain];
    return 0;
    }


    • ちなみに青いif分を"if(0){…}"で通らなければViewの画像を出力画像にします.(その際はwidht, heightの値で画像サイズがきまる)
    • ちなみにrenderAtTimeの引数で経過時間を指定しています.



    4.composition.qtz(実行時はコマンドと同じフォルダに)

    publishしてあるキーについて




    結果
    > ./commandName imageFilePath1 imageFilePath2

    1.入力ファイル(第一, 第二引数)
    出力画像サイズをQCRendererの初期化時のサイズに依存しないという点からQuarz Composer Offlineと異なりOutputのPublishで画像を取得してみた.


    2.出力ファイル(output.png)



    composition.qtzの中身を変えれば当然出力も変わる(変えられる).

    2011年6月22日水曜日

    Quartz Composer / Fragment Shader(GLSL Shaderパッチ)をいじってみた

    動機:
    nobokoさんこのpostをみてこちらの動画(FORTUNE - Staring At The Ice Melt (album teaser BULLY))を見て,「GLSL ShaderパッチのFragment Shaderでそれっぽくできないかしら?」と思いちょっとやってみた.


    やってみた:
    Fragment Shaderのコードとしてはこんなかんじ.
    Vertex Shaderはそのまま.
    uniform sampler2D texture;
    uniform float i;
    uniform float direction;
    void main()
    {
    vec4 c= texture2D(texture, gl_TexCoord[0].xy);

    if (direction<0.5) {
    if (i > gl_TexCoord[0].x) {
    c= texture2D(texture, vec2(i, gl_TexCoord[0].y));
    }
    }
    else {
    if (i > gl_TexCoord[0].y) {
    c= texture2D(texture, vec2(gl_TexCoord[0].x, i));
    }
    }
    gl_FragColor= c;
    }


    float iは0-1の間の値
    float directionは0.5を境界に縦と横の切り替え(boolでよかったのでは…。)


    結果:
    っぽい?

    2011年6月20日月曜日

    Quartz Composer / IteratorのIndexの総和を求める (IteratorのPublish Outputは最後の値だけ

    動機
    nobokoさんのサンプルをみて,そうなのか!と思ったので(世の中の常識なのかもしれませんが).

    やったこと
    全体(0-9の和なので45)


    Iterator内

    'Source #0'の値は'0'

    パッチ処理が上流から下流に流れ,繰り返す直前の演算状態で次のIterator内処理が行われるためか値が保持されてrecurrentな状態になるらしい.
    Publish Outputなら全てというわけでなく,最後の演算状態だけが保持されるので,下流で要求されてしまえば上流の値は計算させるので保持されない.
    そういうケースは素直にFeedbackを使えば良いんだと思う.

    2011年6月18日土曜日

    Quartz Composer / Google SketchUpで作ったMeshの頂点を動かしてみた

    動機
    まぁタイトルをみて全容がわかってしまうような人しか興味がないだろうという無駄さ加減なのですが,一応タイトルの通りな感じでやってみたのでメモ.


    やってみた
    1.Google SketchUpでMeshを描く
    1-1 正方形を描く(正方形になったときはpopupで'正方形'って出る)


    1-2 押し出す


    1-3 全体を選択する


    1-4 コピー&ペーストして動かす(端点が合うと'端点'とpopupされ合わさった頂点が緑色にハイライトされる)


    1-5 繰り返す(今回は8個並べた)


    1-6 ファイル/エクスポート/3Dモデルで書き出す


    1-7 COLLADA形式を選択して書き出す


    1-8 プレビューでみてみる(出来上がった拡張子daeのファイルをダブルクリックで起動する)


    1-9 マウスでグリグリまわしてみる(そんなこともできる)


    2.Quartz Composerで表示していく
    2-1 テンプレートから'Mesh Filter'を選ぶ


    2-2 テンプレートのEditorはこんな感じ


    2-3 1-7のファイルをドラッグ&ドロップでImportして繋ぐ


    2-4 Interpolationで位相を与えてみる


    2-5 Viewはこんな感じ


    3.動かす軸を変えてみる
    3-1 OpenCL Kernelパッチである'SinWave'パッチのインスペクタを開く


    3-2 選択してある所を修正('x'を'z'へ)


    3-3 Viewはこんな感じ