22 init_effect_details();
30 init_effect_details();
34void Brightness::init_effect_details()
42 info.
description =
"Adjust the brightness and contrast of the frame's image.";
49std::shared_ptr<openshot::Frame>
Brightness::GetFrame(std::shared_ptr<openshot::Frame> frame, int64_t frame_number)
52 std::shared_ptr<QImage> frame_image = frame->GetImage();
59 const float contrast_factor = (259.0f * (contrast_value + 255.0f)) / (255.0f * (259.0f - contrast_value));
60 const int brightness_offset_i =
static_cast<int>(255.0f * brightness_value);
63 unsigned char *pixels =
reinterpret_cast<unsigned char *
>(frame_image->bits());
64 const int pixel_count = frame_image->width() * frame_image->height();
66 static const std::array<float, 256> inv_alpha = [] {
67 std::array<float, 256> lut{};
69 for (
int i = 1; i < 256; ++i)
70 lut[i] = 255.0f /
static_cast<float>(i);
73 const auto clamp_u8 = [](
int value) ->
unsigned char {
74 if (value < 0)
return 0;
75 if (value > 255)
return 255;
76 return static_cast<unsigned char>(value);
78 const auto clamp_i = [](
int value) ->
int {
79 if (value < 0)
return 0;
80 if (value > 255)
return 255;
84 const auto adjust_contrast_and_brightness = [&](
int &R,
int &G,
int &B) {
85 R = clamp_u8(clamp_i(
static_cast<int>((contrast_factor * (R - 128)) + 128.0f)) + brightness_offset_i);
86 G = clamp_u8(clamp_i(
static_cast<int>((contrast_factor * (G - 128)) + 128.0f)) + brightness_offset_i);
87 B = clamp_u8(clamp_i(
static_cast<int>((contrast_factor * (B - 128)) + 128.0f)) + brightness_offset_i);
90 #pragma omp parallel for if(pixel_count >= 16384) schedule(static)
91 for (
int pixel = 0; pixel < pixel_count; ++pixel)
93 const int idx = pixel * 4;
96 const int A = pixels[idx + 3];
106 adjust_contrast_and_brightness(R, G, B);
107 pixels[idx + 0] =
static_cast<unsigned char>(R);
108 pixels[idx + 1] =
static_cast<unsigned char>(G);
109 pixels[idx + 2] =
static_cast<unsigned char>(B);
111 const float alpha_percent =
static_cast<float>(A) * (1.0f / 255.0f);
112 const float inv_alpha_percent = inv_alpha[A];
115 R =
static_cast<int>(pixels[idx + 0] * inv_alpha_percent);
116 G =
static_cast<int>(pixels[idx + 1] * inv_alpha_percent);
117 B =
static_cast<int>(pixels[idx + 2] * inv_alpha_percent);
118 adjust_contrast_and_brightness(R, G, B);
121 pixels[idx + 0] =
static_cast<unsigned char>(R * alpha_percent);
122 pixels[idx + 1] =
static_cast<unsigned char>(G * alpha_percent);
123 pixels[idx + 2] =
static_cast<unsigned char>(B * alpha_percent);
137 std::shared_ptr<QImage> mask_image, int64_t frame_number)
const {
139 if (!original_image || !effected_image || !mask_image)
141 if (original_image->size() != effected_image->size() || effected_image->size() != mask_image->size())
144 unsigned char* original_pixels =
reinterpret_cast<unsigned char*
>(original_image->bits());
145 unsigned char* effected_pixels =
reinterpret_cast<unsigned char*
>(effected_image->bits());
146 unsigned char* mask_pixels =
reinterpret_cast<unsigned char*
>(mask_image->bits());
147 const int pixel_count = effected_image->width() * effected_image->height();
150 #pragma omp parallel for schedule(static)
151 for (
int i = 0; i < pixel_count; ++i) {
152 const int idx = i * 4;
153 float factor =
static_cast<float>(qGray(mask_pixels[idx], mask_pixels[idx + 1], mask_pixels[idx + 2])) / 255.0f;
154 factor = 1.0f - factor;
155 factor = factor * factor;
156 const float inverse = 1.0f - factor;
158 effected_pixels[idx] =
static_cast<unsigned char>(
159 (original_pixels[idx] * inverse) + (effected_pixels[idx] * factor));
160 effected_pixels[idx + 1] =
static_cast<unsigned char>(
161 (original_pixels[idx + 1] * inverse) + (effected_pixels[idx + 1] * factor));
162 effected_pixels[idx + 2] =
static_cast<unsigned char>(
163 (original_pixels[idx + 2] * inverse) + (effected_pixels[idx + 2] * factor));
164 effected_pixels[idx + 3] = original_pixels[idx + 3];
167 #pragma omp parallel for schedule(static)
168 for (
int i = 0; i < pixel_count; ++i) {
169 const int idx = i * 4;
170 float factor =
static_cast<float>(qGray(mask_pixels[idx], mask_pixels[idx + 1], mask_pixels[idx + 2])) / 255.0f;
171 factor = factor * factor;
172 const float inverse = 1.0f - factor;
174 effected_pixels[idx] =
static_cast<unsigned char>(
175 (original_pixels[idx] * inverse) + (effected_pixels[idx] * factor));
176 effected_pixels[idx + 1] =
static_cast<unsigned char>(
177 (original_pixels[idx + 1] * inverse) + (effected_pixels[idx + 1] * factor));
178 effected_pixels[idx + 2] =
static_cast<unsigned char>(
179 (original_pixels[idx + 2] * inverse) + (effected_pixels[idx + 2] * factor));
180 effected_pixels[idx + 3] = original_pixels[idx + 3];
216 catch (
const std::exception& e)
219 throw InvalidJSON(
"JSON is invalid (missing keys or invalid data types)");
230 if (!root[
"brightness"].isNull())
232 if (!root[
"contrast"].isNull())
234 if (!root[
"mask_mode"].isNull())
252 return root.toStyledString();
Header file for Brightness class.
Header file for all Exception classes.
Keyframe brightness
Brightness keyframe. A constant value here will prevent animation.
std::string Json() const override
Generate JSON string of this object.
void ApplyCustomMaskBlend(std::shared_ptr< QImage > original_image, std::shared_ptr< QImage > effected_image, std::shared_ptr< QImage > mask_image, int64_t frame_number) const override
Optional override for effects with custom mask implementation.
Keyframe contrast
Contrast keyframe.
int mask_mode
Mask behavior mode for this effect.
std::shared_ptr< openshot::Frame > GetFrame(int64_t frame_number) override
This method is required for all derived classes of ClipBase, and returns a new openshot::Frame object...
void SetJsonValue(const Json::Value root) override
Load Json::Value into this object.
Json::Value JsonValue() const override
Generate Json::Value for this object.
std::string PropertiesJSON(int64_t requested_frame) const override
bool UseCustomMaskBlend(int64_t frame_number) const override
Optional override for effects that need custom mask behavior.
Brightness()
Blank constructor, useful when using Json to load the effect properties.
void SetJson(const std::string value) override
Load JSON string into this object.
Json::Value add_property_choice_json(std::string name, int value, int selected_value) const
Generate JSON choice for a property (dropdown properties)
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.
bool mask_invert
Invert grayscale mask values before blending.
virtual Json::Value JsonValue() const
Generate Json::Value for this object.
Json::Value BasePropertiesJSON(int64_t requested_frame) const
Generate JSON object of base properties (recommended to be used by all effects)
virtual void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
EffectInfoStruct info
Information about the current effect.
Exception for invalid JSON.
A Keyframe is a collection of Point instances, which is used to vary a number or property over time.
void SetJsonValue(const Json::Value root)
Load Json::Value into this object.
double GetValue(int64_t index) const
Get the value at a specific index.
Json::Value JsonValue() const
Generate Json::Value for this object.
This namespace is the default namespace for all code in the openshot library.
@ BRIGHTNESS_MASK_LIMIT_TO_AREA
@ BRIGHTNESS_MASK_VARY_STRENGTH
const Json::Value stringToJson(const std::string value)
bool has_video
Determines if this effect manipulates the image of a frame.
bool has_audio
Determines if this effect manipulates the audio of a frame.
std::string class_name
The class name of the effect.
std::string name
The name of the effect.
std::string description
The description of this effect and what it does.