Module: OilyPNG::Operations

Included in:
Canvas
Defined in:
ext/oily_png/oily_png_ext.c

Instance Method Summary collapse

Instance Method Details

#compose!(*args) ⇒ Object



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'ext/oily_png/operations.c', line 13

VALUE oily_png_compose_bang(int argc, VALUE *argv, VALUE self) {
  // Corresponds to the other image(foreground) that we want to compose onto this one(background).
  VALUE other;
  
  // The offsets are optional arguments, so these may or may not be null pointers.
  // We'll prefix them with 'opt' to identify this.
  VALUE opt_offset_x;
  VALUE opt_offset_y;
  
  // Scan the passed in arguments, and populate the above-declared variables. Notice that '12'
  // specifies that oily_png_compose_bang takes in 1 required parameter, and 2 optional ones (the offsets)
  rb_scan_args(argc, argv, "12", &other,&opt_offset_x,&opt_offset_y);
  
  // Regardless of whether offsets were provided, we must specify a default value for them since they will
  // be used in calculating the position of the composed element.
  long offset_x = 0;
  long offset_y = 0;

  // If offsets were provided, then the opt_offset_* variables will not be null pointers. FIXNUM_P checks
  // whether they point to a fixnum object. If they do, then we can safely assign our offset_* variables to the values.
  if(FIXNUM_P(opt_offset_x)){
    offset_x = FIX2LONG(opt_offset_x);
  }
  if(FIXNUM_P(opt_offset_y)){
    offset_y = FIX2LONG(opt_offset_y);
  }
  
  // Get the dimension data for both foreground and background images.
  long self_width        = FIX2LONG(rb_funcall(self, rb_intern("width"), 0));
  long self_height       = FIX2LONG(rb_funcall(self, rb_intern("height"), 0));
  long other_width       = FIX2LONG(rb_funcall(other, rb_intern("width"), 0));
  long other_height      = FIX2LONG(rb_funcall(other, rb_intern("height"), 0));
  
  // Make sure that the 'other' image fits within the current image. If it doesn't, an exception is raised
  // and the operation should be aborted.
  oily_png_check_size_constraints( self_width, self_height, other_width, other_height, offset_x, offset_y );
  
  // Get the pixel data for both the foreground(other) and background(self) pixels. 
  VALUE* bg_pixels = RARRAY_PTR(rb_funcall(self, rb_intern("pixels"), 0));
  VALUE* fg_pixels = RARRAY_PTR(rb_funcall(other, rb_intern("pixels"), 0));

  long x = 0;
  long y = 0;
  long bg_index = 0; // corresponds to the current index in the bg_pixels array.
  for( y = 0; y < other_height; y++ ){
    for( x = 0; x < other_width; x++ ){
      // We need to find the value of bg_index twice, so we only calculate and store it once.
      bg_index = ( x + offset_x ) + ( y + offset_y ) * self_width;
      // Replace the background pixel with the composition of background + foreground
      bg_pixels[bg_index] = UINT2NUM( oily_png_compose_color( NUM2UINT( fg_pixels[x+ y * other_width] ), NUM2UINT( bg_pixels[bg_index] ) ) );
    }
  }
  return self;
}

#replace!(*args) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'ext/oily_png/operations.c', line 69

