Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r61387 - sandbox/gil/boost/gil/extension/io2
From: dsaritz_at_[hidden]
Date: 2010-04-18 17:16:11


Author: psiha
Date: 2010-04-18 17:16:10 EDT (Sun, 18 Apr 2010)
New Revision: 61387
URL: http://svn.boost.org/trac/boost/changeset/61387

Log:
Added a first version of the LibJPEG formatted_image implementation.
Added:
   sandbox/gil/boost/gil/extension/io2/libjpeg_private_base.hpp (contents, props changed)

Added: sandbox/gil/boost/gil/extension/io2/libjpeg_private_base.hpp
==============================================================================
--- (empty file)
+++ sandbox/gil/boost/gil/extension/io2/libjpeg_private_base.hpp 2010-04-18 17:16:10 EDT (Sun, 18 Apr 2010)
@@ -0,0 +1,604 @@
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \file libjpeg_private_base.hpp
+/// ------------------------------
+///
+/// Copyright (c) Domagoj Saric 2010.
+///
+/// Use, modification and distribution is subject to the Boost Software License, Version 1.0.
+/// (See accompanying file LICENSE_1_0.txt or copy at
+/// http://www.boost.org/LICENSE_1_0.txt)
+///
+/// For more information, see http://www.boost.org
+///
+////////////////////////////////////////////////////////////////////////////////
+//------------------------------------------------------------------------------
+#pragma once
+#ifndef libjpeg_private_base_hpp__7C5F6951_A00F_4E0D_9783_488A49B1CA2B
+#define libjpeg_private_base_hpp__7C5F6951_A00F_4E0D_9783_488A49B1CA2B
+//------------------------------------------------------------------------------
+#include "../../gil_all.hpp"
+#include "formatted_image.hpp"
+#include "io_error.hpp"
+
+#include <boost/foreach.hpp>
+#include <boost/smart_ptr/scoped_ptr.hpp>
+
+#define JPEG_INTERNALS
+#include "jpeglib.h"
+#undef JPEG_INTERNALS
+
+#include <csetjmp>
+#include <cstdlib>
+//------------------------------------------------------------------------------
+namespace boost
+{
+//------------------------------------------------------------------------------
+namespace gil
+{
+//------------------------------------------------------------------------------
+namespace detail
+{
+//------------------------------------------------------------------------------
+
+BOOST_STATIC_ASSERT( BITS_IN_JSAMPLE == 8 );
+
+
+template <typename Pixel, bool isPlanar>
+struct gil_to_libjpeg_format : mpl::integral_c<J_COLOR_SPACE, JCS_UNKNOWN> {};
+
+template <> struct gil_to_libjpeg_format<rgb8_pixel_t , false> : mpl::integral_c<J_COLOR_SPACE, JCS_RGB > {};
+template <> struct gil_to_libjpeg_format<gray8_pixel_t, false> : mpl::integral_c<J_COLOR_SPACE, JCS_GRAYSCALE> {};
+template <> struct gil_to_libjpeg_format<cmyk8_pixel_t, false> : mpl::integral_c<J_COLOR_SPACE, JCS_CMYK > {};
+
+
+
+struct view_libjpeg_format
+{
+ template <class View>
+ struct apply : gil_to_libjpeg_format<typename View::value_type, is_planar<View>::value> {};
+};
+
+
+typedef mpl::vector3
+<
+ image<rgb8_pixel_t , false>,
+ image<gray8_pixel_t, false>,
+ image<cmyk8_pixel_t, false>
+> libjpeg_supported_pixel_formats;
+
+
+
+struct libjpeg_guard {};
+
+
+class libjpeg_roi
+{
+public:
+ typedef std::ptrdiff_t value_type;
+ typedef point2<value_type> point_t ;
+
+ typedef value_type offset_t ;
+
+public:
+ libjpeg_roi( value_type const start_row, value_type const end_row )
+ :
+ start_row_( start_row ),
+ end_row_ ( end_row )
+ {}
+
+ value_type start_row() const { return start_row_; }
+ value_type end_row () const { return end_row_ ; }
+
+private:
+ void operator=( libjpeg_roi const & );
+
+private:
+ value_type const start_row_;
+ value_type const end_row_;
+};
+
+
+#if defined(BOOST_MSVC)
+# pragma warning( push )
+# pragma warning( disable : 4127 ) // "conditional expression is constant"
+#endif
+
+class libjpeg_base : private libjpeg_guard
+{
+protected:
+ struct for_decompressor {};
+ struct for_compressor {};
+
+protected:
+ libjpeg_base( for_decompressor ) throw(...)
+ {
+ initialize_error_handler();
+ if ( setjmp( error_handler_target() ) )
+ throw_jpeg_error();
+ jpeg_create_decompress( &decompressor() );
+ }
+
+ libjpeg_base( for_compressor ) throw(...)
+ {
+ initialize_error_handler();
+ if ( setjmp( error_handler_target() ) )
+ throw_jpeg_error();
+ jpeg_create_compress( &compressor() );
+ }
+
+ ~libjpeg_base() { jpeg_destroy( &common() ); }
+
+ void abort() const { jpeg_abort( &mutable_this().common() ); }
+
+ jmp_buf & error_handler_target() const { return longjmp_target_; }
+
+ jpeg_common_struct & common () { return *gil_reinterpret_cast<j_common_ptr>( &libjpeg_object.compressor_ ); }
+ jpeg_common_struct const & common () const { return const_cast<libjpeg_base &>( *this ).common(); }
+ jpeg_compress_struct & compressor () { return libjpeg_object.compressor_ ; }
+ jpeg_compress_struct const & compressor () const { return const_cast<libjpeg_base &>( *this ).compressor(); }
+ jpeg_decompress_struct & decompressor() { return libjpeg_object.decompressor_; }
+ jpeg_decompress_struct const & decompressor() const { return const_cast<libjpeg_base &>( *this ).decompressor(); }
+
+ libjpeg_base & mutable_this() const { return const_cast<libjpeg_base &>( *this ); }
+
+ __declspec( noreturn )
+ static void throw_jpeg_error() throw(...)
+ {
+ io_error( "jpeg error" );
+ }
+
+private:
+ void initialize_error_handler()
+ {
+ common().err = jpeg_std_error( &jerr_ );
+ common().client_data = this;
+ jerr_.error_exit = &libjpeg_base::libX_fatal_error_handler;
+ }
+
+ static inline void libX_fatal_error_handler( j_common_ptr const cinfo )
+ {
+ libjpeg_base * const p_me( gil_reinterpret_cast<libjpeg_base *>( cinfo->client_data ) );
+ BOOST_ASSERT( p_me );
+ longjmp( p_me->longjmp_target_, 1 );
+ }
+
+private:
+ union libjpeg_object_t
+ {
+ jpeg_compress_struct compressor_;
+ jpeg_decompress_struct decompressor_;
+ } libjpeg_object;
+
+ jpeg_error_mgr jerr_ ;
+
+ //#ifndef BOOST_MSVC
+ mutable jmp_buf longjmp_target_;
+ //#endif // BOOST_MSVC
+};
+
+class libjpeg_image;
+
+struct decompression_setup_data_t
+{
+ decompression_setup_data_t( J_COLOR_SPACE const format, JSAMPROW const buffer, libjpeg_roi::offset_t const offset )
+ : format_( format ), buffer_( buffer ), offset_( offset ) {}
+
+ J_COLOR_SPACE /*const*/ format_;
+ JSAMPROW /*const*/ buffer_;
+ libjpeg_roi::offset_t /*const*/ offset_;
+};
+
+struct view_data_t : decompression_setup_data_t
+{
+ template <class View>
+ explicit view_data_t( View const & view, libjpeg_roi::offset_t const offset )
+ :
+ decompression_setup_data_t
+ (
+ view_libjpeg_format::apply<View>::value,
+ formatted_image_base::get_raw_data( view ),
+ offset
+ ),
+ height_( view.height() ),
+ width_ ( view.width () ),
+ stride_( view.pixels().row_size() )
+ {}
+
+ void set_format( J_COLOR_SPACE const format ) { format_ = format; }
+
+ unsigned int /*const*/ height_;
+ unsigned int /*const*/ width_ ;
+ unsigned int /*const*/ stride_;
+};
+
+template <>
+struct formatted_image_traits<libjpeg_image>
+{
+ typedef J_COLOR_SPACE format_t;
+
+ typedef libjpeg_supported_pixel_formats supported_pixel_formats_t;
+
+ typedef libjpeg_roi roi_t;
+
+ typedef view_libjpeg_format view_to_native_format;
+
+ typedef view_data_t view_data_t;
+
+ template <class View>
+ struct is_supported : mpl::bool_<view_libjpeg_format::apply<View>::value != JCS_UNKNOWN> {};
+
+ BOOST_STATIC_CONSTANT( unsigned int, desired_alignment = sizeof( void * ) );
+};
+
+
+class libjpeg_image
+ :
+ public libjpeg_base,
+ public detail::formatted_image<libjpeg_image>
+{
+public:
+ format_t format() const { return decompressor().jpeg_color_space; }
+
+ format_t closest_gil_supported_format() const
+ {
+ switch ( format() )
+ {
+ case JCS_RGB :
+ case JCS_YCbCr:
+ return JCS_RGB;
+
+ case JCS_CMYK:
+ case JCS_YCCK:
+ return JCS_CMYK;
+
+ case JCS_GRAYSCALE:
+ return JCS_GRAYSCALE;
+
+ default:
+ BOOST_ASSERT( format() == JCS_UNKNOWN );
+ BOOST_ASSERT( !"Unknown format." );
+ return JCS_UNKNOWN;
+ }
+ }
+
+ image_type_id current_image_format_id() const
+ {
+ return image_format_id( closest_gil_supported_format() );
+ }
+
+ static image_type_id image_format_id( format_t const closest_gil_supported_format )
+ {
+ switch ( closest_gil_supported_format )
+ {
+ case JCS_RGB : return 0;
+ case JCS_GRAYSCALE: return 1;
+ case JCS_CMYK : return 2;
+ default:
+ BOOST_ASSERT( !"Should not get reached." ); __assume( false );
+ return unsupported_format;
+ }
+ }
+
+ static std::size_t format_size( format_t const format )
+ {
+ switch ( format )
+ {
+ default:
+ BOOST_ASSERT( !"Invalid or unknown format specified." ); __assume( false );
+ return 0;
+
+ case JCS_RGB:
+ case JCS_YCbCr:
+ return 3;
+ case JCS_CMYK:
+ case JCS_YCCK:
+ return 4;
+ case JCS_GRAYSCALE:
+ return 1;
+ }
+ }
+
+ //...zzz...
+ //std::size_t format_size( format_t const format ) const
+ //{
+ // BOOST_ASSERT( format_size( format ) == decompressor().output_components );
+ // BOOST_ASSERT( decompressor().out_color_components == decompressor().output_components );
+ // ignore_unused_variable_warning( format );
+ // return decompressor().output_components;
+ //}
+
+
+public: /// \ingroup Construction
+ explicit libjpeg_image( FILE * const p_file )
+ :
+ libjpeg_base( for_decompressor() )
+ {
+ BOOST_ASSERT( p_file );
+
+ if ( setjmp( error_handler_target() ) )
+ throw_jpeg_error();
+
+ jpeg_stdio_src( &decompressor(), p_file );
+
+ BOOST_VERIFY( jpeg_read_header( &decompressor(), true ) == JPEG_HEADER_OK );
+
+ io_error_if( decompressor().data_precision != 8, "Unsupported image file data precision." );
+ }
+
+
+public:
+ point2<std::ptrdiff_t> dimensions() const
+ {
+ return point2<std::ptrdiff_t>( decompressor().image_width, decompressor().image_height );
+ }
+
+
+private: // Private formatted_image_base interface.
+ friend base_t;
+ void raw_convert_to_prepared_view( view_data_t const & view_data ) const throw(...)
+ {
+ setup_decompression( view_data );
+
+ if ( setjmp( error_handler_target() ) )
+ throw_jpeg_error();
+
+ JSAMPROW scanlines[ 4 ] =
+ {
+ view_data.buffer_,
+ scanlines[ 0 ] + view_data.stride_,
+ scanlines[ 1 ] + view_data.stride_,
+ scanlines[ 2 ] + view_data.stride_
+ };
+
+ BOOST_ASSERT( _countof( scanlines ) >= decompressor().rec_outbuf_height );
+ unsigned int scanlines_to_read( view_data.height_ );
+ for ( ; ; )
+ {
+ BOOST_ASSERT( scanlines_to_read <= ( decompressor().output_height - decompressor().output_scanline ) );
+ unsigned int const lines_read
+ (
+ jpeg_read_scanlines
+ (
+ &mutable_this().decompressor(),
+ scanlines,
+ (std::min)( _countof( scanlines ), scanlines_to_read )
+ )
+ );
+ scanlines_to_read -= lines_read;
+ if ( !scanlines_to_read )
+ return;
+
+ scanlines[ 0 ] = scanlines[ lines_read - 1 ] + view_data.stride_;
+ scanlines[ 1 ] = scanlines[ 0 ] + view_data.stride_;
+ scanlines[ 2 ] = scanlines[ 1 ] + view_data.stride_;
+ scanlines[ 3 ] = scanlines[ 2 ] + view_data.stride_;
+ }
+ }
+
+ template <class MyView, class TargetView, class Converter>
+ void generic_convert_to_prepared_view( TargetView const & view, Converter const & converter ) const
+ {
+ typedef typename MyView::value_type pixel_t;
+ std::size_t const scanline_length( decompressor().image_width * decompressor().num_components );
+ scoped_ptr<JSAMPLE> const p_scanline_buffer( new JSAMPLE[ scanline_length ] );
+ JSAMPROW scanline ( p_scanline_buffer.get() );
+ JSAMPROW const scanlineEnd( scanline + scanline_length );
+
+ BOOST_ASSERT( closest_gil_supported_format() == view_libjpeg_format::apply<MyView>::value );
+ setup_decompression
+ (
+ decompression_setup_data_t
+ (
+ view_libjpeg_format::apply<MyView>::value,
+ scanline,
+ detail::get_offset<offset_t>( view )
+ )
+ );
+
+ BOOST_ASSERT( decompressor().output_width == decompressor().image_width );
+ BOOST_ASSERT( decompressor().output_components == decompressor().num_components );
+
+ if ( setjmp( error_handler_target() ) )
+ throw_jpeg_error();
+
+ unsigned int const scanlines_to_read( detail::original_view( view ).dimensions().y );
+ for ( unsigned int scanline_index( 0 ); scanline_index < scanlines_to_read; ++scanline_index )
+ {
+ BOOST_VERIFY
+ (
+ jpeg_read_scanlines
+ (
+ &mutable_this().decompressor(),
+ &scanline,
+ 1
+ ) == 1
+ );
+
+ pixel_t const * p_source_pixel( gil_reinterpret_cast_c<pixel_t const *>( scanline ) );
+ typename TargetView::x_iterator p_target_pixel( view.row_begin( scanline_index ) );
+ while ( p_source_pixel < gil_reinterpret_cast_c<pixel_t const *>( scanlineEnd ) )
+ {
+ converter( *p_source_pixel, *p_target_pixel );
+ ++p_source_pixel;
+ ++p_target_pixel;
+ }
+ }
+ }
+
+ void copy_to_prepared_view( view_data_t const & view_data ) const
+ {
+ BOOST_ASSERT( view_data.width_ == static_cast<unsigned int>( dimensions().x ) );
+ BOOST_ASSERT( view_data.height_ == static_cast<unsigned int>( dimensions().y ) );
+ BOOST_ASSERT( view_data.format_ == closest_gil_supported_format() );
+ raw_convert_to_prepared_view( view_data );
+ }
+
+private:
+ void setup_decompression( decompression_setup_data_t const & view_data ) const throw(...)
+ {
+ unsigned int const state ( decompressor().global_state );
+ unsigned int rows_to_skip( view_data.offset_ );
+ if
+ (
+ ( state != DSTATE_SCANNING ) ||
+ ( decompressor().out_color_space != view_data.format_ ) ||
+ ( decompressor().output_scanline > view_data.offset_ )
+ )
+ {
+ BOOST_ASSERT
+ (
+ ( state == DSTATE_READY ) ||
+ ( state == DSTATE_SCANNING )
+ );
+
+ if ( setjmp( error_handler_target() ) )
+ throw_jpeg_error();
+
+ if ( state == DSTATE_SCANNING )
+ abort();
+
+ mutable_this().decompressor().out_color_space = view_data.format_;
+ BOOST_VERIFY( jpeg_start_decompress( &mutable_this().decompressor() ) );
+ BOOST_ASSERT( decompressor().output_scanline == 0 );
+ }
+ else
+ rows_to_skip -= decompressor().output_scanline;
+
+ if ( rows_to_skip )
+ skip_rows( rows_to_skip, view_data.buffer_ );
+ BOOST_ASSERT( decompressor().output_scanline == view_data.offset_ );
+ }
+
+ void skip_rows( unsigned int const number_of_rows_to_skip, JSAMPROW /*const*/ dummy_scanline_buffer ) const
+ {
+ BOOST_ASSERT( decompressor().raw_data_out == false );
+ BOOST_ASSERT( decompressor().global_state == DSTATE_SCANNING );
+ mutable_this().decompressor().raw_data_out = true;
+ mutable_this().decompressor().global_state = DSTATE_RAW_OK;
+
+ std::size_t const max_number_of_components( 4 ); // CMYK
+ std::size_t const max_sampling_factor ( 2 ); // Documentation
+ std::size_t const mcu_row_size ( max_sampling_factor * DCTSIZE ); // Documentation
+ BOOST_ASSERT( decompressor().num_components <= max_number_of_components );
+ BOOST_ASSERT( decompressor().max_v_samp_factor <= max_sampling_factor );
+
+ JSAMPROW dummy_component_2d_array[ mcu_row_size ];
+ JSAMPARRAY dummy_scan_lines [ max_number_of_components ];
+
+ std::fill( begin( dummy_component_2d_array ), end( dummy_component_2d_array ), dummy_scanline_buffer );
+ std::fill( begin( dummy_scan_lines ), end( dummy_scan_lines ), &dummy_component_2d_array[ 0 ] );
+
+ unsigned int number_of_rows_to_skip_using_scanlines
+ (
+ number_of_rows_to_skip % mcu_row_size
+ );
+ unsigned int number_of_rows_to_skip_using_raw
+ (
+ number_of_rows_to_skip - number_of_rows_to_skip_using_scanlines
+ );
+
+ while ( number_of_rows_to_skip_using_raw )
+ {
+ unsigned int const lines_to_read( _countof( dummy_component_2d_array ) );
+ BOOST_VERIFY
+ (
+ jpeg_read_raw_data
+ (
+ &mutable_this().decompressor(),
+ dummy_scan_lines,
+ lines_to_read
+ ) == lines_to_read
+ );
+ number_of_rows_to_skip_using_raw -= lines_to_read;
+ }
+
+ mutable_this().decompressor().raw_data_out = false;
+ mutable_this().decompressor().global_state = DSTATE_SCANNING;
+ while ( number_of_rows_to_skip_using_scanlines-- )
+ {
+ BOOST_VERIFY
+ (
+ jpeg_read_scanlines
+ (
+ &mutable_this().decompressor(),
+ &dummy_scanline_buffer,
+ 1
+ ) == 1
+ );
+ }
+ }
+
+ libjpeg_image & mutable_this() const { return static_cast<libjpeg_image &>( libjpeg_base::mutable_this() ); }
+
+private:
+ friend class libjpeg_view_base;
+
+};
+
+#if defined(BOOST_MSVC)
+# pragma warning( pop )
+#endif
+
+
+//...zzz...incomplete...
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \class libjpeg_view_base
+///
+////////////////////////////////////////////////////////////////////////////////
+
+class libjpeg_view_base : noncopyable
+{
+public:
+ ~libjpeg_view_base()
+ {
+ }
+
+protected:
+ libjpeg_view_base( libjpeg_image & bitmap, unsigned int const lock_mode, libjpeg_image::roi const * const p_roi = 0 )
+ {
+ }
+
+ template <typename Pixel>
+ typename type_from_x_iterator<Pixel *>::view_t
+ get_typed_view()
+ {
+ //todo assert correct type...
+ interleaved_view<Pixel *>( bitmapData_.Width, bitmapData_.Height, bitmapData_.Scan0, bitmapData_.Stride );
+ }
+
+private:
+};
+
+
+//...zzz...incomplete...
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \class libjpeg_view
+///
+////////////////////////////////////////////////////////////////////////////////
+
+template <typename Pixel>
+class libjpeg_view
+ :
+ private libjpeg_view_base,
+ public type_from_x_iterator<Pixel *>::view_t
+{
+public:
+ libjpeg_view( libjpeg_image & image, libjpeg_image::roi const * const p_roi = 0 )
+ :
+ libjpeg_view_base( image, ImageLockModeRead | ( is_const<Pixel>::value * ImageLockModeWrite ), p_roi ),
+ type_from_x_iterator<Pixel *>::view_t( get_typed_view<Pixel>() )
+ {}
+};
+
+
+//------------------------------------------------------------------------------
+} // namespace detail
+//------------------------------------------------------------------------------
+} // namespace gil
+//------------------------------------------------------------------------------
+} // namespace boost
+//------------------------------------------------------------------------------
+#endif // libjpeg_private_base_hpp


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk