First cut at J2K import.
authorCarl Hetherington <cth@carlh.net>
Sun, 23 Nov 2014 01:48:55 +0000 (01:48 +0000)
committerCarl Hetherington <cth@carlh.net>
Sun, 23 Nov 2014 12:47:36 +0000 (12:47 +0000)
src/lib/image_decoder.cc
src/lib/image_examiner.cc
src/lib/j2k_image_proxy.cc
src/lib/j2k_image_proxy.h
src/lib/util.cc
src/lib/util.h

index 53ef7bae7f02bc480d4d4674bb2690e28cd0fe98..f11d377563ea64d15568e819f61235bcdd66feed 100644 (file)
@@ -24,6 +24,7 @@
 #include "image_decoder.h"
 #include "image.h"
 #include "magick_image_proxy.h"
+#include "j2k_image_proxy.h"
 #include "film.h"
 #include "exceptions.h"
 
@@ -49,7 +50,15 @@ ImageDecoder::pass ()
 
        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);
index 75ccb6a3e91fd3e21207ce26872f69f187b95170..ef9c13c5a1c1e8b33500d72531bba395372d7563 100644 (file)
 
 */
 
-#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"
 
@@ -39,10 +41,24 @@ ImageExaminer::ImageExaminer (shared_ptr<const Film> film, shared_ptr<const Imag
 {
 #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());
index 1fe854cd1bd4e88afb8c379b140fd58d9337da84..9312a7763ba8e5c959cf48e39cd227de5c686a9f 100644 (file)
 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)
index c931e56441887d0497b349f20c4eab1e8028e603..299180f50ceda178ad286e4d015125eab77e6874 100644 (file)
@@ -25,6 +25,7 @@ class EncodedData;
 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);
index 2b7df86bfbf8fd5e64a6533004b22c2d4a8b22b0..ec8b0f7a52571c18f93c99f48ead29bba668d196 100644 (file)
@@ -797,6 +797,14 @@ valid_image_file (boost::filesystem::path f)
        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)
 {
index c06f51ca3a37ff68fdab6b7c0d7b89c298582f26..886e2a61c7e5d3087c79fc759160e3f46c8106a0 100644 (file)
@@ -63,6 +63,7 @@ extern std::string md5_digest (std::vector<boost::filesystem::path>, boost::shar
 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