3

私のアプリケーションでは、レンダリングされたHTMLキャンバスの任意の部分を画像ファイルに保存しようとしています。私のJavascriptでは、結果のオブジェクトを呼び出してmacrubyコードに渡します(ただし、objcの解決策を知っている場合は、私も非常に興味があります)。ctx.getImageData(x, y, w, h)

そこで、ユーザーが希望する画像形式で保存できるように、 NSBitmapImageRepオブジェクトを作成しようとしています。

これはこれまでの私のコードです(関数は引数としてWebScriptObjectを取得します):

def setimagedata(d)
    w =  d.valueForKey("width").to_i
    h =  d.valueForKey("height").to_i
    data = Pointer.new(:char, d.valueForKey("data").valueForKey("length").to_i)
    d.valueForKey("data").valueForKey("length").to_i.times do |i|
        data[i] = d.valueForKey("data").webScriptValueAtIndex(i).to_i
    end
    puts "data complete" # get's called
    @exported_image = NSBitmapImageRep.alloc.initWithBitmapDataPlanes(data,
        pixelsWide: w, pixelsHigh:h, bitsPerSample: 32,
        samplesPerPixel: 4, hasAlpha: true, isPlanar: false, 
        colorSpaceName: NSCalibratedRGBColorSpace, 
        bitmapFormat: NSAlphaNonpremultipliedBitmapFormat, 
        bytesPerRow: 0, bitsPerPixel: 0)
    puts "done" # doesn't get called
end

コードは関数を通過していないようですがinitWithBitmapDataPlanes、エラーは発生しません。

私の質問は:私は何を間違っているのですか?このアプローチは合理的ですか(そうでない場合は、何が良いでしょうか?)。

編集

以下のPhrogzの回答を使用して、中間的な解決策を得ました。別のキャンバス、getImageData、putImageData、およびtoDataURLを使用して、必要な領域のデータURLを取得します。私setimagedataの場合、データのURLを保存するだけで、dataOfType: error:メソッドは次のようになります。

def dataOfType(type, error:outError)
    workspace = NSWorkspace.sharedWorkspace
    if workspace.type(type, conformsToType: "public.image")
        @data_url[ /(?<=,).+/ ].unpack("m").first
    end
end

不足している分泌物は、この醜いハックスにソースをかけます:

class NSString
    def writeToURL(url, options: opts, error: error)
        File.open(url.path, "w") {|f| f << self }
    end
end

これは、Cocoaでのダックタイピングを活用し、通常はNSDataでセレクターを定義して、ファイルに書き込みます。

これは今のところうまくいくようで、解決策に到達できてうれしいです。ただし、NSBitmapImageRepを使用した解決策を見たいと思います。私が実装している次の機能はビデオへのエクスポートであり、このクラスによって提供されるより細かい制御が必要になると思います。

4

1 に答える 1

3

を使用する代わりに、 Canvas.toDataURLgetImageDataを使用することをお勧めします。これにより、base64でエンコードされたバイナリPNG(またはJPEG)が得られます。base64をデコードすると、ユーザー用に保存したり、別の形式にトランスコードするために処理したりできるファイルが作成されます。

編集:キャンバスのサブリージョンをシリアル化する必要があることに気付いたため、最初に回答を削除しました。それから私はこれがあなたが代わりにこれをすることができるならあなたがこれをすることができることに気づきました:

  1. サブリージョンのサイズの新しいキャンバスを作成します。
  2. context.drawImage()を使用して、サブ領域を元のキャンバスから新しいキャンバスにコピーします。
  3. 新しいキャンバスでCanvas.toDataURLを呼び出して、base64でシリアル化されたデータを取得します。

base64データをデコードするには、base64rubyライブラリのdecode64メソッドを使用できます。ただし、このメソッドの実装は非常に単純であり、インライン化するだけでよいことに注意してください。

def decode64(str)
  str.unpack("m").first
end

編集2:たとえばtoDataURL、Ruby文字列に配置された呼び出しの結果を考えると、単純に次のようになります。

require 'base64'
data_only = data_url[ /(?<=,).+/ ] # Find everything after the first comma
File.open( 'foo.png', 'w' ){ |f| f << Base64.decode64( data_only ) }
于 2011-01-09T15:38:44.820 に答える