OpenShot Library | libopenshot  0.2.4
ColorShift.cpp
Go to the documentation of this file.
1 /**
2  * @file
3  * @brief Source file for Color Shift effect class
4  * @author Jonathan Thomas <jonathan@openshot.org>
5  *
6  * @ref License
7  */
8 
9 /* LICENSE
10  *
11  * Copyright (c) 2008-2019 OpenShot Studios, LLC
12  * <http://www.openshotstudios.com/>. This file is part of
13  * OpenShot Library (libopenshot), an open-source project dedicated to
14  * delivering high quality video editing and animation solutions to the
15  * world. For more information visit <http://www.openshot.org/>.
16  *
17  * OpenShot Library (libopenshot) is free software: you can redistribute it
18  * and/or modify it under the terms of the GNU Lesser General Public License
19  * as published by the Free Software Foundation, either version 3 of the
20  * License, or (at your option) any later version.
21  *
22  * OpenShot Library (libopenshot) is distributed in the hope that it will be
23  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25  * GNU Lesser General Public License for more details.
26  *
27  * You should have received a copy of the GNU Lesser General Public License
28  * along with OpenShot Library. If not, see <http://www.gnu.org/licenses/>.
29  */
30 
31 #include "../../include/effects/ColorShift.h"
32 
33 using namespace openshot;
34 
35 /// Blank constructor, useful when using Json to load the effect properties
36 ColorShift::ColorShift() : red_x(-0.05), red_y(0.0), green_x(0.05), green_y(0.0), blue_x(0.0), blue_y(0.0), alpha_x(0.0), alpha_y(0.0) {
37  // Init effect properties
38  init_effect_details();
39 }
40 
41 // Default constructor
43  red_x(red_x), red_y(red_y), green_x(green_x), green_y(green_y), blue_x(blue_x), blue_y(blue_y), alpha_x(alpha_x), alpha_y(alpha_y)
44 {
45  // Init effect properties
46  init_effect_details();
47 }
48 
49 // Init effect settings
50 void ColorShift::init_effect_details()
51 {
52  /// Initialize the values of the EffectInfo struct.
54 
55  /// Set the effect info
56  info.class_name = "ColorShift";
57  info.name = "Color Shift";
58  info.description = "Shift the colors of an image up, down, left, and right (with infinite wrapping).";
59  info.has_audio = false;
60  info.has_video = true;
61 }
62 
63 // This method is required for all derived classes of EffectBase, and returns a
64 // modified openshot::Frame object
65 std::shared_ptr<Frame> ColorShift::GetFrame(std::shared_ptr<Frame> frame, int64_t frame_number)
66 {
67  // Get the frame's image
68  std::shared_ptr<QImage> frame_image = frame->GetImage();
69  unsigned char *pixels = (unsigned char *) frame_image->bits();
70 
71  // Get image size
72  int frame_image_width = frame_image->width();
73  int frame_image_height = frame_image->height();
74 
75  // Get the current shift amount, and clamp to range (-1 to 1 range)
76  // Red Keyframes
77  float red_x_shift = red_x.GetValue(frame_number);
78  int red_x_shift_limit = round(frame_image_width * fmod(abs(red_x_shift), 1.0));
79  float red_y_shift = red_y.GetValue(frame_number);
80  int red_y_shift_limit = round(frame_image_height * fmod(abs(red_y_shift), 1.0));
81  // Green Keyframes
82  float green_x_shift = green_x.GetValue(frame_number);
83  int green_x_shift_limit = round(frame_image_width * fmod(abs(green_x_shift), 1.0));
84  float green_y_shift = green_y.GetValue(frame_number);
85  int green_y_shift_limit = round(frame_image_height * fmod(abs(green_y_shift), 1.0));
86  // Blue Keyframes
87  float blue_x_shift = blue_x.GetValue(frame_number);
88  int blue_x_shift_limit = round(frame_image_width * fmod(abs(blue_x_shift), 1.0));
89  float blue_y_shift = blue_y.GetValue(frame_number);
90  int blue_y_shift_limit = round(frame_image_height * fmod(abs(blue_y_shift), 1.0));
91  // Alpha Keyframes
92  float alpha_x_shift = alpha_x.GetValue(frame_number);
93  int alpha_x_shift_limit = round(frame_image_width * fmod(abs(alpha_x_shift), 1.0));
94  float alpha_y_shift = alpha_y.GetValue(frame_number);
95  int alpha_y_shift_limit = round(frame_image_height * fmod(abs(alpha_y_shift), 1.0));
96 
97 
98  // Make temp copy of pixels
99  unsigned char *temp_image = new unsigned char[frame_image_width * frame_image_height * 4]();
100  memcpy(temp_image, pixels, sizeof(char) * frame_image_width * frame_image_height * 4);
101 
102  // Init position of current row and pixel
103  int starting_row_index = 0;
104  int byte_index = 0;
105 
106  // Init RGBA values
107  unsigned char R = 0;
108  unsigned char G = 0;
109  unsigned char B = 0;
110  unsigned char A = 0;
111 
112  int red_starting_row_index = 0;
113  int green_starting_row_index = 0;
114  int blue_starting_row_index = 0;
115  int alpha_starting_row_index = 0;
116 
117  int red_pixel_offset = 0;
118  int green_pixel_offset = 0;
119  int blue_pixel_offset = 0;
120  int alpha_pixel_offset = 0;
121 
122  // Loop through rows of pixels
123  for (int row = 0; row < frame_image_height; row++) {
124  for (int col = 0; col < frame_image_width; col++) {
125  // Get position of current row and pixel
126  starting_row_index = row * frame_image_width * 4;
127  byte_index = starting_row_index + (col * 4);
128  red_starting_row_index = starting_row_index;
129  green_starting_row_index = starting_row_index;
130  blue_starting_row_index = starting_row_index;
131  alpha_starting_row_index = starting_row_index;
132 
133 
134  red_pixel_offset = 0;
135  green_pixel_offset = 0;
136  blue_pixel_offset = 0;
137  alpha_pixel_offset = 0;
138 
139  // Get the RGBA value from each pixel (depending on offset)
140  R = temp_image[byte_index];
141  G = temp_image[byte_index + 1];
142  B = temp_image[byte_index + 2];
143  A = temp_image[byte_index + 3];
144 
145  // Shift X
146  if (red_x_shift > 0.0)
147  red_pixel_offset = (col + red_x_shift_limit) % frame_image_width;
148  if (red_x_shift < 0.0)
149  red_pixel_offset = (frame_image_width + col - red_x_shift_limit) % frame_image_width;
150  if (green_x_shift > 0.0)
151  green_pixel_offset = (col + green_x_shift_limit) % frame_image_width;
152  if (green_x_shift < 0.0)
153  green_pixel_offset = (frame_image_width + col - green_x_shift_limit) % frame_image_width;
154  if (blue_x_shift > 0.0)
155  blue_pixel_offset = (col + blue_x_shift_limit) % frame_image_width;
156  if (blue_x_shift < 0.0)
157  blue_pixel_offset = (frame_image_width + col - blue_x_shift_limit) % frame_image_width;
158  if (alpha_x_shift > 0.0)
159  alpha_pixel_offset = (col + alpha_x_shift_limit) % frame_image_width;
160  if (alpha_x_shift < 0.0)
161  alpha_pixel_offset = (frame_image_width + col - alpha_x_shift_limit) % frame_image_width;
162 
163  // Shift Y
164  if (red_y_shift > 0.0)
165  red_starting_row_index = ((row + red_y_shift_limit) % frame_image_height) * frame_image_width * 4;
166  if (red_y_shift < 0.0)
167  red_starting_row_index = ((frame_image_height + row - red_y_shift_limit) % frame_image_height) * frame_image_width * 4;
168  if (green_y_shift > 0.0)
169  green_starting_row_index = ((row + green_y_shift_limit) % frame_image_height) * frame_image_width * 4;
170  if (green_y_shift < 0.0)
171  green_starting_row_index = ((frame_image_height + row - green_y_shift_limit) % frame_image_height) * frame_image_width * 4;
172  if (blue_y_shift > 0.0)
173  blue_starting_row_index = ((row + blue_y_shift_limit) % frame_image_height) * frame_image_width * 4;
174  if (blue_y_shift < 0.0)
175  blue_starting_row_index = ((frame_image_height + row - blue_y_shift_limit) % frame_image_height) * frame_image_width * 4;
176  if (alpha_y_shift > 0.0)
177  alpha_starting_row_index = ((row + alpha_y_shift_limit) % frame_image_height) * frame_image_width * 4;
178  if (alpha_y_shift < 0.0)
179  alpha_starting_row_index = ((frame_image_height + row - alpha_y_shift_limit) % frame_image_height) * frame_image_width * 4;
180 
181  // Copy new values to this pixel
182  pixels[red_starting_row_index + 0 + (red_pixel_offset * 4)] = R;
183  pixels[green_starting_row_index + 1 + (green_pixel_offset * 4)] = G;
184  pixels[blue_starting_row_index + 2 + (blue_pixel_offset * 4)] = B;
185  pixels[alpha_starting_row_index + 3 + (alpha_pixel_offset * 4)] = A;
186  }
187  }
188 
189  // Delete arrays
190  delete[] temp_image;
191 
192  // return the modified frame
193  return frame;
194 }
195 
196 // Generate JSON string of this object
197 std::string ColorShift::Json() {
198 
199  // Return formatted string
200  return JsonValue().toStyledString();
201 }
202 
203 // Generate Json::JsonValue for this object
204 Json::Value ColorShift::JsonValue() {
205 
206  // Create root json object
207  Json::Value root = EffectBase::JsonValue(); // get parent properties
208  root["type"] = info.class_name;
209  root["red_x"] = red_x.JsonValue();
210  root["red_y"] = red_y.JsonValue();
211  root["green_x"] = green_x.JsonValue();
212  root["green_y"] = green_y.JsonValue();
213  root["blue_x"] = blue_x.JsonValue();
214  root["blue_y"] = blue_y.JsonValue();
215  root["alpha_x"] = alpha_x.JsonValue();
216  root["alpha_y"] = alpha_y.JsonValue();
217 
218  // return JsonValue
219  return root;
220 }
221 
222 // Load JSON string into this object
223 void ColorShift::SetJson(std::string value) {
224 
225  // Parse JSON string into JSON objects
226  Json::Value root;
227  Json::CharReaderBuilder rbuilder;
228  Json::CharReader* reader(rbuilder.newCharReader());
229 
230  std::string errors;
231  bool success = reader->parse( value.c_str(),
232  value.c_str() + value.size(), &root, &errors );
233  delete reader;
234 
235  if (!success)
236  // Raise exception
237  throw InvalidJSON("JSON could not be parsed (or is invalid)");
238 
239  try
240  {
241  // Set all values that match
242  SetJsonValue(root);
243  }
244  catch (const std::exception& e)
245  {
246  // Error parsing JSON (or missing keys)
247  throw InvalidJSON("JSON is invalid (missing keys or invalid data types)");
248  }
249 }
250 
251 // Load Json::JsonValue into this object
252 void ColorShift::SetJsonValue(Json::Value root) {
253 
254  // Set parent data
256 
257  // Set data from Json (if key is found)
258  if (!root["red_x"].isNull())
259  red_x.SetJsonValue(root["red_x"]);
260  if (!root["red_y"].isNull())
261  red_y.SetJsonValue(root["red_y"]);
262  if (!root["green_x"].isNull())
263  green_x.SetJsonValue(root["green_x"]);
264  if (!root["green_y"].isNull())
265  green_y.SetJsonValue(root["green_y"]);
266  if (!root["blue_x"].isNull())
267  blue_x.SetJsonValue(root["blue_x"]);
268  if (!root["blue_y"].isNull())
269  blue_y.SetJsonValue(root["blue_y"]);
270  if (!root["alpha_x"].isNull())
271  alpha_x.SetJsonValue(root["alpha_x"]);
272  if (!root["alpha_y"].isNull())
273  alpha_y.SetJsonValue(root["alpha_y"]);
274 }
275 
276 // Get all properties for a specific frame
277 std::string ColorShift::PropertiesJSON(int64_t requested_frame) {
278 
279  // Generate JSON properties list
280  Json::Value root;
281  root["id"] = add_property_json("ID", 0.0, "string", Id(), NULL, -1, -1, true, requested_frame);
282  root["position"] = add_property_json("Position", Position(), "float", "", NULL, 0, 1000 * 60 * 30, false, requested_frame);
283  root["layer"] = add_property_json("Track", Layer(), "int", "", NULL, 0, 20, false, requested_frame);
284  root["start"] = add_property_json("Start", Start(), "float", "", NULL, 0, 1000 * 60 * 30, false, requested_frame);
285  root["end"] = add_property_json("End", End(), "float", "", NULL, 0, 1000 * 60 * 30, false, requested_frame);
286  root["duration"] = add_property_json("Duration", Duration(), "float", "", NULL, 0, 1000 * 60 * 30, true, requested_frame);
287 
288  // Keyframes
289  root["red_x"] = add_property_json("Red X Shift", red_x.GetValue(requested_frame), "float", "", &red_x, -1, 1, false, requested_frame);
290  root["red_y"] = add_property_json("Red Y Shift", red_y.GetValue(requested_frame), "float", "", &red_y, -1, 1, false, requested_frame);
291  root["green_x"] = add_property_json("Green X Shift", green_x.GetValue(requested_frame), "float", "", &green_x, -1, 1, false, requested_frame);
292  root["green_y"] = add_property_json("Green Y Shift", green_y.GetValue(requested_frame), "float", "", &green_y, -1, 1, false, requested_frame);
293  root["blue_x"] = add_property_json("Blue X Shift", blue_x.GetValue(requested_frame), "float", "", &blue_x, -1, 1, false, requested_frame);
294  root["blue_y"] = add_property_json("Blue Y Shift", blue_y.GetValue(requested_frame), "float", "", &blue_y, -1, 1, false, requested_frame);
295  root["alpha_x"] = add_property_json("Alpha X Shift", alpha_x.GetValue(requested_frame), "float", "", &alpha_x, -1, 1, false, requested_frame);
296  root["alpha_y"] = add_property_json("Alpha Y Shift", alpha_y.GetValue(requested_frame), "float", "", &alpha_y, -1, 1, false, requested_frame);
297 
298  // Return formatted string
299  return root.toStyledString();
300 }
Keyframe alpha_y
Shift the Alpha Y coordinates (up or down)
Definition: ColorShift.h:67
Keyframe red_x
Shift the Red X coordinates (left or right)
Definition: ColorShift.h:60
Keyframe blue_x
Shift the Blue X coordinates (left or right)
Definition: ColorShift.h:64
Keyframe green_y
Shift the Green Y coordinates (up or down)
Definition: ColorShift.h:63
float End()
Get end position (in seconds) of clip (trim end of video)
Definition: ClipBase.h:80
Keyframe green_x
Shift the Green X coordinates (left or right)
Definition: ColorShift.h:62
int Layer()
Get layer of clip on timeline (lower number is covered by higher numbers)
Definition: ClipBase.h:78
virtual Json::Value JsonValue()=0
Generate Json::JsonValue for this object.
Definition: EffectBase.cpp:84
void SetJsonValue(Json::Value root)
Load Json::JsonValue into this object.
Definition: KeyFrame.cpp:374
bool has_audio
Determines if this effect manipulates the audio of a frame.
Definition: EffectBase.h:56
std::shared_ptr< Frame > GetFrame(std::shared_ptr< Frame > frame, int64_t frame_number)
This method is required for all derived classes of EffectBase, and returns a modified openshot::Frame...
Definition: ColorShift.cpp:65
void SetJsonValue(Json::Value root)
Load Json::JsonValue into this object.
Definition: ColorShift.cpp:252
Keyframe alpha_x
Shift the Alpha X coordinates (left or right)
Definition: ColorShift.h:66
Keyframe red_y
Shift the Red Y coordinates (up or down)
Definition: ColorShift.h:61
std::string Id()
Get basic properties.
Definition: ClipBase.h:76
float Position()
Get position on timeline (in seconds)
Definition: ClipBase.h:77
std::string Json()
Get and Set JSON methods.
Definition: ColorShift.cpp:197
virtual void SetJsonValue(Json::Value root)=0
Load Json::JsonValue into this object.
Definition: EffectBase.cpp:129
std::string class_name
The class name of the effect.
Definition: EffectBase.h:52
std::string name
The name of the effect.
Definition: EffectBase.h:53
Json::Value JsonValue()
Generate Json::JsonValue for this object.
Definition: ColorShift.cpp:204
Json::Value add_property_json(std::string name, float value, std::string type, std::string memo, Keyframe *keyframe, float min_value, float max_value, bool readonly, int64_t requested_frame)
Generate JSON for a property.
Definition: ClipBase.cpp:68
This namespace is the default namespace for all code in the openshot library.
Json::Value JsonValue() const
Generate Json::JsonValue for this object.
Definition: KeyFrame.cpp:329
std::string description
The description of this effect and what it does.
Definition: EffectBase.h:54
void SetJson(std::string value)
Load JSON string into this object.
Definition: ColorShift.cpp:223
bool has_video
Determines if this effect manipulates the image of a frame.
Definition: EffectBase.h:55
Exception for invalid JSON.
Definition: Exceptions.h:205
double GetValue(int64_t index) const
Get the value at a specific index.
Definition: KeyFrame.cpp:262
A Keyframe is a collection of Point instances, which is used to vary a number or property over time...
Definition: KeyFrame.h:64
std::string PropertiesJSON(int64_t requested_frame)
Definition: ColorShift.cpp:277
float Duration()
Get the length of this clip (in seconds)
Definition: ClipBase.h:81
float Start()
Get start position (in seconds) of clip (trim start of video)
Definition: ClipBase.h:79
EffectInfoStruct info
Information about the current effect.
Definition: EffectBase.h:73
Keyframe blue_y
Shift the Blue Y coordinates (up or down)
Definition: ColorShift.h:65
ColorShift()
Blank constructor, useful when using Json to load the effect properties.
Definition: ColorShift.cpp:36