1 /**
2  * @file
3  * @brief Source file for ImageReader 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 // Require ImageMagick support
32 #ifdef USE_IMAGEMAGICK
33 
34 #include "ImageReader.h"
35 #include "Exceptions.h"
36 
37 using namespace openshot;
38 
ImageReader(const std::string & path,bool inspect_reader)39 ImageReader::ImageReader(const std::string& path, bool inspect_reader) : path(path), is_open(false)
40 {
41 	// Open and Close the reader, to populate its attributes (such as height, width, etc...)
42 	if (inspect_reader) {
43 		Open();
44 		Close();
45 	}
46 }
47 
48 // Open image file
Open()49 void ImageReader::Open()
50 {
51 	// Open reader if not already open
52 	if (!is_open)
53 	{
54 		// Attempt to open file
55 		try
56 		{
57 			// load image
58 			image = std::make_shared<Magick::Image>(path);
59 
60 			// Give image a transparent background color
61 			image->backgroundColor(Magick::Color("none"));
62 			MAGICK_IMAGE_ALPHA(image, true);
63 		}
64 		catch (const Magick::Exception& e) {
65 			// raise exception
66 			throw InvalidFile("File could not be opened.", path);
67 		}
68 
69 		// Update image properties
70 		info.has_audio = false;
71 		info.has_video = true;
72 		info.has_single_image = true;
73 		info.file_size = image->fileSize();
74 		info.vcodec = image->format();
75 		info.width = image->size().width();
76 		info.height = image->size().height();
77 		info.pixel_ratio.num = 1;
78 		info.pixel_ratio.den = 1;
79 		info.duration = 60 * 60 * 1;  // 1 hour duration
80 		info.fps.num = 30;
81 		info.fps.den = 1;
82 		info.video_timebase.num = 1;
83 		info.video_timebase.den = 30;
84 		info.video_length = round(info.duration * info.fps.ToDouble());
85 
86 		// Calculate the DAR (display aspect ratio)
87 		Fraction size(info.width * info.pixel_ratio.num, info.height * info.pixel_ratio.den);
88 
89 		// Reduce size fraction
90 		size.Reduce();
91 
92 		// Set the ratio based on the reduced fraction
93 		info.display_ratio.num = size.num;
94 		info.display_ratio.den = size.den;
95 
96 		// Mark as "open"
97 		is_open = true;
98 	}
99 }
100 
101 // Close image file
Close()102 void ImageReader::Close()
103 {
104 	// Close all objects, if reader is 'open'
105 	if (is_open)
106 	{
107 		// Mark as "closed"
108 		is_open = false;
109 
110 		// Delete the image
111 		image.reset();
112 	}
113 }
114 
115 // Get an openshot::Frame object for a specific frame number of this reader.
GetFrame(int64_t requested_frame)116 std::shared_ptr<Frame> ImageReader::GetFrame(int64_t requested_frame)
117 {
118 	// Check for open reader (or throw exception)
119 	if (!is_open)
120 		throw ReaderClosed("The FFmpegReader is closed.  Call Open() before calling this method.", path);
121 
122 	// Create or get frame object
123 	auto image_frame = std::make_shared<Frame>(
124 		requested_frame, image->size().width(), image->size().height(),
125 		"#000000", 0, 2);
126 
127 	// Add Image data to frame
128 	image_frame->AddMagickImage(image);
129 
130 	// return frame object
131 	return image_frame;
132 }
133 
134 // Generate JSON string of this object
Json() const135 std::string ImageReader::Json() const {
136 
137 	// Return formatted string
138 	return JsonValue().toStyledString();
139 }
140 
141 // Generate Json::Value for this object
JsonValue() const142 Json::Value ImageReader::JsonValue() const {
143 
144 	// Create root json object
145 	Json::Value root = ReaderBase::JsonValue(); // get parent properties
146 	root["type"] = "ImageReader";
147 	root["path"] = path;
148 
149 	// return JsonValue
150 	return root;
151 }
152 
153 // Load JSON string into this object
SetJson(const std::string value)154 void ImageReader::SetJson(const std::string value) {
155 
156 	// Parse JSON string into JSON objects
157 	try
158 	{
159 		const Json::Value root = openshot::stringToJson(value);
160 		// Set all values that match
161 		SetJsonValue(root);
162 	}
163 	catch (const std::exception& e)
164 	{
165 		// Error parsing JSON (or missing keys)
166 		throw InvalidJSON("JSON is invalid (missing keys or invalid data types)");
167 	}
168 }
169 
170 // Load Json::Value into this object
SetJsonValue(const Json::Value root)171 void ImageReader::SetJsonValue(const Json::Value root) {
172 
173 	// Set parent data
174 	ReaderBase::SetJsonValue(root);
175 
176 	// Set data from Json (if key is found)
177 	if (!root["path"].isNull())
178 		path = root["path"].asString();
179 
180 	// Re-Open path, and re-init everything (if needed)
181 	if (is_open)
182 	{
183 		Close();
184 		Open();
185 	}
186 }
187 
188 #endif //USE_IMAGEMAGICK
189