#include "image_decoder.h"
#include "image.h"
#include "magick_image_proxy.h"
+#include "j2k_image_proxy.h"
#include "film.h"
#include "exceptions.h"
if (!_image_content->still() || !_image) {
/* Either we need an image or we are using moving images, so load one */
- _image.reset (new MagickImageProxy (_image_content->path (_image_content->still() ? 0 : _video_position)));
+ boost::filesystem::path path = _image_content->path (_image_content->still() ? 0 : _video_position);
+ if (valid_j2k_file (path)) {
+ /* We can't extract image size from a JPEG2000 codestream without decoding it,
+ so pass in the image content's size here.
+ */
+ _image.reset (new J2KImageProxy (path, _image_content->video_size ()));
+ } else {
+ _image.reset (new MagickImageProxy (path));
+ }
}
video (_image, _video_position);
*/
-#include <iostream>
-#include <Magick++.h>
#include "image_content.h"
#include "image_examiner.h"
#include "film.h"
#include "job.h"
#include "exceptions.h"
#include "config.h"
+#include "cross.h"
+#include <dcp/xyz_frame.h>
+#include <Magick++.h>
+#include <iostream>
#include "i18n.h"
{
#ifdef DCPOMATIC_IMAGE_MAGICK
using namespace MagickCore;
-#endif
- Magick::Image* image = new Magick::Image (content->path(0).string());
- _video_size = dcp::Size (image->columns(), image->rows());
- delete image;
+#endif
+ boost::filesystem::path path = content->path(0).string ();
+ if (valid_j2k_file (path)) {
+ boost::uintmax_t size = boost::filesystem::file_size (path);
+ uint8_t* buffer = new uint8_t[size];
+ FILE* f = fopen_boost (path, "r");
+ if (!f) {
+ throw FileError ("Could not open file for reading", path);
+ }
+ fread (buffer, 1, size, f);
+ fclose (f);
+ _video_size = dcp::decompress_j2k (buffer, size, 0)->size ();
+ delete[] buffer;
+ } else {
+ Magick::Image* image = new Magick::Image (content->path(0).string());
+ _video_size = dcp::Size (image->columns(), image->rows());
+ delete image;
+ }
if (content->still ()) {
_video_length = ContentTime::from_seconds (Config::instance()->default_still_length());
using std::string;
using boost::shared_ptr;
+/** Construct a J2KImageProxy from a JPEG2000 file */
+J2KImageProxy::J2KImageProxy (boost::filesystem::path path, dcp::Size size)
+ : _mono (new dcp::MonoPictureFrame (path))
+ , _size (size)
+{
+
+}
+
J2KImageProxy::J2KImageProxy (shared_ptr<const dcp::MonoPictureFrame> frame, dcp::Size size)
: _mono (frame)
, _size (size)
class J2KImageProxy : public ImageProxy
{
public:
+ J2KImageProxy (boost::filesystem::path path, dcp::Size);
J2KImageProxy (boost::shared_ptr<const dcp::MonoPictureFrame> frame, dcp::Size);
J2KImageProxy (boost::shared_ptr<const dcp::StereoPictureFrame> frame, dcp::Size, dcp::Eye);
J2KImageProxy (boost::shared_ptr<cxml::Node> xml, boost::shared_ptr<Socket> socket);
return (ext == ".tif" || ext == ".tiff" || ext == ".jpg" || ext == ".jpeg" || ext == ".png" || ext == ".bmp" || ext == ".tga" || ext == ".dpx");
}
+bool
+valid_j2k_file (boost::filesystem::path f)
+{
+ string ext = f.extension().string();
+ transform (ext.begin(), ext.end(), ext.begin(), ::tolower);
+ return (ext == ".j2k" || ext == ".j2c");
+}
+
string
tidy_for_filename (string f)
{
extern void ensure_ui_thread ();
extern std::string audio_channel_name (int);
extern bool valid_image_file (boost::filesystem::path);
+extern bool valid_j2k_file (boost::filesystem::path);
#ifdef DCPOMATIC_WINDOWS
extern boost::filesystem::path mo_path ();
#endif