Как создать изображение из данных холста?

В моем приложении я пытаюсь сохранить произвольную часть визуализированного HTML-холста в файл изображения. В моем Javascript я звоню ctx. getImageData(x, y, w, h) и передать полученный объект в мой код макруби (хотя, если вы знаете решение в objc, я тоже очень заинтересован).

Там я пытаюсь создать объект 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

Он использует типизацию утки в Какао и обычно определяет селектор на NSData для записи себя в файл.

Кажется, до сих пор это работает, и я рад, что нашел решение. Однако я все еще хотел бы увидеть решение, использующее NSBitmapImageRep. Следующая функция, которую я реализую, это экспорт в видео, и я считаю, что мне понадобится более тонкий контроль, предоставляемый этим классом.

1 ответ

Решение

Вместо того, чтобы использовать getImageDataЯ бы предложил использовать Canvas.toDataURL. Это даст вам двоичный PNG (или JPEG), который, как оказалось, закодирован в base64. Расшифруйте base64, и вы получите файл, который вы можете сохранить для пользователя или обработать для перекодирования в другой формат.

Изменить: Первоначально я удалил свой ответ, потому что я понял, что вы хотите сериализовать субрегион холста. Тогда я понял, что если это поможет, вы можете вместо этого сделать это:

  1. Создайте новый холст размером с субрегион.
  2. Используйте context.drawImage(), чтобы скопировать субрегион из оригинала на новый холст.
  3. Вызовите Canvas.toDataURL на новом холсте, чтобы получить сериализованные в base64 данные.

Для декодирования данных base64 вы можете использовать base64 метод decode64 библиотеки ruby. Обратите внимание, что реализация этого метода чрезвычайно проста, и вы можете просто вставить его:

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 ) }
Другие вопросы по тегам