Ruby GTK Pixbuf timed image change - ruby

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

Related

Music and image failed to initialize

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

Bounding box across multiple pages with Prawn PDF

I'm trying to create a document with Prawn Ruby PDF generator, but I'm facing the following problem:
The image below shows what structure I'm trying to do.
And this is the example code that tries to mimics my real scenario with the way that I'm trying to achieve this. The 2.times and (50.times.map { |i| i.to_s }.join("\n")) mimics dynamic data.
require 'prawn'
class MyPdf
def self.to_pdf(*args)
new(*args).to_pdf
end
def to_pdf
pdf.move_down 200
2.times do
pdf.bounding_box(
[0, pdf.cursor],
width: pdf.bounds.width
) do
pdf.text (50.times.map { |i| i.to_s }.join("\n"))
pdf.stroke_bounds
end
end
pdf
end
def pdf
#pdf ||= Prawn::Document.new(page_size: 'A4')
end
end
But I'm having a lot of trouble with the dynamic bounding box placing.
Do you people know a way to achieve this with or without bounding boxes?
You may be looking for span:
def to_pdf
pdf.move_down 200
2.times do
pdf.span(pdf.bounds.width) do
pdf.text (50.times.map { |i| i.to_s }.join("\n"))
pdf.stroke_bounds
end
end
end
I failed to do that with boundig boxes. May be this is not the best solution, but you can do this with tables :
data = []
500.times do |i|
data.push [i.to_s]
end
table(data, width: bounds.width) do |t|
t.cells.border_width = 0 # We don't want to see a table
t.before_rendering_page do |page|
page.row(0).border_top_width = 1
page.row(-1).border_bottom_width = 1
page.column(0).border_left_width = 1
page.column(-1).border_right_width = 1
end
end
source : http://prawnpdf.org/prawn-table-manual.pdf (page 17)
Check your margins to have the continuation on the top of the next page

Signal timed ruby gtk image change without button_press_event, how to trigger looping

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

How to convert a byte array to a png image

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

How to use progressbar indeterminate in ruby/tk?

I cant figure out how the progressbar in ruby/tk works in indeterminate mode.
I can get the progressbar showing but it will not move.
an example if I just use this line in my code
progressBar.start
If I only have that line the progressbar will be showing and moving as it should.
But if i add line of code under it it will not execute. I had the impression that the .start method of progressbar starts it and the method stop stops it and in between you have the code that should be executed and the progressbar show until it sees the stop.
But if i do this
progressBar.start
# some code (a loop that takes a long while to execute)
progressBar.stop
the progressbar is not beeing shown until the code in between is finished? I thought that was why you wanted the progressbar?
What am I not understanding here.
Thx for you help but why is not this working. Its just a stupid test. But i am doing somthing similar in the real program. If I write this code the progressbar will not run as it should but instead after the Devil img loop is done?
Dir.chdir("c:/temp")
bilder = Dir.glob("*.jpg")+
bilder = Dir.glob("*.png")+
bilder = Dir.glob("*.gif")
puts bilder
root = TkRoot.new { title 'Progressbar Demo' }
content = Tk::Frame.new(root) {}.grid(:sticky =>'new')
progress = Tk::Tile::Progressbar.new(content:mode=>'indeterminate':orient=>:horizontal)
progress.pack
Thread.new do
progress.start
i=0
while i < bilder.length
Devil.with_image(bilder[i]) do |img|
img.thumbnail2(150)
img.save("thumbnail_"+ bilder[i])
end
i=i+1
end
progress.stop
end
Tk.mainloop
It is a threading problem.
This code should work. Tested on Win7, Ruby 1.9.3
require 'tk'
root = TkRoot.new { title 'Progressbar Demo' }
progress = Tk::Tile::Progressbar.new(root, :mode=>'determinate', :orient=>:horizontal, :maximum=>100)
progress.pack
Thread.new do
99.times do |i|
progress.step(1) #or progress.value = i
puts i
sleep 0.1
end
end
Tk.mainloop
For your indeerminate version that is
require 'tk'
root = TkRoot.new { title 'Progressbar Demo' }
progress = Tk::Tile::Progressbar.new(root, :mode=>'indeterminate', :orient=>:horizontal)
progress.pack
Thread.new do
progress.start
99.times do |i|
puts i
sleep 0.1
end
progress.stop
end
Tk.mainloop
Here an example how to do it wiht green shoes
require 'green_shoes'
Shoes.app do
#p = progress
#animate = animate do |percent|
#animate.stop if percent > 99
puts percent
#p.fraction = percent.to_f / 100
end
end
EDIT: based on the added question here a reworked more rubylike version of your script
unfortionatly i had to comment out the Devil lines cause i can't get this gem to work (loaderror)
require 'tk'
# require 'devil'
bilder = Dir['c:/temp/*.{jpg,png,gif}']
root = TkRoot.new { title 'Progressbar Demo' }
progress = Tk::Tile::Progressbar.new(root, :mode=>'indeterminate', :orient=>'horizontal')
progress.pack
STDOUT.sync = true
Thread.new do
progress.start
bilder.each do |bild|
puts bild
sleep 0.5
# Devil.with_image(bild) do |img|
# img.thumbnail2(150)
# img.save("thumbnail_#{bild}")
# end
end
progress.stop
end
Tk.mainloop
LAST EDIT:
here a working example with mini_magick since devil doesn't work on any of my pc's and gives problem with TK
['mini_magick','tk','fileutils'].each(&method(:require))
bilder = Dir['c:/test/*.{jpg,png,gif}']
root = TkRoot.new { title 'Progressbar Demo' }
progress = Tk::Tile::Progressbar.new(root, :mode=>'indeterminate', :orient=>'horizontal')
progress.pack
STDOUT.sync = true
def generate file, out, type
image = MiniMagick::Image.open file
if type == :thumb
image.resize "92x92"
elsif type == :slide
image.resize "800x600"
end
image.write out
end
Thread.new do
progress.start
bilder.each do |bild|
puts bild
generate bild, bild+'.thumb.jpg', :thumb
end
progress.stop
progress.destroy
end
Tk.mainloop

Resources