OpenShot Library | libopenshot  0.2.5
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.0), red_y(0.0), green_x(0.0), 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
42 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) :
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(fabs(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(fabs(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(fabs(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(fabs(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(fabs(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(fabs(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(fabs(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(fabs(alpha_y_shift), 1.0));
96 
97  // Make temp copy of pixels
98  unsigned char *temp_image = new unsigned char[frame_image_width * frame_image_height * 4]();
99  memcpy(temp_image, pixels, sizeof(char) * frame_image_width * frame_image_height * 4);
100 
101  // Init position of current row and pixel
102  int starting_row_index = 0;
103  int byte_index = 0;
104 
105  // Init RGBA values
106  unsigned char R = 0;
107  unsigned char G = 0;
108  unsigned char B = 0;
109  unsigned char A = 0;
110 
111  int red_starting_row_index = 0;
112  int green_starting_row_index = 0;
113  int blue_starting_row_index = 0;
114  int alpha_starting_row_index = 0;
115 
116  int red_pixel_offset = 0;
117  int green_pixel_offset = 0;
118  int blue_pixel_offset = 0;
119  int alpha_pixel_offset = 0;
120 
121  // Loop through rows of pixels
122  for (int row = 0; row < frame_image_height; row++) {
123  for (int col = 0; col < frame_image_width; col++) {
124  // Get position of current row and pixel
125  starting_row_index = row * frame_image_width * 4;
126  byte_index = starting_row_index + (col * 4);
127  red_starting_row_index = starting_row_index;
128  green_starting_row_index = starting_row_index;
129  blue_starting_row_index = starting_row_index;
130  alpha_starting_row_index = starting_row_index;
131 
132  red_pixel_offset = 0;
133  green_pixel_offset = 0;
134  blue_pixel_offset = 0;
135  alpha_pixel_offset = 0;
136 
137  // Get the RGBA value from each pixel (depending on offset)
138  R = temp_image[byte_index];
139  G = temp_image[byte_index + 1];
140  B = temp_image[byte_index + 2];
141  A = temp_image[byte_index + 3];
142 
143  // Shift X
144  if (red_x_shift > 0.0)
145  red_pixel_offset = (col + red_x_shift_limit) % frame_image_width;
146  if (red_x_shift < 0.0)
147  red_pixel_offset = (frame_image_width + col - red_x_shift_limit) % frame_image_width;
148  if (green_x_shift > 0.0)
149  green_pixel_offset = (col + green_x_shift_limit) % frame_image_width;
150  if (green_x_shift < 0.0)
151  green_pixel_offset = (frame_image_width + col - green_x_shift_limit) % frame_image_width;
152  if (blue_x_shift > 0.0)
153  blue_pixel_offset = (col + blue_x_shift_limit) % frame_image_width;
154  if (blue_x_shift < 0.0)
155  blue_pixel_offset = (frame_image_width + col - blue_x_shift_limit) % frame_image_width;
156  if (alpha_x_shift > 0.0)
157  alpha_pixel_offset = (col + alpha_x_shift_limit) % frame_image_width;
158  if (alpha_x_shift < 0.0)
159  alpha_pixel_offset = (frame_image_width + col - alpha_x_shift_limit) % frame_image_width;
160 
161  // Shift Y
162  if (red_y_shift > 0.0)
163  red_starting_row_index = ((row + red_y_shift_limit) % frame_image_height) * frame_image_width * 4;
164  if (red_y_shift < 0.0)
165  red_starting_row_index = ((frame_image_height + row - red_y_shift_limit) % frame_image_height) * frame_image_width * 4;
166  if (green_y_shift > 0.0)
167  green_starting_row_index = ((row + green_y_shift_limit) % frame_image_height) * frame_image_width * 4;
168  if (green_y_shift < 0.0)
169  green_starting_row_index = ((frame_image_height + row - green_y_shift_limit) % frame_image_height) * frame_image_width * 4;
170  if (blue_y_shift > 0.0)
171  blue_starting_row_index = ((row + blue_y_shift_limit) % frame_image_height) * frame_image_width * 4;
172  if (blue_y_shift < 0.0)
173  blue_starting_row_index = ((frame_image_height + row - blue_y_shift_limit) % frame_image_height) * frame_image_width * 4;
174  if (alpha_y_shift > 0.0)
175  alpha_starting_row_index = ((row + alpha_y_shift_limit) % frame_image_height) * frame_image_width * 4;
176  if (alpha_y_shift < 0.0)
177  alpha_starting_row_index = ((frame_image_height + row - alpha_y_shift_limit) % frame_image_height) * frame_image_width * 4;
178 
179  // Copy new values to this pixel
180  pixels[red_starting_row_index + 0 + (red_pixel_offset * 4)] = R;
181  pixels[green_starting_row_index + 1 + (green_pixel_offset * 4)] = G;
182  pixels[blue_starting_row_index + 2 + (blue_pixel_offset * 4)] = B;
183  pixels[alpha_starting_row_index + 3 + (alpha_pixel_offset * 4)] = A;
184  }
185  }
186 
187  // Delete arrays
188  delete[] temp_image;
189 
190  // return the modified frame
191  return frame;
192 }
193 
194 // Generate JSON string of this object
195 std::string ColorShift::Json() const {
196 
197  // Return formatted string
198  return JsonValue().toStyledString();
199 }
200 
201 // Generate Json::Value for this object
202 Json::Value ColorShift::JsonValue() const {
203 
204  // Create root json object
205  Json::Value root = EffectBase::JsonValue(); // get parent properties
206  root["type"] = info.class_name;
207  root["red_x"] = red_x.JsonValue();
208  root["red_y"] = red_y.JsonValue();
209  root["green_x"] = green_x.JsonValue();
210  root["green_y"] = green_y.JsonValue();
211  root["blue_x"] = blue_x.JsonValue();
212  root["blue_y"] = blue_y.JsonValue();
213  root["alpha_x"] = alpha_x.JsonValue();
214  root["alpha_y"] = alpha_y.JsonValue();
215 
216  // return JsonValue
217  return root;
218 }
219 
220 // Load JSON string into this object
221 void ColorShift::SetJson(const std::string value) {
222 
223  // Parse JSON string into JSON objects
224  try
225  {
226  const Json::Value root = openshot::stringToJson(value);
227  // Set all values that match
228  SetJsonValue(root);
229  }
230  catch (const std::exception& e)
231  {
232  // Error parsing JSON (or missing keys)
233  throw InvalidJSON("JSON is invalid (missing keys or invalid data types)");
234  }
235 }
236 
237 // Load Json::Value into this object
238 void ColorShift::SetJsonValue(const Json::Value root) {
239 
240  // Set parent data
242 
243  // Set data from Json (if key is found)
244  if (!root["red_x"].isNull())
245  red_x.SetJsonValue(root["red_x"]);
246  if (!root["red_y"].isNull())
247  red_y.SetJsonValue(root["red_y"]);
248  if (!root["green_x"].isNull())
249  green_x.SetJsonValue(root["green_x"]);
250  if (!root["green_y"].isNull())
251  green_y.SetJsonValue(root["green_y"]);
252  if (!root["blue_x"].isNull())
253  blue_x.SetJsonValue(root["blue_x"]);
254  if (!root["blue_y"].isNull())
255  blue_y.SetJsonValue(root["blue_y"]);
256  if (!root["alpha_x"].isNull())
257  alpha_x.SetJsonValue(root["alpha_x"]);
258  if (!root["alpha_y"].isNull())
259  alpha_y.SetJsonValue(root["alpha_y"]);
260 }
261 
262 // Get all properties for a specific frame
263 std::string ColorShift::PropertiesJSON(int64_t requested_frame) const {
264 
265  // Generate JSON properties list
266  Json::Value root;
267  root["id"] = add_property_json("ID", 0.0, "string", Id(), NULL, -1, -1, true, requested_frame);
268  root["position"] = add_property_json("Position", Position(), "float", "", NULL, 0, 1000 * 60 * 30, false, requested_frame);
269  root["layer"] = add_property_json("Track", Layer(), "int", "", NULL, 0, 20, false, requested_frame);
270  root["start"] = add_property_json("Start", Start(), "float", "", NULL, 0, 1000 * 60 * 30, false, requested_frame);
271  root["end"] = add_property_json("End", End(), "float", "", NULL, 0, 1000 * 60 * 30, false, requested_frame);
272  root["duration"] = add_property_json("Duration", Duration(), "float", "", NULL, 0, 1000 * 60 * 30, true, requested_frame);
273 
274  // Keyframes
275  root["red_x"] = add_property_json("Red X Shift", red_x.GetValue(requested_frame), "float", "", &red_x, -1, 1, false, requested_frame);
276  root["red_y"] = add_property_json("Red Y Shift", red_y.GetValue(requested_frame), "float", "", &red_y, -1, 1, false, requested_frame);
277  root["green_x"] = add_property_json("Green X Shift", green_x.GetValue(requested_frame), "float", "", &green_x, -1, 1, false, requested_frame);
278  root["green_y"] = add_property_json("Green Y Shift", green_y.GetValue(requested_frame), "float", "", &green_y, -1, 1, false, requested_frame);
279  root["blue_x"] = add_property_json("Blue X Shift", blue_x.GetValue(requested_frame), "float", "", &blue_x, -1, 1, false, requested_frame);
280  root["blue_y"] = add_property_json("Blue Y Shift", blue_y.GetValue(requested_frame), "float", "", &blue_y, -1, 1, false, requested_frame);
281  root["alpha_x"] = add_property_json("Alpha X Shift", alpha_x.GetValue(requested_frame), "float", "", &alpha_x, -1, 1, false, requested_frame);
282  root["alpha_y"] = add_property_json("Alpha Y Shift", alpha_y.GetValue(requested_frame), "float", "", &alpha_y, -1, 1, false, requested_frame);
283 
284  // Return formatted string
285  return root.toStyledString();
286 }
openshot::ClipBase::add_property_json
Json::Value add_property_json(std::string name, float value, std::string type, std::string memo, const Keyframe *keyframe, float min_value, float max_value, bool readonly, int64_t requested_frame) const
Generate JSON for a property.
Definition: ClipBase.cpp:68
openshot::ColorShift::alpha_y
Keyframe alpha_y
Shift the Alpha Y coordinates (up or down)
Definition: ColorShift.h:67
openshot::stringToJson
const Json::Value stringToJson(const std::string value)
Definition: Json.cpp:33
openshot::ColorShift::red_x
Keyframe red_x
Shift the Red X coordinates (left or right)
Definition: ColorShift.h:60
openshot::EffectBase::info
EffectInfoStruct info
Information about the current effect.
Definition: EffectBase.h:73
openshot
This namespace is the default namespace for all code in the openshot library.
Definition: AudioBufferSource.h:38
openshot::ColorShift::ColorShift
ColorShift()
Blank constructor, useful when using Json to load the effect properties.
Definition: ColorShift.cpp:36
openshot::ColorShift::green_x
Keyframe green_x
Shift the Green X coordinates (left or right)
Definition: ColorShift.h:62
openshot::ColorShift::SetJsonValue
void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
Definition: ColorShift.cpp:238
openshot::ColorShift::blue_x
Keyframe blue_x
Shift the Blue X coordinates (left or right)
Definition: ColorShift.h:64
openshot::Keyframe::SetJsonValue
void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
Definition: KeyFrame.cpp:362
openshot::EffectBase::SetJsonValue
virtual void SetJsonValue(const Json::Value root)=0
Load Json::Value into this object.
Definition: EffectBase.cpp:117
openshot::EffectBase::JsonValue
virtual Json::Value JsonValue() const =0
Generate Json::Value for this object.
Definition: EffectBase.cpp:84
openshot::ColorShift::PropertiesJSON
std::string PropertiesJSON(int64_t requested_frame) const override
Definition: ColorShift.cpp:263
openshot::ColorShift::alpha_x
Keyframe alpha_x
Shift the Alpha X coordinates (left or right)
Definition: ColorShift.h:66
openshot::ColorShift::red_y
Keyframe red_y
Shift the Red Y coordinates (up or down)
Definition: ColorShift.h:61
openshot::Keyframe::JsonValue
Json::Value JsonValue() const
Generate Json::Value for this object.
Definition: KeyFrame.cpp:329
openshot::ColorShift::green_y
Keyframe green_y
Shift the Green Y coordinates (up or down)
Definition: ColorShift.h:63
openshot::Keyframe
A Keyframe is a collection of Point instances, which is used to vary a number or property over time.
Definition: KeyFrame.h:64
openshot::InvalidJSON
Exception for invalid JSON.
Definition: Exceptions.h:205
openshot::ColorShift::GetFrame
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
openshot::EffectBase::InitEffectInfo
void InitEffectInfo()
Definition: EffectBase.cpp:36
openshot::EffectInfoStruct::has_audio
bool has_audio
Determines if this effect manipulates the audio of a frame.
Definition: EffectBase.h:56
openshot::EffectInfoStruct::class_name
std::string class_name
The class name of the effect.
Definition: EffectBase.h:52
openshot::EffectInfoStruct::description
std::string description
The description of this effect and what it does.
Definition: EffectBase.h:54
openshot::ColorShift::JsonValue
Json::Value JsonValue() const override
Generate Json::Value for this object.
Definition: ColorShift.cpp:202
openshot::EffectInfoStruct::has_video
bool has_video
Determines if this effect manipulates the image of a frame.
Definition: EffectBase.h:55
openshot::ColorShift::Json
std::string Json() const override
Get and Set JSON methods.
Definition: ColorShift.cpp:195
openshot::ClipBase::Id
void Id(std::string value)
Set basic properties.
Definition: ClipBase.h:84
openshot::Frame::GetImage
std::shared_ptr< QImage > GetImage()
Get pointer to Qt QImage image object.
Definition: Frame.cpp:913
openshot::ColorShift::SetJson
void SetJson(const std::string value)
Load JSON string into this object.
Definition: ColorShift.cpp:221
openshot::EffectInfoStruct::name
std::string name
The name of the effect.
Definition: EffectBase.h:53
openshot::ColorShift::blue_y
Keyframe blue_y
Shift the Blue Y coordinates (up or down)
Definition: ColorShift.h:65
openshot::Keyframe::GetValue
double GetValue(int64_t index) const
Get the value at a specific index.
Definition: KeyFrame.cpp:262