morandi 0.12.1 → 0.99.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,79 @@
1
+ typedef enum {
2
+ ANGLE_0 = 0,
3
+ ANGLE_90 = 90,
4
+ ANGLE_180 = 180,
5
+ ANGLE_270 = 270
6
+ } rotate_angle_t;
7
+
8
+ static GdkPixbuf *
9
+ pixbuf_rotate(GdkPixbuf *src, rotate_angle_t angle) {
10
+ GdkPixbuf *dest;
11
+ int has_alpha;
12
+ int s_width, s_height, s_rowstride;
13
+ int d_width, d_height, d_rowstride;
14
+ guchar *s_pix;
15
+ guchar *d_pix;
16
+ guchar *sp;
17
+ guchar *dp;
18
+ int i, j, pix_width;
19
+
20
+ if (!src) return NULL;
21
+
22
+ if (angle == ANGLE_0)
23
+ return gdk_pixbuf_copy(src);
24
+
25
+ s_width = gdk_pixbuf_get_width(src);
26
+ s_height = gdk_pixbuf_get_height(src);
27
+ has_alpha = gdk_pixbuf_get_has_alpha(src);
28
+ s_rowstride = gdk_pixbuf_get_rowstride(src);
29
+ s_pix = gdk_pixbuf_get_pixels(src);
30
+
31
+ switch (angle) {
32
+ case ANGLE_90:
33
+ case ANGLE_270:
34
+ d_width = s_height;
35
+ d_height = s_width;
36
+ break;
37
+ default:
38
+ case ANGLE_0:/* Avoid compiler warnings... */
39
+ case ANGLE_180:
40
+ d_width = s_width;
41
+ d_height = s_height;
42
+ break;
43
+ }
44
+
45
+ dest = gdk_pixbuf_new(GDK_COLORSPACE_RGB, has_alpha, 8, d_width, d_height);
46
+ d_rowstride = gdk_pixbuf_get_rowstride(dest);
47
+ d_pix = gdk_pixbuf_get_pixels(dest);
48
+
49
+ pix_width = (has_alpha ? 4 : 3);
50
+
51
+ for (i = 0; i < s_height; i++) {
52
+ sp = s_pix + (i * s_rowstride);
53
+ for (j = 0; j < s_width; j++) {
54
+ switch (angle) {
55
+ case ANGLE_180:
56
+ dp = d_pix + ((d_height - i - 1) * d_rowstride) + ((d_width - j - 1) * pix_width);
57
+ break;
58
+ case ANGLE_90:
59
+ dp = d_pix + (j * d_rowstride) + ((d_width - i - 1) * pix_width);
60
+ break;
61
+ case ANGLE_270:
62
+ dp = d_pix + ((d_height - j - 1) * d_rowstride) + (i * pix_width);
63
+ break;
64
+ default:
65
+ case ANGLE_0:/* Avoid compiler warnings... */
66
+ dp = d_pix + (i * d_rowstride) + (j * pix_width);
67
+ break;
68
+ }
69
+
70
+ *(dp++) = *(sp++); /* red */
71
+ *(dp++) = *(sp++); /* green */
72
+ *(dp++) = *(sp++); /* blue */
73
+ if (has_alpha) *(dp) = *(sp++); /* alpha */
74
+ }
75
+ }
76
+
77
+ return dest;
78
+ }
79
+
@@ -0,0 +1,72 @@
1
+ #define RLUM (0.3086)
2
+ #define GLUM (0.6094)
3
+ #define BLUM (0.0820)
4
+
5
+ // Graphica Obscure
6
+ #define GO_RGB_TO_GREY(r, g, b) ((int)((RLUM * (double)r) + (GLUM * (double)g) + (BLUM * (double)b)))
7
+
8
+ static inline unsigned char pu_clamp(int x) {
9
+ return (x > 255) ? 255 : (x < 0 ? 0 : x);
10
+ }
11
+
12
+ static GdkPixbuf *pixbuf_tint(GdkPixbuf *src, GdkPixbuf *dest, int r, int g, int b, int alpha) {
13
+ int s_has_alpha, d_has_alpha;
14
+ int s_width, s_height, s_rowstride;
15
+ int d_width, d_height, d_rowstride;
16
+ guchar *s_pix, *sp;
17
+ guchar *d_pix, *dp;
18
+ int i, j, pix_width, grey;
19
+
20
+ g_return_val_if_fail(src != NULL, NULL);
21
+ g_return_val_if_fail(dest != NULL, NULL);
22
+
23
+ s_width = gdk_pixbuf_get_width(src);
24
+ s_height = gdk_pixbuf_get_height(src);
25
+ s_has_alpha = gdk_pixbuf_get_has_alpha(src);
26
+ s_rowstride = gdk_pixbuf_get_rowstride(src);
27
+ s_pix = gdk_pixbuf_get_pixels(src);
28
+
29
+ d_width = gdk_pixbuf_get_width(dest);
30
+ d_height = gdk_pixbuf_get_height(dest);
31
+ d_has_alpha = gdk_pixbuf_get_has_alpha(dest);
32
+ d_rowstride = gdk_pixbuf_get_rowstride(dest);
33
+ d_pix = gdk_pixbuf_get_pixels(dest);
34
+
35
+ g_return_val_if_fail(d_width == s_width, NULL);
36
+ g_return_val_if_fail(d_height == s_height, NULL);
37
+ g_return_val_if_fail(d_has_alpha == s_has_alpha, NULL);
38
+
39
+ pix_width = (s_has_alpha ? 4 : 3);
40
+
41
+ for (i = 0; i < s_height; i++) {
42
+ sp = s_pix;
43
+ dp = d_pix;
44
+
45
+ for (j = 0; j < s_width; j++) {
46
+ grey = GO_RGB_TO_GREY(sp[0], sp[1], sp[2]);
47
+
48
+ dp[0] = pu_clamp(pu_clamp(((int) grey + r) * alpha / 255) +
49
+ pu_clamp((int) sp[0] * (255 - alpha) / 255)); /* red */
50
+
51
+ //fprintf(stderr, "alpha=%i, r=%i, grey=%i -> %i + %i = %i\n", alpha, r, grey, pu_clamp(((int)grey + r) * alpha / 255), pu_clamp((int)sp[0] * (255 - alpha) / 255), dp[0]); /* red */
52
+
53
+ dp[1] = pu_clamp(
54
+ pu_clamp((grey + g) * alpha / 255) + pu_clamp((int) sp[1] * (255 - alpha) / 255)); /* green */
55
+ dp[2] = pu_clamp(
56
+ pu_clamp((grey + b) * alpha / 255) + pu_clamp((int) sp[2] * (255 - alpha) / 255)); /* blue */
57
+
58
+ if (s_has_alpha) {
59
+ dp[3] = sp[3]; /* alpha */
60
+ }
61
+
62
+ dp += pix_width;
63
+ sp += pix_width;
64
+ }
65
+
66
+ d_pix += d_rowstride;
67
+ s_pix += s_rowstride;
68
+ }
69
+
70
+ return dest;
71
+ }
72
+
Binary file
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cairo'
4
+ require 'gdk_pixbuf_cairo'
5
+ require 'pango'
6
+
7
+ module Morandi
8
+ # Rounded rectangle function for photo borders
9
+ module CairoExt
10
+ module_function
11
+
12
+ def rounded_rectangle(cr, x1, y1, x2, y2, x_radius = 4, y_radius = nil)
13
+ width = x2 - x1
14
+ height = y2 - y1
15
+ y_radius ||= x_radius
16
+
17
+ x_radius = [x_radius, width / 2].min
18
+ y_radius = [y_radius, height / 2].min
19
+
20
+ xr1 = x_radius
21
+ xr2 = x_radius / 2.0
22
+ yr1 = y_radius
23
+ yr2 = y_radius / 2.0
24
+
25
+ cr.new_path
26
+ cr.move_to(x1 + xr1, y1)
27
+ cr.line_to(x2 - xr1, y1)
28
+ cr.curve_to(x2 - xr2, y1, x2, y1 + yr2, x2, y1 + yr1)
29
+ cr.line_to(x2, y2 - yr1)
30
+ cr.curve_to(x2, y2 - yr2, x2 - xr2, y2, x2 - xr1, y2)
31
+ cr.line_to(x1 + xr1, y2)
32
+ cr.curve_to(x1 + xr2, y2, x1, y2 - yr2, x1, y2 - yr1)
33
+ cr.line_to(x1, y1 + yr1)
34
+ cr.curve_to(x1, y1 + yr2, x1 + xr2, y1, x1 + xr1, y1)
35
+ cr.close_path
36
+ end
37
+ end
38
+ end
39
+
40
+ # Monkey patch Cairo::Context
41
+ module Cairo
42
+ # Add Cairo::Context#set_source_pixbuf without gtk2 depdendency
43
+ class Context
44
+ def set_source_pixbuf(pixbuf, x = 0, y = 0)
45
+ set_source(pixbuf.to_cairo_image_surface, x, y)
46
+ end
47
+ end
48
+
49
+ # Add ImageSurface.to_gdk_pixbuf
50
+ # for converting back to pixbuf without exporting as PNG
51
+ class ImageSurface
52
+ def to_gdk_pixbuf
53
+ GdkPixbufCairo.surface_to_pixbuf(self)
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'gdk_pixbuf2'
4
+
5
+ module Morandi
6
+ # Utility functions relating to cropping
7
+ module CropUtils
8
+ module_function
9
+
10
+ def autocrop_coords(pixbuf_width, pixbuf_height, target_width, target_height)
11
+ return nil unless target_width
12
+
13
+ aspect = target_width.to_f / target_height
14
+ pixbuf_aspect = pixbuf_width.to_f / pixbuf_height
15
+
16
+ # TODO: this looks wrong - typically relative aspect ratios matter more
17
+ # than whether this is portrait or landscape
18
+ if pixbuf_height > pixbuf_width
19
+ # Portrait image
20
+ # Check whether the aspect ratio is greater or smaller
21
+ # ie. where constraints will hit
22
+ aspect = target_height.to_f / target_width
23
+ end
24
+
25
+ # Landscape
26
+ if aspect > pixbuf_aspect
27
+ # Width constraint - aspect-rect wider
28
+ crop_width = pixbuf_width
29
+ crop_height = (crop_width / aspect).to_i
30
+ else
31
+ # Height constraint - aspect-rect wider
32
+ crop_height = pixbuf_height
33
+ crop_width = (crop_height * aspect).to_i
34
+ end
35
+
36
+ [
37
+ ((pixbuf_width - crop_width) >> 1),
38
+ ((pixbuf_height - crop_height) >> 1),
39
+ crop_width,
40
+ crop_height
41
+ ].map(&:to_i)
42
+ end
43
+
44
+ def apply_crop(pixbuf, x_coord, y_coord, width, height, fill_col = 0xffffffff)
45
+ if x_coord.negative? ||
46
+ y_coord.negative? ||
47
+ ((x_coord + width) > pixbuf.width) ||
48
+ ((y_coord + height) > pixbuf.height)
49
+
50
+ base_pixbuf = GdkPixbuf::Pixbuf.new(
51
+ colorspace: GdkPixbuf::Colorspace::RGB,
52
+ has_alpha: false,
53
+ bits_per_sample: 8,
54
+ width: width,
55
+ height: height
56
+ )
57
+ base_pixbuf.fill!(fill_col)
58
+
59
+ offset_x = [x_coord, 0].max
60
+ offset_y = [y_coord, 0].max
61
+ copy_w = [width, pixbuf.width - offset_x].min
62
+ copy_h = [height, pixbuf.height - offset_y].min
63
+
64
+ paste_x = [x_coord, 0].min * -1
65
+ paste_y = [y_coord, 0].min * -1
66
+
67
+ copy_w = base_pixbuf.width - paste_x if copy_w + paste_x > base_pixbuf.width
68
+ copy_h = base_pixbuf.height - paste_y if copy_h + paste_y > base_pixbuf.height
69
+
70
+ base_pixbuf.composite!(
71
+ pixbuf,
72
+ dest_x: paste_x,
73
+ dest_y: paste_y,
74
+ dest_width: copy_w,
75
+ dest_height: copy_h,
76
+ offset_x: paste_x - offset_x,
77
+ offset_y: paste_y - offset_y,
78
+ scale_x: 1,
79
+ scale_y: 1,
80
+ interpolation_type: :hyper,
81
+ overall_alpha: 255
82
+ )
83
+ pixbuf = base_pixbuf
84
+ else
85
+ x_coord = x_coord.clamp(0, pixbuf.width)
86
+ y_coord = y_coord.clamp(0, pixbuf.height)
87
+ width = width.clamp(1, pixbuf.width - x_coord)
88
+ height = height.clamp(1, pixbuf.height - y_coord)
89
+
90
+ pixbuf = pixbuf.subpixbuf(x_coord, y_coord, width, height)
91
+ end
92
+ pixbuf
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Morandi
4
+ class Error < StandardError
5
+ end
6
+
7
+ class CorruptImageError < Error
8
+ end
9
+
10
+ class UnknownTypeError < Error
11
+ end
12
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Morandi
4
+ # Base Image Op class
5
+ # @!visibility private
6
+ class ImageOperation
7
+ class << self
8
+ def new_from_hash(hash)
9
+ op = allocate
10
+ hash.each_pair do |key, val|
11
+ op.respond_to?(key.intern) && op.instance_variable_set("@#{key}", val)
12
+ end
13
+ op
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def create_pixbuf_from_image_surface(type, width, height)
20
+ surface = Cairo::ImageSurface.new(type, width, height)
21
+ cr = Cairo::Context.new(surface)
22
+
23
+ yield(cr)
24
+
25
+ final_pb = surface.to_gdk_pixbuf
26
+ cr.destroy
27
+ surface.destroy
28
+ final_pb
29
+ end
30
+ end
31
+ end