///###////////////////////////////////////////////////////////////////////////
//
// Burton Computer Corporation
// http://www.burton-computer.com
// http://www.cooldevtools.com
// $Id$
//
// Copyright (C) 2007 Burton Computer Corporation
// ALL RIGHTS RESERVED
//
// This program is open source software; you can redistribute it
// and/or modify it under the terms of the Q Public License (QPL)
// version 1.0. Use of this software in whole or in part, including
// linking it (modified or unmodified) into other programs is
// subject to the terms of the QPL.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// Q Public License for more details.
//
// You should have received a copy of the Q Public License
// along with this program; see the file LICENSE.txt.  If not, visit
// the Burton Computer Corporation or CoolDevTools web site
// QPL pages at:
//
//    http://www.burton-computer.com/qpl.html
//    http://www.cooldevtools.com/qpl.html
//

#if defined(HAVE_PNG)

#include <stdexcept>
#include "AbstractTokenizer.h"
#include "MD5Digester.h"
#include "Message.h"
#include "StringReader.h"
#include "PngParser.h"

PngParser::PngParser(Message *message,
                     AbstractTokenizer *tokenizer,
                     AbstractTokenReceiver *receiver,
                     const string &prefix,
                     const Buffer<unsigned char> &bytes)
  : ImageParser(message, tokenizer, receiver, prefix, bytes),
    m_pngPtr(0),
    m_infoPtr(0),
    m_initialized(false)
{
}

PngParser::~PngParser()
{
  if (m_initialized) {
    if (m_infoPtr) {
      png_destroy_read_struct(&m_pngPtr, &m_infoPtr, png_infopp_NULL);
    } else {
      png_destroy_read_struct(&m_pngPtr, png_infopp_NULL, png_infopp_NULL);
    }
  }
}

bool PngParser::parseImage()
{
  try {
    digestImage();
    initializeImage();
  } catch (runtime_error &ex) {
    return false;
  }
}

void PngParser::initializeImage()
{
  m_pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if (!m_pngPtr) {
    throw runtime_error("allocate png ptr failed");
  }

  m_initialized = true;
  m_infoPtr = png_create_info_struct(m_pngPtr);
  if (!m_infoPtr) {
    throw runtime_error("allocate info ptr failed");
  }

  if (setjmp(png_jmpbuf(m_pngPtr))) {
    throw runtime_error("png error");
  }

  png_set_progressive_read_fn(m_pngPtr, this, receiveHeader, NULL, NULL);
  png_process_data(m_pngPtr, m_infoPtr, m_bytes.get(), m_bytes.length());
}

void PngParser::receiveHeader(png_structp png_ptr,
                              png_infop info)
{
  PngParser *parser = (PngParser *)png_get_progressive_ptr(png_ptr);
  parser->tokenizeImage();
}

void PngParser::tokenizeImage()
{
  png_uint_32 width, height;
  int bit_depth, color_type, interlace_type;

  png_get_IHDR(m_pngPtr, m_infoPtr, &width, &height, &bit_depth, &color_type,
               &interlace_type, int_p_NULL, int_p_NULL);

  string base_token("image_0");
  sendToken(base_token + "_height_" + num_to_string((int)width));
  sendToken(base_token + "_width_" + num_to_string((int)height));
  sendToken(base_token + "_bit_depth_" + num_to_string((int)bit_depth));
  sendToken(base_token + "_color_type_" + num_to_string(color_type));
  sendToken(base_token + "_interlace_type_" + num_to_string(interlace_type));

  png_start_read_image(m_pngPtr);
}

#endif // HAVE_PNG


syntax highlighted by Code2HTML, v. 0.9.1