Codebase list ruby-fxruby / 1646eee
Change access to raw pixel data of FXImage and derivatives Allow more consistent read/write access to image data, that is also usable with derived classes like FXJPGImage. Moreover much faster String based access to the pixel data is possible, now. FXImage#data and FXMemoryBuffer is now deprecated. Lars Kanis 12 years ago
7 changed file(s) with 135 addition(s) and 50 deletion(s). Raw diff Collapse all Expand all
446446 rb_ary_push(result,to_ruby(colors[i]));
447447 return result;
448448 }
449
450 FXuint FXRbNumberOfFXColors(VALUE string_or_ary){
451 FXuint len;
452
453 if(TYPE(string_or_ary) == T_ARRAY){
454 len = RARRAY_LEN(string_or_ary);
455 }else{
456 Check_Type(string_or_ary,T_STRING);
457 if(RSTRING_LEN(string_or_ary) % sizeof(FXColor) != 0 )
458 rb_raise( rb_eArgError, "String size is no multiple of %lu", sizeof(FXColor) );
459 len = RSTRING_LEN(string_or_ary) / sizeof(FXColor);
460 }
461 return len;
462 }
463
464 FXColor *FXRbConvertToFXColors(VALUE string_or_ary){
465 FXColor* pix=0;
466 if(TYPE(string_or_ary) == T_ARRAY){
467 if(FXMALLOC(&pix,FXColor,RARRAY_LEN(string_or_ary))){
468 for(long i=0; i<RARRAY_LEN(string_or_ary); i++){
469 pix[i]=static_cast<FXColor>(NUM2UINT(rb_ary_entry(string_or_ary,i)));
470 }
471 }
472 }else{
473 if(FXMALLOC(&pix,FXColor,RSTRING_LEN(string_or_ary)/sizeof(FXColor))){
474 memcpy(pix, RSTRING_PTR(string_or_ary), RSTRING_LEN(string_or_ary));
475 }
476 }
477 return pix;
478 }
449479
450480 //----------------------------------------------------------------------
451481
149149
150150 // Returns a Ruby array of FXColor values
151151 extern VALUE FXRbMakeColorArray(const FXColor* colors,FXint w,FXint h);
152
153 // Returns a number of FXColor elements in the argument
154 extern FXuint FXRbNumberOfFXColors(VALUE string_or_ary);
155
156 // Allocate a FXColor buffer and populate with data
157 extern FXColor *FXRbConvertToFXColors(VALUE string_or_ary);
152158
153159 extern void* FXRbGetExpectedData(VALUE recv,FXSelector key,VALUE data);
154160
24092409 class FXImage
24102410 def data(*args) # :nodoc:
24112411 getData(*args)
2412 end
2413 def pixels=(*args) # :nodoc:
2414 setPixels(*args)
24122415 end
24132416 def options(*args) # :nodoc:
24142417 getOptions(*args)
3838
3939 class FXImage < FXDrawable
4040
41 # Pixel data [FXMemoryBuffer]
41 # [deprecated] Pixel data [FXMemoryBuffer]
4242 attr_reader :data
43
44 # Array of colors of all image pixels. Can also be written as String of raw [RGBA] values.
45 attr_accessor :pixels
46
4347
4448 # Option flags [Integer]
4549 attr_accessor :options
4650
4751 #
4852 # Create an image. If a client-side pixel buffer has been specified,
49 # the image does not own the pixel buffer unless the +IMAGE_OWNED+ flag is
50 # set. If the +IMAGE_OWNED+ flag is set but a +nil+ pixel buffer is
53 # the image owns the pixel buffer.
54 # If the +IMAGE_OWNED+ flag is set but a +nil+ pixel buffer is
5155 # passed, a pixel buffer will be automatically created and will be owned
5256 # by the image. The flags +IMAGE_SHMI+ and +IMAGE_SHMP+ may be specified for
5357 # large images to instruct #render to use shared memory to communicate
5660 # ==== Parameters:
5761 #
5862 # +a+:: an application instance [FXApp]
59 # +pixels+:: pixels [Array of FXColor values]
63 # +pixels+:: pixels [Array of FXColor values or string of raw [RGBA] values]
6064 # +opts+:: image options [Integer]
6165 # +width+:: image width [Integer]
6266 # +height+:: image height [Integer]
7478 #
7579 # ==== Parameters:
7680 #
77 # +pix+:: the array of FXColor values.
81 # +pixels+:: pixels [Array of FXColor values or string of raw [RGBA] values]
7882 # +opts+:: image options [Integer]
7983 # +width+:: image width [Integer]
8084 # +height+:: image height [Integer]
8185 #
82 def setData(pix, opts=0, width=nil, height=nil)
86 def setPixels(pixels, opts=0, width=nil, height=nil)
8387 end
88
89 #
90 # Return a String of the raw color representation of all image pixels.
91 #
92 # Image pixels are stored bytewise as [RGBA] values.
93 #
94 def pixel_string ; end
8495
8596 #
8697 # Return the color of the pixel at (_x_, _y_).
00 module Fox
1 # This class is deprecated. Use FXImage methods instead.
12 class FXMemoryBuffer
23
34 #
5454 * large images to instruct render() to use shared memory to communicate
5555 * with the server.
5656 */
57 FXImage(FXApp* a,VALUE ary=Qnil,FXuint opts=0,FXint w=1,FXint h=1){
57 FXImage(FXApp* a,VALUE string_or_ary=Qnil,FXuint opts=0,FXint w=1,FXint h=1){
5858 FXColor* pix=0;
59 if(!NIL_P(ary)){
60 Check_Type(ary,T_ARRAY);
61 if(FXMALLOC(&pix,FXColor,RARRAY_LEN(ary))){
62 for(long i=0; i<RARRAY_LEN(ary); i++){
63 pix[i]=static_cast<FXColor>(NUM2UINT(rb_ary_entry(ary,i)));
64 }
65 }
66 opts&=IMAGE_OWNED;
59 if(!NIL_P(string_or_ary)){
60 FXuint len=FXRbNumberOfFXColors(string_or_ary);
61 if(w*h != len){
62 rb_raise( rb_eArgError, "Array size does not match image size" );
6763 }
64 pix=FXRbConvertToFXColors(string_or_ary);
65 opts|=IMAGE_OWNED;
66 }
6867 return new FXRbImage(a,pix,opts,w,h);
69 }
68 }
7069
7170 /// To get to the pixel data
7271 FXMemoryBuffer *getData() const {
7372 if(self->getData()){
7473 return new FXMemoryBuffer(self->getData(),self->getWidth()*self->getHeight());
75 }
74 }
7675 else{
7776 return 0;
78 }
79 }
77 }
78 }
8079 }
8180
8281 /// To get to the option flags
9291 * The server-side representation of the image, if it exists, is not updated.
9392 * This can be done by calling render().
9493 */
95 void setData(VALUE ary,FXuint opts=0,VALUE w=Qnil,VALUE h=Qnil){
96 FXColor* pix=0;
97 Check_Type(ary,T_ARRAY);
98 if( ( (NIL_P(w) || NIL_P(h)) && self->getWidth()*self->getHeight() != RARRAY_LEN(ary)) ||
99 (!(NIL_P(w) || NIL_P(h)) && NUM2UINT(w)*NUM2UINT(h) != RARRAY_LEN(ary))){
100 rb_raise( rb_eArgError, "array size does not match image size" );
101 }
102 if(FXMALLOC(&pix,FXColor,RARRAY_LEN(ary))){
103 for(long i=0; i<RARRAY_LEN(ary); i++){
104 pix[i]=static_cast<FXColor>(NUM2UINT(rb_ary_entry(ary,i)));
105 }
106 }
94 void setPixels(VALUE string_or_ary,FXuint opts=0,VALUE w=Qnil,VALUE h=Qnil){
95 FXuint len=FXRbNumberOfFXColors(string_or_ary);
96 if( ( (NIL_P(w) || NIL_P(h)) && self->getWidth()*self->getHeight() != len) ||
97 (!(NIL_P(w) || NIL_P(h)) && NUM2UINT(w)*NUM2UINT(h) != len)){
98 rb_raise( rb_eArgError, "Array size does not match image size" );
99 }
100
101 FXColor* pix=FXRbConvertToFXColors(string_or_ary);
107102 opts|=IMAGE_OWNED;
108103 if( NIL_P(w) || NIL_P(h) ){
109104 self->setData(pix,opts);
110105 }else{
111106 self->setData(pix,opts,NUM2UINT(w),NUM2UINT(h));
107 }
108 }
109
110 VALUE pixels(){
111 FXColor* data = self->getData();
112 if (data) {
113 FXuint size = self->getWidth()*self->getHeight();
114 VALUE ary = rb_ary_new2(size);
115 for (int i = 0; i < size; i++)
116 rb_ary_store(ary, i, UINT2NUM(data[i]));
117 return ary;
118 } else {
119 return Qnil;
120 }
121 }
122
123 VALUE pixel_string(){
124 FXColor* data = self->getData();
125 if (data) {
126 return rb_str_new((char*)data, self->getWidth()*self->getHeight()*sizeof(FXColor));
127 } else {
128 return Qnil;
112129 }
113130 }
114131 }
1010
1111 def test_default_constructor_args_1
1212 img = FXImage.new(app)
13 assert_same(nil, img.data)
13 assert_same(nil, img.pixels)
1414 assert_equal(0, img.options)
1515 assert_equal(1, img.width)
1616 assert_equal(1, img.height)
1818
1919 def test_default_constructor_args_2
2020 img = FXImage.new(app, nil)
21 assert_same(nil, img.data)
21 assert_same(nil, img.pixels)
2222 assert_equal(0, img.options)
2323 assert_equal(1, img.width)
2424 assert_equal(1, img.height)
2626
2727 def test_default_constructor_args_3
2828 img = FXImage.new(app, nil, 0)
29 assert_same(nil, img.data)
29 assert_same(nil, img.pixels)
3030 assert_equal(0, img.options)
3131 assert_equal(1, img.width)
3232 assert_equal(1, img.height)
3434
3535 def test_default_constructor_args_4
3636 img = FXImage.new(app, nil, 0, 1)
37 assert_same(nil, img.data)
37 assert_same(nil, img.pixels)
3838 assert_equal(0, img.options)
3939 assert_equal(1, img.width)
4040 assert_equal(1, img.height)
4242
4343 def test_default_constructor_args_5
4444 img = FXImage.new(app, nil, 0, 1, 1)
45 assert_same(nil, img.data)
45 assert_same(nil, img.pixels)
4646 assert_equal(0, img.options)
4747 assert_equal(1, img.width)
4848 assert_equal(1, img.height)
5858 assert_equal(IMAGE_OWNED, img.options)
5959 end
6060
61 def test_setData
61 def test_setPixels
6262 img = FXImage.new(app, nil, 0, 2, 2)
63 img.setData([0x12345678, 2, 3, 4])
63 img.pixels = [0x12345678, 2, 3, 4]
6464 assert_equal(IMAGE_OWNED, img.options)
65 assert_equal(2*2, img.data.size)
66 assert_equal([0x12345678, 2, 3, 4], img.data.to_a)
65 assert_equal([0x12345678, 2, 3, 4], img.pixels)
6766 end
6867
69 def test_setData2
68 def test_setPixels2
7069 img = FXImage.new(app)
71 img.setData([0x12345678, 2], 0, 2, 1)
70 img.setPixels([0x12345678, 2], 0, 2, 1)
7271 assert_equal(IMAGE_OWNED, img.options)
73 assert_equal(2*1, img.data.size)
74 assert_equal([0x12345678, 2], img.data.to_a)
72 assert_equal([0x12345678, 2], img.pixels)
73 end
74
75 def test_setPixels_string
76 img = FXImage.new(app, nil, 0, 2, 1)
77 img.pixels = "rgbaRGBA"
78 assert_equal(IMAGE_OWNED, img.options)
79 assert_equal("rgbaRGBA", img.pixel_string)
7580 end
7681
7782 def test_create
8085 # the data should go away after we call create.
8186 #
8287 img = FXImage.new(app, nil, IMAGE_OWNED)
83 assert_not_nil(img.data)
88 assert_not_nil(img.pixels)
8489 img.create
85 assert_nil(img.data)
90 assert_nil(img.pixels)
8691
8792 #
8893 # If the image owns its pixel data and IMAGE_KEEP was specified,
8994 # the data should stay after we call create.
9095 #
9196 img = FXImage.new(app, nil, IMAGE_KEEP|IMAGE_OWNED)
92 assert_not_nil(img.data)
97 assert_not_nil(img.pixels)
9398 img.create
94 assert_not_nil(img.data)
99 assert_not_nil(img.pixels)
100 end
101
102 def test_create_with_data
103 img = FXImage.new(app, "rgbaRGBA", 0, 1, 2)
104 assert_equal("rgbaRGBA", img.pixel_string)
105 img.create
106 assert_nil(img.pixels)
107
108 img = FXImage.new(app, [0x12345678], IMAGE_KEEP|IMAGE_OWNED)
109 assert_equal([0x12345678], img.pixels)
110 img.create
111 assert_not_nil(img.pixels)
95112 end
96113
97114 #
105122 #
106123 img = FXImage.new(app)
107124 img.create
108 assert_nil(img.data)
125 assert_nil(img.pixels)
109126 assert_equal(0, img.options&IMAGE_OWNED)
110127 img.restore
111 assert_not_nil(img.data)
128 assert_not_nil(img.pixels)
112129 assert_not_equal(0, img.options&IMAGE_OWNED)
113130 end
114131