Logo Search packages:      
Sourcecode: kmess version File versions  Download package

QByteArray Stream::writerGif ( const Drawing drawing,
bool  encodeToBase64 = false 
) [static]

Convert a drawing into a Fortified-GIF image.

The resulting byte array will be empty if the drawing is not valid.

Please note that this method does nothing if Isf-Qt is compiled withous GIF support. Use Stream::supportsGif() to verify whether GIF was compiled in or not.

The Fortified-GIF format is nothing more than a GIF image with the original ISF drawing added as a GIF Comment field.

See also:
supportsGif()
Parameters:
drawingSource drawing
encodeToBase64Whether the converted GIF should be encoded with Base64 or not
Returns:
Byte array with a GIF data stream (optionally encoded with Base64)

Definition at line 460 of file isfqt.cpp.

References Isf::Drawing::pixmap().

{
  QByteArray imageBytes;

#if ISFQT_GIF_ENABLED == 1
  Drawing source( drawing );

  // Get the ISF data stream
  QByteArray isfData( writer( source ) );

#ifdef ISFQT_DEBUG_VERBOSE
  qDebug() << "GIF-Fortifying an ISF stream of size" << isfData.size();
#endif

  // Get the ISF pixmap and copy the pixels to an 8bpp image
  QImage isfImage( source.pixmap().toImage()
                                  .convertToFormat( QImage::Format_Indexed8,
                                                    Qt::ThresholdDither ) );

  // Initialise the gif variables
  QBuffer         gifData;
  GifFileType*    gifImage  = NULL;
  ColorMapObject* cmap      = NULL;
  int             height    = isfImage.height();
  int             width     = isfImage.width();
  int             numColors = 0;
  bool            gifError  = true;

  // Convert the image to GIF using libgif

  // Open the gif file
  gifData.open( QIODevice::WriteOnly );
  gifImage = EGifOpen( (void*)&gifData, GifWriteToByteArray );
  if( gifImage == 0 )
  {
    qWarning() << "Couldn't initialize gif library!";
    goto writeError;
  }

  // Create the color map
  numColors = ( isfImage.numColors() << 2 );
  if( numColors > 256 )
  {
    numColors = 256;
  }

  cmap = MakeMapObject( numColors, NULL );
  if( cmap == 0 && isfImage.numColors() > 1 )
  {
    qWarning() << "Couldn't create map object for gif conversion (colors:" << isfImage.numColors() << ")!";
    goto writeError;
  }

  // Fill in the color map with the colors in the image color table
  for( int i = 0; i < isfImage.numColors(); ++i )
  {
    const QRgb &color( isfImage.color( i ) );
    cmap->Colors[i].Red   = qRed  ( color );
    cmap->Colors[i].Green = qGreen( color );
    cmap->Colors[i].Blue  = qBlue ( color );
  }

  // Save the file properties
  if( EGifPutScreenDesc( gifImage, width, height, 8, 0, cmap ) == GIF_ERROR )
  {
    qWarning() << "EGifPutScreenDesc() failed!";
    goto writeError;
  }

  // Save the image format
  if( EGifPutImageDesc( gifImage, 0, 0, width, height, 0, NULL ) == GIF_ERROR )
  {
    qWarning() << "EGifPutImageDesc() failed!";
    goto writeError;
  }


  /**
   * FIXME: If to write the scanlines you use
   *   EGifPutLine( gifImage, isfImage.bits(), isfImage.width() * isfImage.height() )
   * i.e. convert the complete image in one call, then the resulting image is mangled.
   * Something is wrong with the width or so, it seems to be off by about two pixels.
   */
  // Write every scanline
  for( int line = 0; line < height; ++line )
  {
    if( EGifPutLine( gifImage, isfImage.scanLine( line ), width ) == GIF_ERROR )
    {
      qWarning() << "EGifPutLine failed at scanline" << line
                 << "(height:" << isfImage.height()
                 << ", width:" << isfImage.width()
                 << ", bytesperline:" << isfImage.bytesPerLine() << ")";
      goto writeError;
    }
  }


/**
 * Completing the funny theater that is giflib, EGifPutComment() doesn't
 * work, or I've overlooked something Extremely Obvious(tm).
 * Googling didn't help: I rewrote it (from the giflib source) with
 * Qt.
 */
/*
  if( EGifPutComment( gifImage, isfData.constData() ) == GIF_ERROR )
  {
    qWarning() << "EGifPutComment has failed!";
    goto writeError;
  }
*/

  // Write the ISF stream into the Comment Extension field
  if( isfData.size() < MAX_GIF_BYTE )
  {
    EGifPutExtension( gifImage, COMMENT_EXT_FUNC_CODE, isfData.size(), isfData.constData() );
  }
  else
  {
    // Write the extension
    if( EGifPutExtensionFirst( gifImage, COMMENT_EXT_FUNC_CODE, MAX_GIF_BYTE, isfData.left( MAX_GIF_BYTE ).data() ) == GIF_ERROR )
    {
      qWarning() << "EGifPutExtensionFirst failed!";
      goto writeError;
    }

    // The first MAX_GIF_BYTE bytes have been written already
    quint32 pos = MAX_GIF_BYTE;

    quint32 length = ( isfData.size() - pos );

    // Write all the full data blocks
    while( length >= MAX_GIF_BYTE )
    {
      if( EGifPutExtensionNext( gifImage, 0, MAX_GIF_BYTE, isfData.mid( pos, MAX_GIF_BYTE ).data() ) == GIF_ERROR )
      {
        qWarning() << "EGifPutExtensionNext failed!";
        goto writeError;
      }

      pos += MAX_GIF_BYTE;
      length -= MAX_GIF_BYTE;
    }

    // Write the last block
    if( length > 0 )
    {
      if( EGifPutExtensionLast( gifImage, 0, length, isfData.mid( pos, MAX_GIF_BYTE ).data() ) == GIF_ERROR )
      {
        qWarning() << "EGifPutExtensionLast (n) failed!";
        goto writeError;
      }
    }
    else
    {
      if( EGifPutExtensionLast( gifImage, 0, 0, 0 ) == GIF_ERROR )
      {
        qWarning() << "EGifPutExtensionLast (0) failed!";
        goto writeError;
      }
    }
  }

  gifError = false;

writeError:
  // Clean up the GIF converter etc
  EGifCloseFile( gifImage );
  FreeMapObject( cmap );
  gifData.close();

  if( gifError )
  {
    qWarning() << "GIF error code:" << GifLastError();
  }
  else
  {
    // Return the GIF data
    imageBytes = gifData.data();

#ifdef ISFQT_DEBUG_VERBOSE
    qDebug() << "Converted a" << isfData.size() << "bytes Ink to GIF:" << isfImage.height() << "x" << isfImage.width() << "->" << imageBytes.size() << "bytes";
#endif
  }

#endif // ISFQT_GIF_ENABLED == 1


  // Convert to Base64 if needed
  if( encodeToBase64 )
  {
    return imageBytes.toBase64();
  }
  else
  {
    return imageBytes;
  }
}

Here is the call graph for this function:


Generated by  Doxygen 1.6.0   Back to index