<?php

/* vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP version 4                                                        |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2002 The PHP Group                                |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.0 of the PHP license,       |
// | that is bundled with this package in the file LICENSE, and is        |
// | available at through the world-wide-web at                           |
// | http://www.php.net/license/2_02.txt.                                 |
// | If you did not receive a copy of the PHP license and are unable to   |
// | obtain it through the world-wide-web, please send a note to          |
// | license@php.net so we can mail you a copy immediately.               |
// +----------------------------------------------------------------------+
// | Authors: Evgeny Stepanischev <imbolk@gmail.com>                      |
// +----------------------------------------------------------------------+
// Project home page (Russian): http://bolknote.ru/files/monobmp/
//
// $Id$


require_once 'Image/XBM.php';

class Image_MonoBMP extends Image_XBM
{
    function Image_MonoBMP()
    {
        parent::Image_XBM();
    }

    /**
     * Output image to browser or file
     *
     * @param string $filename (optional) filename for output
     * @return bool PEAR_Error or true
     * @access public
     */
    function output($filename = false)
    {
        $s = '';
        $wx = ceil($this->_sx / 8);

        // Prepare image data
        for ($y = $this->_sy - 1; $y >= 0; --$y) {
            for ($x = 0; $x < $wx; ++$x) {
                $s .= chr($this->_bitrev($this->_image[$x][$y]));
            }

            for (; $x % 4; $x++) {
                $s .= "\0";
            }
        }

        $size = strlen($s);

        // Prepare subheader
        $header = pack
        (
            'VVvvV6',
            $this->_sx, // width
            $this->_sy, // height
            1,          // planes
            1,          // bit count
            0,          // compress
            $size,      // picture size (bytes)
            0xB12,      // X pixels per meter
            0xB12,      // Y pixels per meter
            0,          // color used (0 mean "all")
            0           // important colors (all)
        );

        $header = pack('V', strlen($header) + 4) . $header;

        // Adding color table (white and black colors)
        $color = "\xFF\xFF\xFF\0\0\0\0\0";

        // Pack main header
        $main = pack('vvV', 0, 0, 0x3E);

        // Build header and bitmap data
        $s = $main.$header.$color.$s."\0";
        $s = 'BM'.pack('V', strlen($s) + 4) . $s;

        if ($filename === false) {
            echo $s;
        } else {
            if ($fp = fopen($filename, 'w')) {
                flock($fp, LOCK_EX);

                fwrite($fp, $s);
                fclose($fp);
            } else {
                return PEAR::raiseError('Cannot open file for writing.', 5);
            }
        }
        return true;
    }

    /**
     * Create a new image from XBM file or URL
     *
     * @param string $filename XBM file name or URL
     * @return mixed PEAR_error or true for success
     * @access public
     */
    function createFromFile($filename)
    {
        $fp = fopen($filename, 'r');
        if (!is_resource($fp)) {
            return PEAR::raiseError('Cannot open file.', 4);
        }

        // Bitmap magick signature
        $sign = fread($fp, 2);
        if ($sign <> 'BM') {
            return PEAR::raiseError('Invalid BMP file.', 5);
        }

        // Skip header
        fread($fp, 16);

        // Width, height
        extract(unpack('Vwidth/Vheight/vplanes', fread($fp, 10)));

        // Check if bitmap is b/w
        if ($planes != 1) {
            return PEAR::raiseError('Invalid BMP file.', 5);
        }

        // Create blank picture
        $this->create($width, $height);

        // Skip rest of the header
        fread($fp, 34);

        // Read the picture
        $sx = ceil($width / 8);

        // Fill image by bitmap data
        for ($y = $height - 1; $y >= 0; --$y) {
            for ($x = 0; $x < $sx; ++$x) {
                $this->_image[$x][$y] = $this->_bitrev(ord(fread($fp, 1)));
            }

            if ($x % 4) {
                fread($fp, 4 - $x % 4);
            }
        }

        fclose($fp);
    }

    /**
     * Bit reverse function
     *
     * @param int $num number for reverse
     * @return int bit reversed number
     * @access private
     */
    function _bitrev($num)
    {
        for ($i = $r = 0; $i<8; $i++) {
            $r <<= 1;
            $r |= $num & 1;
            $num >>= 1;
        }

        return $r;
    }
}
?>