Как создать изображение из данных холста?
В моем приложении я пытаюсь сохранить произвольную часть визуализированного 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, и вы получите файл, который вы можете сохранить для пользователя или обработать для перекодирования в другой формат.
Изменить: Первоначально я удалил свой ответ, потому что я понял, что вы хотите сериализовать субрегион холста. Тогда я понял, что если это поможет, вы можете вместо этого сделать это:
- Создайте новый холст размером с субрегион.
- Используйте context.drawImage(), чтобы скопировать субрегион из оригинала на новый холст.
- Вызовите 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 ) }