From: "Ara.T.Howard" Date: 2004-02-09T10:07:46+09:00 Subject: Re: graphics lib? On Mon, 2 Feb 2004, Charles Comstock wrote: > You don't happen to have some code for example of this? I'm not quite > following is this through a C extension or just raw ruby? My solution I did > last time was wrap the get/set pixel methods so they only grabbed a 1x1 > range, and then I could access them directly, but this somehow seems like it > probably incites horrible performance. > Charles Comstock before i reply to the above i'd also suggest checking out narray - it features ultra fast and pretty easy to use very large array manipulation. it is a c extension available from the raa... re: above yes - i have example code - and yes mmap is a c extension (written by ts). my code is ultra specific to a statelite image format we use here at ngdc that's something like number of records = 3021 number of header records = 1 number of data records = 3020 record size = 7231 ... ... ... ... ... lots_of_binary_satelite_data32409132483124083209840238402983..... 409132483124083209840238402983..... 409132483124083209840238402983..... i have classes for header, scanlines, scanline header, and to get at row/pixels. excerpt follows (contact me offline and i will send you sources); this should give you the general flavor of what i'm talking about. below shows the idea behind a row level 'munging' method (#map!) that makes use of mmap to change pixels in place w/o really doing anything explict. pixel operations would be similar. the speed is gained by mapping the file 'rw' and never hanging on to more data than required at a time - in this case a scanline (record) of data. # RAA require 'mmap' .... module DMSP module OLS class Header < Array #{{{ .... .... def [] k #{{{ idx = index_of k raise IndexError, "#{ k.class } : #{ k.inspect }" unless idx ret = super(idx) raise IndexError, "#{ k.class } : #{ k.inspect }" unless ret and ret.size == 2 Numeric === k ? ret : ret[1] #}}} end # new .... def []= k, v #{{{ if Numeric === k raise TypeError, "#{ v.class } : #{ v.inspect }" unless Array === v @modified = true return super(k,v) end idx = index_of k if idx k = self[idx].first if Regexp === k else raise IndexError, "#{ k.class } : #{ k.inspect }" if Regexp === k idx = self.size # append end raise TypeError, "#{ k.class } : #{ k.inspect }" unless String === k pair = [k.strip, v] # recurse with numeric argument! self[idx] = pair v #}}} end .... #}}} end # class Header class Mmap < ::Mmap #{{{ .... .... # methods def initialize(*args) #{{{ @args = DMSP::hashify(*args) @path, @mode, @protection = @args.values_at :path, :mode, :protection @type = DMSP::file_type @path @mode ||= DEFAULT_MODE @protection ||= DEFAULT_PROTECTION super(path, mode, protection) @header = Header.new :io => self self #}}} end .... def get_record n #{{{ n = n.to_i raise(IndexError, "INDEX [%s]" % [n]) if n < 0 or n >= number_of_records rb = header.record_bytes start, length = n * rb, rb self[start, length] #}}} end .... def set_record n, data #{{{ n = n.to_i raise(IndexError, "INDEX [%s]" % [n]) if n < 0 or n >= number_of_records rb = header.record_bytes raise(RangeError, "DATA SIZE [%d]" % [data.size]) if data.size != rb start, length = n * rb, rb self[start, length] = data #}}} end .... def map! #{{{ changed = false r = header.number_of_header_records ... header.number_of_records r.each do |n| data = yield(get_record(n)) if data set_record(n, data) changed = true end end changed ? self : nil #}}} end alias collect! map! .... #}}} end # class MmappedFile end # module DMSP i would think that, for an image, you may end up with something like (un-tested) class Image < Mmap # class to support double ([i][j]) style indexing class Row attr :row attr :image def initialize row, image; @row = row; @image = image; end def [] col image[row * image.n_cols + col] end def []= col, pixel image[row * image.n_cols + col] = pixel end end attr :n_rows attr :n_cols def initialize path, n_rows, n_cols super path, 'rw', Mmap::MAP_SHARED end def [] row Row.new row, self end def pixel i, j, pix = nil pix ? (self[i * n_cols + j] = pix) : self[i * n_cols + j] end end which would allow you to do something like p(image.pixel i, j) image.pixel i, j, 0b101010 p(image.pixel i, j) or p(image.pixel[i][j]) image.pixel[i][j] = 0b101010 p(image.pixel[i][j]) you would proably be better off using rmagick or narray. the reason i chose this approach is that the ONLY thing i really needed was pixel level access since we are applying our own algorithims to the pixels and installing rmagick or narray for this was a bit overkill. mmap is lightweight and fast if all you desire is pixel level access. food for thought. -a -- ATTN: please update your address books with address below! =============================================================================== | EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov | PHONE :: 303.497.6469 | ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328 | STP :: http://www.ngdc.noaa.gov/stp/ | NGDC :: http://www.ngdc.noaa.gov/ | NESDIS :: http://www.nesdis.noaa.gov/ | NOAA :: http://www.noaa.gov/ | US DOC :: http://www.commerce.gov/ | | The difference between art and science is that science is what we | understand well enough to explain to a computer. | Art is everything else. | -- Donald Knuth, "Discover" | | /bin/sh -c 'for l in ruby perl;do $l -e "print \"\x3a\x2d\x29\x0a\"";done' ===============================================================================