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