I want to convert a byte string from Ice server to a png as frequent as 30 times per second. I use chunky_png gem with this code:
data = ##cprx.getImageData()
width= data.description.width
height = data.description.height
png = ChunkyPNG::Image.new(width,height, ChunkyPNG::Color::TRANSPARENT)
pixeles = data.pixelData.bytes.to_a
k=0
for i in 0..height-1
for j in 0..width-1
png[j,i]=ChunkyPNG::Color.rgb(pixeles[k],pixeles[k+1],pixeles[k+2])
k=k+3
end
end
image = png.to_data_url
I create an image and I give values pixel by pixel. But it is too slow. I would like to know if there is a faster method.
Finally I have solved the problem with the method from_rgb_stream. Besides there is a library equivalent to chunky_png called oily_png that is faster thanks to a c++ core. My code currently looks like:
def ice_camera
status = 0
ic = nil
if session[:conected2] == nil
arguments= ["--Ice.Config=cameraview.cfg"]
ic = Ice::initialize(arguments)
base = ic.propertyToProxy("Cameraview.Camera.Proxy")
cprx = Jderobot::CameraPrx::checkedCast(base)
session[:conected2] = true
thr1 = Thread.new do
##mutex = Mutex.new
while true do
puts "11111111111111111111111111111111111111111"
data = cprx.getImageData()
png = ChunkyPNG::Canvas.from_rgb_stream(data.description.width, data.description.height, data.pixelData)
##mutex.synchronize do
##image=png.to_data_url
end
end
end
end
end
Related
I was trying to make a multiple-choice music player using Gosu but the picture and music Iwanted would not initialize despite the program running, it showed a black screen. The single block of codes works:
require 'gosu'
require './input_functions'
class MW < Gosu::Window
def initialize
super 200, 135
#beth = Gosu::Image.new("media/beth.jpg")
#song = Gosu::Song.new("media/3rdmovement.mp3")
#song.play
end
def draw
#beth.draw(0, 0)
end
end
window = MW.new
window.show
But adding the multiple choice elements would not work(note: read_integer_in_range is defined in input function, the name itself is self explanatory). Full code:
require 'gosu'
require './input_functions'
class MW < Gosu::Window
def initialize
super 200, 135
#beth = Gosu::Image.new("media/beth.jpg")
#dimitri = Gosu::Image.new("media/dimitri.png")
#vil = Gosu::Image.new("media/vilva.png")
#song = Gosu::Song.new("media/3rdmovement.mp3")
#song2=Gosu::Song.new("media/2ndwaltz.mp3")
#song3=Gosu::Song.new("media/1stseason.mp3")
read_integer_in_range( "What song you want play
1st Spring
2nd Waltz
3rd movement", 1, 3)
choice = gets.chomp.to_i()
case choice
when 1
#song3.play
#vil.draw(0, 0)
when 2
#song2.play
#dimitri.draw(0, 0)
when 3
#song.play
draw_beth()
end
end
end
def draw_beth
#beth.draw(0, 0)
end
window = MW.new
window.show
All of the Png/Jpg and mp3 file works just fine..
I tried separating the draw_beth to call it in case but it did not work. I hope some passing by could help me with this one
As I can see, you are creating a music player with GUI, and if you are doing so, you shouldn't use gets function, instead you should track for the cursor's position and return a test value; for example:
def update
#locs = [mouse_x, mouse_y]
#cursor_choice_album = mouse_over_button(mouse_x, mouse_y)
end
def needs_cursor?; true; end
def mouse_over_button(mouse_x, mouse_y)
if ((mouse_x > 100 and mouse_x < 500) and (mouse_y < 500 and mouse_y > 100))
return 1
end
then you can use the case condition in the "button down ID" function
The line: pics.box.signal_connect("button_press_event"){pics.nuImage}, triggers nuImage and adds 1 to the picindex counter upon clicking, making the current image destroy, and next image show. I would like to make this automatic, like a slideshow without having to click. It needs to show a new image every x amount of seconds, using a sleep or something like GLib.timeout_add_seconds (), but I do not understand how to implement these options to continue looping without any user input. Thank you for your help, I am very new to ruby.
require 'gtk2'
class Pics
attr_accessor :pile, :picindex, :imgLoaded, :image, :box, :window, :time
def initialize
#window = Gtk::Window.new()
#window.signal_connect("destroy"){Gtk.main_quit}
pic1 = "1.jpg"
pic2 = "2.jpg"
pic3 = "3.jpg"
pic4 = "4.jpg"
#pile = [pic1, pic2, pic3, pic4]
#picindex = 0
self.getImage
#box = Gtk::EventBox.new.add(#image)
#time = true
end
def nuImage
#box.remove(#image)
#picindex = #picindex + 1
#picindex = 0 if #picindex == #pile.length
self.getImage
#box.add(#image)
#box.show
end
def getImage
#imgLoaded = #pile[#picindex]
img = Gdk::Pixbuf.new(#imgLoaded, 556, 900)
#image = Gtk::Image.new(img)
#image.show
end
end # class Pics
pics = Pics.new
pics.box.signal_connect("button_press_event"){pics.nuImage}
pics.window.set_default_size(556, 900)
pics.window.add(pics.box)
pics.window.show_all
Gtk.main
the following code is an implementation:
GLib::Timeout.add(1000) do
pics.nuImage if pics.time
true
end
pics.window.signal_connect("key_press_event") do |_window, event|
case event.keyval
when Gdk::Keyval::GDK_KEY_space
pics.time = !pics.time
end
end
more details: http://ruby-gnome2.sourceforge.jp/hiki.cgi?GLib%3A%3ATimeout
related: Ruby GTK Pixbuf timed image change
I am creating an image slideshow in ruby, using gtk pixbuf to load images. I am very new to ruby & GTK, this may be an stupid question.
Currently image changes are linked to the GUI button_press_event, I would like them to change /refresh automatically based on a set time, like a slideshow or animation. I saw the gtk animation using a gif method, but I would like to use individual jpeg files inline sequence, so that I can set the time to show a slide. Once the loop has gone through all the images, the GUI should display buttons for replay or quit. ( I haven't used #time yet, it is just there for possibilities ) Thanks for any suggestions;
require 'gtk2'
class Pics
attr_accessor :pile, :picindex, :imgLoaded, :image, :box, :window, :time
def initialize
#window = Gtk::Window.new()
#window.signal_connect("destroy"){Gtk.main_quit}
pic1 = "1.jpg"
pic2 = "2.jpg"
pic3 = "3.jpg"
pic4 = "4.jpg"
#pile = [pic1, pic2, pic3, pic4]
#picindex = 0
self.getImage
#box = Gtk::EventBox.new.add(#image)
#time = true
end
def nuImage
#box.remove(#image)
#picindex = #picindex + 1
#picindex = 0 if #picindex == #pile.length
self.getImage
#box.add(#image)
#box.show
end
def getImage
#imgLoaded = #pile[#picindex]
img = Gdk::Pixbuf.new(#imgLoaded, 556, 900)
#image = Gtk::Image.new(img)
#image.show
end
end # class Pics
pics = Pics.new
pics.box.signal_connect("button_press_event"){pics.nuImage}
pics.window.set_default_size(556, 900)
pics.window.add(pics.box)
pics.window.show_all
Gtk.main
use GLib.timeout_add () or GLib.timeout_add_seconds (). Return False if you don't want to use it anymore.read GLib documentation, Section: Main Event Loop
This is a solution:
def start_button__clicked(but)
#thread = Thread.new {
loop do
next_button__clicked
sleep(2)
end
end
def stop_button__clicked(but)
#thread.kill
end
This is how I would do it in visual ruby. Its basically the same.
You'd just have a form with a button named "start_button" and "stop_button" etc.
the following code is an implementation:
GLib::Timeout.add(1000) do
pics.nuImage if pics.time
true
end
pics.window.signal_connect("key_press_event") do |_window, event|
case event.keyval
when Gdk::Keyval::GDK_KEY_space
pics.time = !pics.time
end
end
more details:
http://ruby-gnome2.sourceforge.jp/hiki.cgi?GLib%3A%3ATimeout
after_photo_post_process :post_process_photo
def post_process_photo
img = EXIFR::JPEG.new(photo.queued_for_write[:original].path) # error on this line
return unless img
self.width = img.width
self.height = img.height
self.model = img.model
end
I am using a ruby gem called EXIFR that extracts the EXIF data from JPEG files. The EXIF data is simply technical data about the picture. So my code works fine when I upload a JPEG, however any other image type causes it to break.
EXIFR::MalformedJPEG in ImagesController#create
no start of image marker found
I assumed that the return statement would allow this to work if nothing gets assigned to the img variable, but that looks like it is not the case.
You could rescue the error and return something else.
def post_process_photo
begin
img = EXIFR::JPEG.new(photo.queued_for_write[:original].path) # error on this line
self.width = img.width
self.height = img.height
self.model = img.model
rescue EXIFR::MalformedJPEG
return nil
end
end
I'm looking for an easy way to get width and height dimensions for image files in Ruby without having to use ImageMagick or ImageScience (running Snow Leapard).
As of June 2012, FastImage which "finds the size or type of an image given its uri by fetching as little as needed" is a good option. It works with local images and those on remote servers.
An IRB example from the readme:
require 'fastimage'
FastImage.size("http://stephensykes.com/images/ss.com_x.gif")
=> [266, 56] # width, height
Standard array assignment in a script:
require 'fastimage'
size_array = FastImage.size("http://stephensykes.com/images/ss.com_x.gif")
puts "Width: #{size_array[0]}"
puts "Height: #{size_array[1]}"
Or, using multiple assignment in a script:
require 'fastimage'
width, height = FastImage.size("http://stephensykes.com/images/ss.com_x.gif")
puts "Width: #{width}"
puts "Height: #{height}"
You could try these (untested):
http://snippets.dzone.com/posts/show/805
PNG:
IO.read('image.png')[0x10..0x18].unpack('NN')
=> [713, 54]
GIF:
IO.read('image.gif')[6..10].unpack('SS')
=> [130, 50]
BMP:
d = IO.read('image.bmp')[14..28]
d[0] == 40 ? d[4..-1].unpack('LL') : d[4..8].unpack('SS')
JPG:
class JPEG
attr_reader :width, :height, :bits
def initialize(file)
if file.kind_of? IO
examine(file)
else
File.open(file, 'rb') { |io| examine(io) }
end
end
private
def examine(io)
raise 'malformed JPEG' unless io.getc == 0xFF && io.getc == 0xD8 # SOI
class << io
def readint; (readchar << 8) + readchar; end
def readframe; read(readint - 2); end
def readsof; [readint, readchar, readint, readint, readchar]; end
def next
c = readchar while c != 0xFF
c = readchar while c == 0xFF
c
end
end
while marker = io.next
case marker
when 0xC0..0xC3, 0xC5..0xC7, 0xC9..0xCB, 0xCD..0xCF # SOF markers
length, #bits, #height, #width, components = io.readsof
raise 'malformed JPEG' unless length == 8 + components * 3
when 0xD9, 0xDA: break # EOI, SOS
when 0xFE: #comment = io.readframe # COM
when 0xE1: io.readframe # APP1, contains EXIF tag
else io.readframe # ignore frame
end
end
end
end
There's also a new (July 2011) library that wasn't around at the time the question was originally asked: the Dimensions rubygem (which seems to be authored by the same Sam Stephenson responsible for the byte-manipulation techniques also suggested here.)
Below code sample from project's README
require 'dimensions'
Dimensions.dimensions("upload_bird.jpg") # => [300, 225]
Dimensions.width("upload_bird.jpg") # => 300
Dimensions.height("upload_bird.jpg") # => 225
There's a handy method in the paperclip gem:
>> Paperclip::Geometry.from_file("/path/to/image.jpg")
=> 180x180
This only works if identify is installed. If it isn't, if PHP is installed, you could do something like this:
system(%{php -r '$w = getimagesize("#{path}"); echo("${w[0]}x${w[1]}");'})
# eg returns "200x100" (width x height)
I have finally found a nice quick way to get dimensions of an image. You should use MiniMagick.
require 'mini_magick'
image = MiniMagick::Image.open('http://www.thetvdb.com/banners/fanart/original/81189-43.jpg')
assert_equal 1920, image[:width]
assert_equal 1080, image[:height]
libimage-size is a Ruby library for calculating image sizes for a wide variety of graphical formats. A gem is available, or you can download the source tarball and extract the image_size.rb file.
Here's a version of the JPEG class from ChristopheD's answer that works in both Ruby 1.8.7 and Ruby 1.9. This allows you to get the width and height of a JPEG (.jpg) image file by looking directly at the bits. (Alternatively, just use the Dimensions gem, as suggested in another answer.)
class JPEG
attr_reader :width, :height, :bits
def initialize(file)
if file.kind_of? IO
examine(file)
else
File.open(file, 'rb') { |io| examine(io) }
end
end
private
def examine(io)
if RUBY_VERSION >= "1.9"
class << io
def getc; super.bytes.first; end
def readchar; super.bytes.first; end
end
end
class << io
def readint; (readchar << 8) + readchar; end
def readframe; read(readint - 2); end
def readsof; [readint, readchar, readint, readint, readchar]; end
def next
c = readchar while c != 0xFF
c = readchar while c == 0xFF
c
end
end
raise 'malformed JPEG' unless io.getc == 0xFF && io.getc == 0xD8 # SOI
while marker = io.next
case marker
when 0xC0..0xC3, 0xC5..0xC7, 0xC9..0xCB, 0xCD..0xCF # SOF markers
length, #bits, #height, #width, components = io.readsof
raise 'malformed JPEG' unless length == 8 + components * 3
# colons not allowed in 1.9, change to "then"
when 0xD9, 0xDA then break # EOI, SOS
when 0xFE then #comment = io.readframe # COM
when 0xE1 then io.readframe # APP1, contains EXIF tag
else io.readframe # ignore frame
end
end
end
end
For PNGs I got this modified version of ChristopeD's method to work.
File.binread(path, 64)[0x10..0x18].unpack('NN')