1
2
3
4
5
6
7
8
9
10
11
12
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
67
68
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
use crate::{
    geometry::{Coords, Rect},
    server::Server,
};
use filter::Filter;

mod builder;
pub mod filter;

#[derive(strum::AsRefStr)]
#[strum(serialize_all = "lowercase")]
pub enum HAlignment {
    Left,
    Center,
    Right,
}

#[derive(strum::AsRefStr)]
#[strum(serialize_all = "lowercase")]
pub enum VAlignment {
    Top,
    Middle,
    Bottom,
}

#[derive(Default)]
pub enum Trim {
    #[default]
    TopLeft,
    BottomRight,
}

#[derive(Default)]
pub enum FitIn {
    #[default]
    Default,
    Adaptive,
    Full,
}

pub enum ResponseMode {
    /// The metadata endpoint has **ALL** the options that the image one has,
    /// but instead of actually performing the operations in the image, it just simulates the operations.
    ///
    /// Since it has the same options as the other endpoint, we won’t repeat all of them.
    /// To use the metadata endpoint, just add a /meta in the beginning of the url.
    ///
    /// Say we have the following crop URL:
    ///
    /// http://my-server.thumbor.org/unsafe/-300x-200/left/top/smart/path/to/my/nice/image.jpg
    ///
    /// If we want the metadata on what thumbor would do, just change the url to be
    ///
    /// http://my-server.thumbor.org/unsafe/meta/-300x-200/left/top/smart/path/to/my/nice/image.jpg
    ///
    /// After the processing is finished, thumbor will return a json object containing metadata
    /// on the image and the operations that would have been performed.
    ///
    /// The json looks like this:
    /// ```json
    /// {
    ///     thumbor: {
    ///         source: {
    ///             url: "path/to/my/nice/image.jpg",
    ///             width: 800,
    ///             height: 600
    ///         },
    ///         operations: [
    ///             {
    ///                 type: "crop",
    ///                 left: 10,
    ///                 top: 10,
    ///                 right: 300,
    ///                 bottom: 200
    ///             },
    ///             {
    ///                 type: "resize",
    ///                 width: 300,
    ///                 height: 200
    ///             },
    ///             { type: "flip_horizontally" },
    ///             { type: "flip_vertically" }
    ///         ]
    ///     }
    /// }
    /// ```
    Metadata,

    /// The debug endpoint helps debug focal points by drawing a rectangle around them.
    Debug,
}

/// An endpoint is a representation of a Thumbor image URL.
///
/// # Usage
///
/// [`EndpointBuilder`] is used to create an [`Endpoint`] instance.
///
/// You can then use the [`Endpoint::to_url`] method to generate the URL,
/// or the [`Endpoint::to_path`] method to get the path (without the server origin).
///
/// The format of the image URI depends heavily on the image loader you are using.
/// Thumbor comes pre-packaged with an HTTP loader and a Filesystem loader.
/// - If you use the HTTP loader, the URI corresponds to the image complete URI.
/// - If you use the Filesystem loader, the URI corresponds to the path of the image from the images root.
#[derive(Default, bon::Builder)]
#[builder(start_fn = with_server)]
pub struct Endpoint {
    #[builder(start_fn)]
    server: Server,
    response: Option<ResponseMode>,

    /// Removing surrounding space in images can be done using the trim option.
    ///
    /// Unless specified trim assumes the top-left pixel color and no tolerance
    /// (more on tolerance below).
    ///
    /// Trim also supports color tolerance. The euclidean distance between the colors
    /// of the reference pixel and the surrounding pixels is used. If the distance is
    /// within the tolerance they’ll get trimmed. For a RGB image the tolerance would
    /// be within the range 0-442.
    trim: Option<Trim>,

    /// The manual crop is entirely optional. This is very useful for applications
    /// that provide custom real-time cropping capabilities to their users.
    ///
    /// The manual crop part of the url takes two points as arguments, separated by a colon.
    /// The first point is the left-top point of the cropping rectangle.
    /// The second point is the right-bottom point.
    ///
    /// This crop is performed before the rest of the operations, so it can be used as
    /// a prepare step before resizing and smart-cropping. It is very useful when you
    /// just need to get that celebrity face on a big picture full of people, as an example.
    #[builder(into)]
    crop: Option<Rect>,

    /// The fit-in argument specifies that the image should not be auto-cropped and
    /// auto-resized to be **EXACTLY** the specified size, and should be fit in an imaginary
    /// box of “E” width and “F” height, instead.
    ///
    /// Consider an image of *800px* x *600px*, and a fit of *300px* x *200px*.
    /// This is how thumbor would resize it:
    ///
    /// ![](https://thumbor.readthedocs.io/en/latest/_images/vertical-fit-in.png)
    ///
    /// Consider an image of *400px* x *600px*, and a fit of *300px* x *200px*.
    /// This is how thumbor would resize it:
    ///
    /// ![](https://thumbor.readthedocs.io/en/latest/_images/horizontal-fit-in.png)
    ///
    /// This is very useful when you need to fit an image somewhere, but you have no idea about the original image dimensions.
    ///
    /// If a full fit-in is used, instead of using the largest size for cropping it uses the smallest one, so in the above scenarios:
    ///
    /// For the image of *800px* x *600px*, with a full fit-in of *300px* x *200px*, we would get an image of *300px* x *225px*.
    ///
    /// For the image of *400px* x *600px*, with a full fit-in of *300px* x *200px*, we would get an image of *300px* x *450px*.
    fit_in: Option<FitIn>,
    #[builder(into)]
    resize: Option<Coords>,
    h_align: Option<HAlignment>,
    v_align: Option<VAlignment>,

    /// Thumbor allows for usage of a filter pipeline that will be applied sequentially to the image.
    #[builder(default, into)]
    filters: Vec<Filter>,

    /// Thumbor uses some very advanced techniques for obtaining important points of
    /// the image (referred to as Focal Points in the rest of this documentation).
    ///
    /// Even though Thumbor comes with facial recognition of Focal Points as well as
    /// feature recognition, you can easily implement your own detectors.
    ///
    /// If you use it in the url, smart cropping will be performed and will override both
    /// horizontal and vertical alignments if it finds any Focal Points.
    ///
    /// **The default value (in case it is omitted) for this option is not to use smart cropping.**
    #[builder(default)]
    smart: bool,
}