Logo Search packages:      
Sourcecode: vdr-plugin-burn version File versions  Download package

gdwrapper.c

/*
 * See the files COPYING and README for copyright information and how to reach
 * the author.
 *
 *  $Id: gdwrapper.c,v 1.10 2006/09/16 18:33:36 lordjaxom Exp $
 */

#include "common.h"
#include "gdwrapper.h"
#include "iconvwrapper.h"
#include "proctools/format.h"
#include "proctools/logger.h"
#include <vdr/i18n.h>
#include <algorithm>
#include <cctype>
#include <cstdlib>

namespace gdwrapper
{

      using namespace std;
      using vdr_burn::user_exception;
      using proctools::format;
      using proctools::logger;

      inline char mytolower( char c ) { return tolower( c ); }

      // --- image --------------------------------------------------------------

      image::image( const string& filename, bool alphaBlending ):
                  m_image( 0 )
      {
            if ( filename.length() < 4 ) {
                  logger::error( format( "couldn't open image {0} for reading: filename too short to determine format" )
                                       % filename, false );
                  throw user_exception( tr("Couldn't open image file!") );
            }

            FILE* fp = fopen( filename.c_str(), "rb" );
            if (fp == 0) {
                  logger::error( format( "couldn't open image {0} for reading" ) % filename );
                  throw user_exception( tr("Couldn't open image file!") );
            }

            string extension;
            extension.resize( 4 );
            transform( filename.begin() + filename.length() - 4, filename.end(), extension.begin(), mytolower );
            if ( extension == ".png" )
                  m_image = gdImageCreateFromPng( fp );
            else if ( extension == ".jpg" || extension == ".jpeg" )
                  m_image = gdImageCreateFromJpeg( fp );
            else {
                  logger::error( format( "couldn't read image {0}: unsupported file format" ) % filename, false );
                  throw user_exception( tr("Couldn't open image file!") );
            }
            fclose( fp );

            if (m_image == 0) {
                  logger::error( format( "couldn't read image {0}: possibly corrupt" ) % filename, false );
                  throw user_exception( tr("Couldn't open image file!") );
            }
            gdImageSaveAlpha( m_image, 1 );
            gdImageAlphaBlending( m_image, alphaBlending ? 1 : 0 );
      }

      image::image( int width, int height, bool alphaBlending ):
                  m_image( gdImageCreateTrueColor( width, height ) )
      {
            if (m_image == 0) {
                  logger::error( "couldn't create new image: possibly out of memory" );
                  throw user_exception( tr("Couldn't create new image!") );
            }
            gdImageSaveAlpha( m_image, 1 );
            gdImageAlphaBlending( m_image, alphaBlending ? 1 : 0 );
      }

      image::~image()
      {
            if (m_image != 0)
                  gdImageDestroy( m_image );
      }

      void image::draw_image( const point& position, const image& image_ )
      {
            gdImageCopy( m_image, image_.m_image, position.x, position.y, 0, 0, image_.m_image->sx, image_.m_image->sy );
      }

      string image::wrap_text( int width, int& lineHeight, const string& text, const font_spec& font )
      {
            static const string delimiters( "-.,:;!?_" );

            const string fontPath( setup::get_font_path() + "/" + font.face + ".ttf" );
            string result;
            string::const_iterator lastWord = text.begin();
            string::const_iterator thisLine = text.begin();
            lineHeight = 0;

            for ( string::const_iterator pos = text.begin(); pos != text.end(); ++pos ) {
                  bool isSpace = isspace( *pos );

                  if ( !isSpace && delimiters.find( *pos ) == string::npos && pos + 1 < text.end() )
                        continue;

                  bool isNewline = ( *pos == '\n' );

#warning TODO: check if there is a whole word of delimiters here

                  string sample( thisLine, pos );
                  if ( !isSpace ) {
                        sample.append( pos, pos + 1 );
//                      if ( pos + 1 < text.end() )
//                            ++pos;
                  }

                  int bounds[8];
                  const char* error = gdImageStringFT( 0, bounds, 0, const_cast<char*>( fontPath.c_str() ), font.size, 0, 0, 0,
                                                                         const_cast<char*>( sample.c_str() ) );
                  if (error != 0) {
                        string message( error );
                        if ( message == "Could not find/open font" )
                              message += " " + fontPath;
                        logger::error( format( "Couldn't render text: {0}" ) % message, false );
                        throw user_exception( tr("Couldn't render menu images!") );
                  }

                  int lineWidth = bounds[2] - bounds[0];
                  int currentLineHeight = bounds[3] - bounds[5];
                  if ( sample != "" && currentLineHeight > lineHeight )
                        lineHeight = currentLineHeight;
                  if ( lineWidth > width || isNewline ) {
                        if ( isNewline || lastWord == thisLine )
                              lastWord = pos;

                        result.append( thisLine, lastWord );
                        if ( pos + 1 < text.end() ) {
                              result.append( "\n" );
//                            if ( isNewline )
//                                  ++pos;
                        }
                        thisLine = lastWord + 1;
                  }

                  lastWord = pos;
            }

            if ( thisLine < text.end() )
                  result.append( thisLine, text.end() );

            return result;

//          string result( text.substr( 0, text.find_last_not_of( '\n' ) ) );
//          string::iterator blank = result.end();
//          string::iterator delim = result.end();
//          int lines = 1;
//          int totalwidth = 0;
//          lineHeight = 0;
//
//          char* c_font = strdup( font_.filename.c_str() );
//
//          for (string::iterator pos = result.begin(); pos != result.end(); ) {
//                if (*pos == '\n') {
//                      ++lines; ++pos;
//                      totalwidth = 0;
//                      blank = delim = result.end();
//                      continue;
//                } else if (isspace( *pos ))
//                      blank = pos;
//
//                char buf[2] = { *pos, '\0' };
//                int bounds[8];
//                gdImageStringFT( 0, bounds, 0, c_font, font_.size, 0, 0, 0, buf );
//
//                int charwidth = bounds[2] - bounds[0] + 2; // char spacing
//                lineHeight = bounds[3] - bounds[1] + 1;
//                if (totalwidth + charwidth > width) {
//                      if (blank != result.end()) {
//                            *blank = '\n';
//                            pos = blank;
//                            continue;
//                      }
//
//                      if (delim != result.end())
//                            pos = delim + 1;
//
//                      result.insert( pos, '\n' );
//                      continue;
//                }
//
//                totalwidth += charwidth;
//
//                if (delimiters.find( *pos ) != string::npos) {
//                      delim = pos;
//                      blank = result.end();
//                }
//
//                ++pos;
//          }
//
//          free( c_font );
//
//          if (lineHeight > 0)
//                ++lines;
//          return result;
      }