VALUE oily_png_replace_bang(int argc, VALUE *argv, VALUE self) {
  // Corresponds to the other image(foreground) that we want to compose onto this one(background).
  VALUE other;
  
  // The offsets are optional arguments, so these may or may not be null pointers.
  // We'll prefix them with 'opt' to identify this.
  VALUE opt_offset_x;
  VALUE opt_offset_y;
  
  // Scan the passed in arguments, and populate the above-declared variables. Notice that '12'
  // specifies that oily_png_compose_bang takes in 1 required parameter, and 2 optional ones (the offsets)
  rb_scan_args(argc, argv, "12", &other,&opt_offset_x,&opt_offset_y);
  
  // Regardless of whether offsets were provided, we must specify a default value for them since they will
  // be used in calculating the position of the composed element.
  long offset_x = 0;
  long offset_y = 0;

  // If offsets were provided, then the opt_offset_* variables will not be null pointers. FIXNUM_P checks
  // whether they point to a fixnum object. If they do, then we can safely assign our offset_* variables to the values.
  if(FIXNUM_P(opt_offset_x)){
    offset_x = FIX2LONG(opt_offset_x);
  }
  if(FIXNUM_P(opt_offset_y)){
    offset_y = FIX2LONG(opt_offset_y);
  }
  
  // Get the dimension data for both foreground and background images.
  long self_width        = FIX2LONG(rb_funcall(self, rb_intern("width"), 0));
  long self_height       = FIX2LONG(rb_funcall(self, rb_intern("height"), 0));
  long other_width       = FIX2LONG(rb_funcall(other, rb_intern("width"), 0));
  long other_height      = FIX2LONG(rb_funcall(other, rb_intern("height"), 0));
  
  // Make sure that the 'other' image fits within the current image. If it doesn't, an exception is raised
  // and the operation should be aborted.
  oily_png_check_size_constraints( self_width, self_height, other_width, other_height, offset_x, offset_y );
  
  // Get the pixel data for both the foreground(other) and background(self) pixels. 
  VALUE* bg_pixels = RARRAY_PTR(rb_funcall(self, rb_intern("pixels"), 0));
  VALUE* fg_pixels = RARRAY_PTR(rb_funcall(other, rb_intern("pixels"), 0));

  long x = 0;
  long y = 0;
  long bg_index = 0; // corresponds to the current index in the bg_pixels array.
  for( y = 0; y < other_height; y++ ){
    for( x = 0; x < other_width; x++ ){
      // We need to find the value of bg_index twice, so we only calculate and store it once.
      bg_index = ( x + offset_x ) + ( y + offset_y ) * self_width;
      // Replace the background pixel with the composition of background + foreground
      bg_pixels[bg_index] = fg_pixels[x+ y * other_width];
    }
  }
  return self;
}

#rotate_left!Object



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'ext/oily_png/operations.c', line 124

VALUE oily_png_rotate_left_bang(VALUE self){
  int store_at;
  VALUE pixel_value;
  int canvas_width = NUM2INT(rb_funcall(self, rb_intern("width"), 0));
  int canvas_height = NUM2INT(rb_funcall(self, rb_intern("height"), 0));
  VALUE original_pixels = rb_funcall(self, rb_intern("pixels"), 0);
  VALUE new_pixels = rb_ary_dup(original_pixels);
  int i, j;
  for( j = 0 ; j < canvas_width; j++ ){
    for( i = 0 ; i < canvas_height; i++ ){
      store_at = (canvas_width - 1 - j)*canvas_height + i;
      pixel_value = rb_ary_entry(original_pixels, i*canvas_width + j);
      rb_ary_store(new_pixels, store_at, pixel_value );
    }
  }
  rb_funcall(self, rb_intern("replace_canvas!"), 3, INT2NUM(canvas_height), INT2NUM(canvas_width), new_pixels);
  return self;
}

#rotate_right!Object



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'ext/oily_png/operations.c', line 143

VALUE oily_png_rotate_right_bang(VALUE self){
  int store_at;
  VALUE pixel_value;
  int canvas_width = NUM2INT(rb_funcall(self, rb_intern("width"), 0));
  int canvas_height = NUM2INT(rb_funcall(self, rb_intern("height"), 0));
  VALUE original_pixels = rb_funcall(self, rb_intern("pixels"), 0);
  VALUE new_pixels = rb_ary_dup(original_pixels);
  int i, j;
  for( j = 0; j < canvas_width; j++ ){
    for( i = 0; i < canvas_height; i++ ){
      store_at = j * canvas_height + (canvas_height - i - 1);
      pixel_value = rb_ary_entry(original_pixels, i*canvas_width + j);
      rb_ary_store(new_pixels, store_at, pixel_value );
    }
  }
  rb_funcall(self, rb_intern("replace_canvas!"), 3, INT2NUM(canvas_height), INT2NUM(canvas_width), new_pixels);
  return self;
}