      int image::draw_text( const text_spec& region, const std::string& text, int firstLine )
      {
            if ( text.empty() )
                  return -1;

            const string fontPath( setup::get_font_path() + "/" + region.font.face + ".ttf" );
            int lineh;
            string wrappedText = wrap_text( region.boundaries.width, lineh, text, region.font );

            int y_ = region.boundaries.y;
            int lines = 0, width_, height_;
            int white = gdImageColorResolveAlpha(m_image, 255, 255, 255, 0);
            int bounds[8];

            if (lineh == 0)
                  abort();

            string::size_type pos = 0;
            string::size_type next;
            while ( y_ + lineh < region.boundaries.y + region.boundaries.height - 1 &&
                        ( next = wrappedText.find( '\n', pos ) ) != string::npos ) {
                  string line( wrappedText.substr( pos, next - pos ) );

                  if (lines++ >= firstLine) {
                        gdImageStringFT( 0, bounds, 0, const_cast<char*>( fontPath.c_str() ),
                                                 region.font.size, 0, 0, 0, const_cast<char*>( line.c_str() ) );
                        width_ = bounds[2] - bounds[0] + 1;
                        height_ = bounds[3] - bounds[1] + 1;
                        if ( region.align == 0 )
                              gdImageStringFT( m_image, bounds, white, const_cast<char*>( fontPath.c_str() ),
                                                       region.font.size, 0, region.boundaries.x, y_ + lineh,
                                                       const_cast<char*>( line.c_str() ) );
                        else if (region.align == 2)
                              gdImageStringFT( m_image, bounds, white, const_cast<char*>( fontPath.c_str() ),
                                                       region.font.size, 0, region.boundaries.x + region.boundaries.width - width_ - 1,
                                                       y_ + lineh, const_cast<char*>( line.c_str() ) );
                        y_ += lineh;
                  }

                  pos = next + 1;
                  if ( pos == wrappedText.length() ) {
                        lines = -1;
                        break;
                  }
            }

            if ( pos < wrappedText.length() && y_ + lineh < region.boundaries.y + region.boundaries.height) {
                  string rest( wrappedText.substr( pos ) );
                  gdImageStringFT( 0, bounds, 0, const_cast<char*>( fontPath.c_str() ), region.font.size, 0, 0, 0,
                                           const_cast<char*>( rest.c_str() ) );
                  width_ = bounds[2] - bounds[0] + 1;
                  height_ = bounds[3] - bounds[1] + 1;
                  if (region.align == 0)
                        gdImageStringFT( m_image, bounds, white, const_cast<char*>( fontPath.c_str() ),
                                                 region.font.size, 0, region.boundaries.x, y_ + lineh, const_cast<char*>( rest.c_str() ) );
                  else if (region.align == 2)
                        gdImageStringFT( m_image, bounds, white, const_cast<char*>( fontPath.c_str() ),
                                                 region.font.size, 0, region.boundaries.x + region.boundaries.width - width_ - 1, y_ + lineh,
                                                 const_cast<char*>( rest.c_str() ) );
                  lines = -1;
            }

            return lines;
      }

      void image::fill_rectangle( const rectangle& rectangle, const color& color )
      {
            int bincolor = gdImageColorResolveAlpha( m_image, color.red, color.green, color.blue, color.alpha );
            gdImageFilledRectangle( m_image, rectangle.x, rectangle.y,
                                                rectangle.x + rectangle.width - 1, rectangle.y + rectangle.height - 1, bincolor );
      }

      void image::save( const std::string& filename )
      {
            FILE* fp = fopen( filename.c_str(), "wb" );
            if (fp == 0) {
                  logger::error( format( "Couldn't open image {0} for writing" ) % filename );
                  throw user_exception( tr("Couldn't save image file!") );
            }

            gdImagePng( m_image, fp );
            fclose( fp );
      }

      // --- setup --------------------------------------------------------------

      setup& setup::instance()
      {
            static setup instance_;
            return instance_;
      }

      void setup::set_font_path( const std::string& path )
      {
            instance().m_fontPath = path;
      }

}

Generated by  Doxygen 1.6.0   Back to index