soderlind/read-offline

View on GitHub
inc/class-read-offline-create.php

Summary

Maintainability
F
1 wk
Test Coverage
<?php
use PHPePub\Core\EPub;
use PHPePub\Core\EPubChapterSplitter;
use PHPePub\Core\Logger;
use PHPePub\Core\Structure\OPF\DublinCore;
use PHPePub\Core\Structure\OPF\MetaValue;
use PHPePub\Helpers\CalibreHelper;
use PHPePub\Helpers\URLHelper;
use PHPZip\Zip\File\Zip;

// require_once READOFFLINE_PATH . '/lib/phpMobi/MOBIClass/MOBI.php';

class Read_Offline_Create extends Read_Offline {

    private static $instance;

    public static function get_instance() {

        if ( self::$instance ) {
            return self::$instance;
        }

        self::$instance = new self();
        return self::$instance;
    }

    private function __construct() {
        parent::get_instance();
    }


    private $author_firstlast;
    private $author_lastfirst;
    private $subject;
    private $keywords;
    private $generator;
    private $html;

    function init( $post ) {
        if ( '' !== get_the_author_meta( 'user_firstname', $post->post_author ) && '' !== get_the_author_meta( 'user_lastname', $post->post_author ) ) {
            $this->author_firstlast = sprintf( '%s %s', get_the_author_meta( 'user_firstname', $post->post_author ), get_the_author_meta( 'user_lastname', $post->post_author ) );
            $this->author_lastfirst = sprintf( '%s, %s', get_the_author_meta( 'user_firstname', $post->post_author ), get_the_author_meta( 'user_lastname', $post->post_author ) );
        } else {
            $this->author_firstlast = get_the_author_meta( 'display_name', $post->post_author );
            $this->author_lastfirst = get_the_author_meta( 'display_name', $post->post_author );
        }

        $this->subject   = ( count( wp_get_post_categories( $post->ID ) ) ) ? implode( ' ,', array_map( 'get_cat_name', wp_get_post_categories( $post->ID ) ) ) : '';
        $this->keywords  = $this->_get_taxonomies_terms( $post );
        $this->generator = 'Read Offline ' . READOFFLINE_VERSION . ' by Per Soderlind, http://wordpress.org/extend/plugins/read-offline/';

        // content
        $this->html   = '<h1 class="entry-title">' . get_the_title( $post->ID ) . '</h1>';
        $content     = $post->post_content;
        $content     = preg_replace( '/\[\\/?(pdf|epub|mobi|print)(\\s+.*?\]|\])/i', '', $content ); // remove all [readonline] shortcodes
        $this->html .= $this->_remove_dont_readoffline( apply_filters( 'the_content', $content ) );
    }

    function pprint( $post ) {
        $print_header = '';
        $print_css    = '';
        if ( '0' != parent::$options['print']['header'] ) {
            $print_header = sprintf(
                'BODY:before {  display: block;  content: "%s";  margin-bottom: 10px;  border: 1px solid #bbb;  padding: 3px 5px;  font-style: italic;}',
                $this->_parse_header_footer( $post, parent::$options['print']['headertext'], true )
            );

        }

        $print_style = $this->_get_child_array_key( 'print', parent::$options['print']['style'] );
        switch ( $print_style ) {
            case 'theme_style':
                $print_css = file_get_contents( get_stylesheet_uri() );
                break;

            case 'css':
                $print_css = ( '' != parent::$options['print']['css'] ) ? parent::$options['print']['css'] : '';
                break;
        }
        printf(
            '<!DOCTYPE html><html%s><head><meta charset="UTF-8"><title>%s</title><style type="text/css" media="print">%s%s</style></head><body>%s</body></html>',
            ( is_rtl() ) ? " dir='rtl'" : '',
            get_the_title( $post->ID ),
            $print_css,
            $print_header,
            $this->html
        );
    }


    function epub( $post ) {

        $iso6391 = ( '' == get_locale() ) ? 'en' : strtolower( substr( get_locale(), 0, 2 ) ); // only ISO 639-1
        if ( is_rtl() ) {
            $writing_direction = EPub::DIRECTION_RIGHT_TO_LEFT;
        } else {
            $writing_direction = EPub::DIRECTION_LEFT_TO_RIGHT;
        }

        $epub            = new EPub( EPub::BOOK_VERSION_EPUB3, $iso6391, $writing_direction );
        $epub->isLogging = false; // @codingStandardsIgnoreLine
        /*
         * Social DRM:
         * - Page 2 contains an Ex Libris (image with customer name), that can be customised per publisher and per customer.
         * - Every chapter ends with a personalised footer text.
         * - The last page contains a disclaimer and logo, and has a corresponding entry in the table of contents.
         */
        $epub->setGenerator( $this->generator );
        $epub->setTitle( $post->post_title ); // setting specific options to the EPub library
        $epub->setIdentifier( $post->guid, EPub::IDENTIFIER_URI );
        $epub->setLanguage( $iso6391 );
        $epub->setAuthor( $this->author_firstlast, $this->author_lastfirst ); // "Firstname Lastname", "Lastname, First names"
        $epub->setPublisher( get_bloginfo( 'name' ), get_bloginfo( 'url' ) );
        $epub->setSourceURL( $post->guid );
        $epub->rootLevel();

        $print_css   = '';
        $print_style = $this->_get_child_array_key( 'epub', parent::$options['epub']['style'] );
        switch ( $print_style ) {
            case 'theme_style':
                // $print_css = file_get_contents(get_stylesheet_uri());
                break;

            case 'css':
                $print_css = ( '' != parent::$options['epub']['css'] ) ? parent::$options['epub']['css'] : '';
                break;
        }
        if ( '' != $print_css ) {
            $epub->addCSSFile( 'styles.css', 'css1', $print_css );
            // $epub->setCoverCss($print_css);
        }
        /**
         * Coverart
         */
        $coverart   = $this->_get_child_array_key( 'epub', parent::$options['epub']['art'] );
        $upload_dir = wp_upload_dir();
        if ( 'none' != $coverart ) {

            switch ( $coverart ) {

                case 'feature_image':
                    $image_url = wp_get_attachment_url( get_post_thumbnail_id( $post->ID, 'thumbnail' ) );
                    if ( false !== $this->_url_exists( $image_url ) ) {
                        $attachment_data = wp_get_attachment_metadata( get_post_thumbnail_id( $post->ID, 'thumbnail' ) );

                        $image_path = $upload_dir['basedir'] . '/' . $attachment_data['file'];
                        if ( count( $attachment_data ) ) {
                            $epub->setCoverImage( $image_path );
                        }
                    }
                    break;

                case 'custom_image':
                    $epub->setCoverImage( 'Cover.jpg', file_get_contents( parent::$options['epub']['custom_image'] ) );
                    break;
            }
        }
        $epub->setDate( get_the_date( 'U', $post ) );
        $epub->setRights( parent::$options['copyright']['message'] );

        /*
        $content_start =
            "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
            . "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"\n"
            . "    \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
            . "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
            . "<head>"
            . "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n"
            . "<link rel=\"stylesheet\" type=\"text/css\" href=\"styles.css\" />\n"
            . "<title>" . $post->post_title . "</title>\n"
            . "</head>\n"
            . "<body>\n";
        */
        if ( '' != $print_css ) {
            $content_start = sprintf( '<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml"><head><meta charset="UTF-8" /><link rel="stylesheet" type="text/css" href="styles.css" /><title>%s</title></head><body%s>', $post->post_title, ( is_rtl() ) ? " dir='rtl'" : '' );
        } else {
            $content_start = sprintf( '<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml"><head><meta charset="UTF-8" /><title>%s</title></head><body%s>', $post->post_title, ( is_rtl() ) ? " dir='rtl'" : '' );
        }
        $content_end = "\n</body>\n</html>\n";

        $cover = $content_start . sprintf( "<h1>%s</h1>\n<h2>%s: %s</h2>\n", $post->post_title, _x( 'By', 'Rererence between title and author: Title By: Author Name' ), $this->author_firstlast ) . $content_end;
        $epub->addChapter( 'Cover', 'Cover.xhtml', $cover );

        /*
        $epub->addFileToMETAINF("com.apple.ibooks.display-options.xml", "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<display_options>\n    <platform name=\"*\">\n        <option name=\"fixed-layout\">true</option>\n        <option name=\"interactive\">true</option>\n        <option name=\"specified-fonts\">true</option>\n    </platform>\n</display_options>");
        */

        $html = $this->html;

        $add_toc = $this->_get_child_array_key( 'epub', parent::$options['epub']['add_toc'] );
        $toc     = $this->_get_child_array_key( 'epub', parent::$options['epub']['toc'] );
        $content = array();
        if ( 0 !== $add_toc && 0 !== $toc ) {
            $content = $this->_split_content( $html, $toc );
            if ( 0 != count( $content ) ) {
                $chapter_num = 1;
                // $epub->buildTOC( null, 'toc', __( 'Table of Contents', 'read-offline' ), true, false );
                $levels    = array_map(
                    function( $paragraphs ) {
                        return $paragraphs['level'];
                    },
                    $content
                );
                $top_level = min( $levels );
                $epub->setCurrentLevel( 1 );
                foreach ( $content as $paragraph ) {
                    // TODO, create hieratical TOC
                    // $level = ( $paragraph['level'] > 2 ) ? $paragraph['level'] - 1 : 1;
                    // // $level = $paragraph['level'];
                    // // if ( $epub->getCurrentLevel() < $level ) {
                    // while ( $epub->getCurrentLevel() < $level ) {
                    // $epub->subLevel();
                    // }
                    // for ( $i = $epub->getCurrentLevel(); $i < $level; $i++ ) {
                    // $epub->subLevel();
                    // }
                    // // } elseif ( $epub->getCurrentLevel() > $level ) {
                    // $epub->setCurrentLevel( $level );
                    // while ( $epub->getCurrentLevel() > $level ) {
                    // $epub->backLevel();
                    // }
                    // for ( $i = $epub->getCurrentLevel(); $i > $level; $i-- ) {
                    // $epub->backLevel();
                    // }
                    // // }
                    // // $epub->setCurrentLevel( $level );
                    if ( '' !== $paragraph['title'] ) {
                        $header = sprintf( '<h%s>%s</h%s>', $paragraph['level'], $paragraph['title'], $paragraph['level'] );
                        $epub->addChapter( $paragraph['title'], sprintf( 'Chapter%03d.xhtml', $chapter_num ), $content_start . $header . $paragraph['content'] . $content_end, false, EPub::EXTERNAL_REF_ADD );
                        $chapter_num++;
                    }
                }
                $epub->rootLevel();
            }
        }

        if ( 0 === $add_toc || 0 === count( $content ) ) {
            $epub->addChapter( 'Body', 'Body.xhtml', $content_start . $html . $content_end, false, EPub::EXTERNAL_REF_ADD );
        }
        $epub->finalize();
        $zip_data = $epub->sendBook( $post->post_name );
    }

    function mobi( $post ) {

        $html = $this->html;
        $mobi = new MOBI();
        /*
        //options:
        asin
        -author
        contributor
        -description
        -imprint
        isbn
        -publisher
        published_at
        review
        rights
        -source
        -subject
        subject_code
        -title
        type
        version
         */

        $add_toc = $this->_get_child_array_key( 'mobi', parent::$options['mobi']['add_toc'] );
        $toc     = $this->_get_child_array_key( 'mobi', parent::$options['mobi']['toc'] );
        $content = array();
        if ( 0 !== $add_toc && 0 !== $toc ) {
            $content = $this->_split_content( $html, $toc );
            if ( 0 != count( $content ) ) {
                $mobi_content = new Read_Offline_MobiFile();
                $mobi_content->set( 'title', $post->post_title );
                $mobi_content->set( 'description', parent::get_excerpt_by_id( $post->ID ) );
                $mobi_content->set( 'author', $this->author_firstlast );
                $mobi_content->set( 'publishingdate', get_the_date( 'r', $post ) );

                $mobi_content->set( 'source', $post->guid );
                $mobi_content->set( 'publisher', get_bloginfo( 'name' ), get_bloginfo( 'url' ) );
                $mobi_content->set( 'subject', $this->subject );
                $mobi_content->set( 'imprint', parent::$options['copyright']['message'] );
                if ( parent::$options['mobi']['mobi_cover_image'] ) {
                    $mobi_content->appendImage( parent::image_create_frome_image( parent::$options['mobi']['mobi_cover_image'] ) );
                    $mobi_content->appendPageBreak();
                }
                foreach ( $content as $paragraph ) {
                    if ( '' !== $paragraph['title'] ) {
                        $mobi_content->appendChapterTitle( wp_strip_all_tags( $paragraph['title'] ) );
                    }
                    // if ( false !== ($imgurl = $this->_get_first_imageurl( $paragraph )) ) {
                    // $img = $this->_image_create_from_url( $imgurl );
                    // $mobi_content->appendImage( $img );
                    // }
                    $mobi_content->appendParagraph( $this->_strip_img( $paragraph['content'] ) );
                    $mobi_content->appendPageBreak();
                }
                $mobi->setContentProvider( $mobi_content );
            }
        }
        if ( 0 === $add_toc || 0 === count( $content ) ) {
            $options = array(
                'title'          => $post->post_title,
                'description'    => parent::get_excerpt_by_id( $post->ID ),
                'author'         => $this->author_firstlast,
                'subject'        => $this->subject,
                'publishingdate' => get_the_date( 'r', $post ),
                'source'         => $post->guid,
                'publisher'      => get_bloginfo( 'name' ),
                'imprint'        => parent::$options['copyright']['message'],
            );
            $mobi->setData( $this->_strip_img( $html ) );
            $mobi->setOptions( $options );
        }
        $title = $post->post_name;
        if ( false === $title ) {
            $title = 'file'; }
        $title = urlencode( substr( $title, 0, 12 ) );

        // Send the mobi file as download
        $zip_data = $mobi->download( $title . '.mobi' );
    }



    function pdf( $post ) {

        $html = $this->html;

        define( '_MPDF_TEMP_PATH', READOFFLINE_CACHE . '/tmp/' );
        define( '_MPDF_TTFONTDATAPATH', READOFFLINE_CACHE . '/font/' );
        if ( defined( 'READ_OFFLINE_FONTS' ) ) {
            define( '_MPDF_TTFONTPATH', READ_OFFLINE_FONTS );
        }
        // require_once READOFFLINE_PATH . '/lib/mpdf610/mpdf.php';

        $paper_format = sprintf(
            "'%s-%s'",
            ( 'custom_paper_format' == $this->_get_child_array_key( 'pdf_layout', parent::$options['pdf_layout']['paper_format'] ) ) ? parent::$options['pdf_layout']['custom_paper_format'] : parent::$options['pdf_layout']['paper_format'],
            parent::$options['pdf_layout']['paper_orientation']
        );

        $pdf = new \Mpdf\Mpdf(
            array(
                'mode'              => 'utf-8',
                'format'            => $paper_format,
                'default_font_size' => 0,
                'default_font'      => 'dejavusans',
                'margin_left'       => 15,
                'margin_right'      => 15,
                'margin_top'        => 16,
                'margin_bottom'     => 16,
                'margin_header'     => 9,
                'margin_footer'     => 9,
                'orientation'       => parent::$options['pdf_layout']['paper_orientation'],
            )
        );

        if ( ! defined( 'READ_OFFLINE_FONTS' ) ) {
            $pdf->fontdata = array(
                'dejavusanscondensed'  => array(
                    'R'          => 'DejaVuSansCondensed.ttf',
                    'B'          => 'DejaVuSansCondensed-Bold.ttf',
                    'I'          => 'DejaVuSansCondensed-Oblique.ttf',
                    'BI'         => 'DejaVuSansCondensed-BoldOblique.ttf',
                    'useOTL'     => 0xFF,
                    'useKashida' => 75,
                ),
                'dejavusans'           => array(
                    'R'          => 'DejaVuSans.ttf',
                    'B'          => 'DejaVuSans-Bold.ttf',
                    'I'          => 'DejaVuSans-Oblique.ttf',
                    'BI'         => 'DejaVuSans-BoldOblique.ttf',
                    'useOTL'     => 0xFF,
                    'useKashida' => 75,
                ),
                'dejavuserif'          => array(
                    'R'  => 'DejaVuSerif.ttf',
                    'B'  => 'DejaVuSerif-Bold.ttf',
                    'I'  => 'DejaVuSerif-Italic.ttf',
                    'BI' => 'DejaVuSerif-BoldItalic.ttf',
                ),
                'dejavuserifcondensed' => array(
                    'R'  => 'DejaVuSerifCondensed.ttf',
                    'B'  => 'DejaVuSerifCondensed-Bold.ttf',
                    'I'  => 'DejaVuSerifCondensed-Italic.ttf',
                    'BI' => 'DejaVuSerifCondensed-BoldItalic.ttf',
                ),
                'dejavusansmono'       => array(
                    'R'          => 'DejaVuSansMono.ttf',
                    'B'          => 'DejaVuSansMono-Bold.ttf',
                    'I'          => 'DejaVuSansMono-Oblique.ttf',
                    'BI'         => 'DejaVuSansMono-BoldOblique.ttf',
                    'useOTL'     => 0xFF,
                    'useKashida' => 75,
                ),
            );
        } else {

            $pdf->autoScriptToLang = true; // @codingStandardsIgnoreLine
            // $pdf->baseScript = 1; // @codingStandardsIgnoreLine
            $pdf->autoVietnamese = true; // @codingStandardsIgnoreLine
            $pdf->autoArabic = true; // @codingStandardsIgnoreLine

            if ( is_rtl() ) {
                $pdf->SetDirectionality( 'rtl' );
            }
        }

        $pdf->SetTitle( $post->post_title );
        $pdf->SetAuthor( $this->author_firstlast );
        $pdf->SetSubject( $this->subject );
        $pdf->SetKeywords( $this->keywords );
        $pdf->SetCreator( parent::$options['copyright']['message'] );

        $pdf->autoLangToFont      = true; // @codingStandardsIgnoreLine
        $pdf->ignore_invalid_utf8 = true; // @codingStandardsIgnoreLine
        $pdf->useSubstitutions    = false; // @codingStandardsIgnoreLine
        $pdf->simpleTables        = true; // @codingStandardsIgnoreLine
        $pdf->h2bookmarks         = array(
            'H1' => 0,
            'H2' => 1,
            'H3' => 2,
        );
        $pdf->title2annots        = true;
        /**
         * Watermark
         */
        $watermark = $this->_get_child_array_key( 'pdf_watermark', parent::$options['pdf_watermark']['watermark'] );
        switch ( $watermark ) {
            case 'watermark_text':
                $pdf->SetWatermarkText(
                    parent::$options['pdf_watermark']['watermark_text'],
                    parent::$options['pdf_watermark']['watermark_tranparency']
                );
                break;

            case 'watermark_image':
                $pdf->SetWatermarkImage(
                    parent::$options['pdf_watermark']['watermark_image'],
                    parent::$options['pdf_watermark']['watermark_tranparency']
                );
                break;
        }

        /**
         * Protection
         */
        $has_protection = $this->_get_child_array_key( 'pdf_protection', parent::$options['pdf_protection']['protection'] );
        if ( 'password_owner' == $has_protection ) {
            $user_can       = array_keys(
                array_intersect_key(
                    array(
                        'copy'          => 1,
                        'print'         => 1,
                        'modify'        => 1,
                        'extract'       => 1,
                        'assemble'      => 1,
                        'print-highres' => 1,
                    ),
                    array_filter( parent::$options['pdf_protection']['user_can_do'] )
                )
            );
            $password_user  = parent::$options['pdf_protection']['password_user'];
            $password_owner = parent::$options['pdf_protection']['password_owner'];
            $pdf->SetProtection( $user_can, $password_user, $password_owner, 128 );
        }

        /**
         * PDFA
         */
        if ( isset( parent::$options['pdf_layout']['pdfa'] ) && '1' == parent::$options['pdf_layout']['pdfa'] ) {
            /*
            PDFA Fatal Errors
            Some issues cannot be fixed automatically by mPDF and will generate fatal errors:
            - $useCoreFontsOnly is set as TRUE (cannot embed core fonts)
            BIG5, SJIS, UHC or GB fonts cannot be used (cannot be embedded)
            - Watermarks - text or image - are not permitted (transparency is disallowed so will make text unreadable)
            Using CMYK colour in functions SetTextColor() SetDrawColor() or SetFillColor()
            PNG images with alpha channel transparency ('masks' not allowed)
            encryption is enabled
             */
            $pdf->showWatermarkText  = false; // @codingStandardsIgnoreLine
            $pdf->showWatermarkImage = false; // @codingStandardsIgnoreLine
            $pdf->useCoreFontsOnly   = false; // @codingStandardsIgnoreLine
            $pdf->PDFA               = true; // @codingStandardsIgnoreLine

        }

        /**
         * header and footer
         */
        $print_css = '';
        $header    = $this->_get_child_array_key( 'pdf_header', parent::$options['pdf_header']['header'] );
        switch ( $header ) {
            case 'default_header':
                if ( ( '0' == parent::$options['pdf_header']['default_header'][0] &&
                     '0' == parent::$options['pdf_header']['default_header'][1] &&
                     '0' == parent::$options['pdf_header']['default_header'][2] ) ) {
                    break;
                }
                $pdf->DefHeaderByName(
                    'pdfheader',
                    array(
                        'L'    => array(
                            'content'     => ( '0' != parent::$options['pdf_header']['default_header'][0] ) ? $this->_header_footer( $post, parent::$options['pdf_header']['default_header'][0] ) : '',
                            'font-size'   => 10,
                            'font-style'  => 'B',
                            'font-family' => 'serif',
                            'color'       => '#000000',
                        ),
                        'C'    => array(
                            'content'     => ( '0' != parent::$options['pdf_header']['default_header'][1] ) ? $this->_header_footer( $post, parent::$options['pdf_header']['default_header'][1] ) : '',
                            'font-size'   => 10,
                            'font-style'  => 'B',
                            'font-family' => 'serif',
                            'color'       => '#000000',
                        ),
                        'R'    => array(
                            'content'     => ( '0' != parent::$options['pdf_header']['default_header'][2] ) ? $this->_header_footer( $post, parent::$options['pdf_header']['default_header'][2] ) : '',
                            'font-size'   => 10,
                            'font-style'  => 'B',
                            'font-family' => 'serif',
                            'color'       => '#000000',
                        ),
                        'line' => 1,
                    )
                );
                break;
            case 'custom_header':
                $pdf->DefHTMLHeaderByName(
                    'pdfheader',
                    $this->_parse_header_footer( $post, parent::$options['pdf_header']['custom_header'] )
                );
                break;
        }

        $footer = $this->_get_child_array_key( 'pdf_footer', parent::$options['pdf_footer']['footer'] );
        switch ( $footer ) {
            case 'default_footer':
                if ( ! isset( parent::$options['pdffooter'], parent::$options['pdffooter']['default_footer'] ) ||
                    ( '0' == parent::$options['pdffooter']['default_footer'][0] &&
                     '0' == parent::$options['pdffooter']['default_footer'][1] &&
                     '0' == parent::$options['pdffooter']['default_footer'][2] ) ) {
                    break;
                }
                $pdf->DefFooterByName(
                    'pdffooter',
                    array(
                        'L'    => array(
                            'content'     => ( '0' != parent::$options['pdf_footer']['default_footer'][0] ) ? $this->_header_footer( $post, parent::$options['pdf_footer']['default_footer'][0] ) : '',
                            'font-size'   => 10,
                            'font-style'  => 'B',
                            'font-family' => 'serif',
                            'color'       => '#000000',
                        ),
                        'C'    => array(
                            'content'     => ( '0' != parent::$options['pdf_footer']['default_footer'][1] ) ? $this->_header_footer( $post, parent::$options['pdf_footer']['default_footer'][1] ) : '',
                            'font-size'   => 10,
                            'font-style'  => 'B',
                            'font-family' => 'serif',
                            'color'       => '#000000',
                        ),
                        'R'    => array(
                            'content'     => ( '0' != parent::$options['pdf_footer']['default_footer'][2] ) ? $this->_header_footer( $post, parent::$options['pdf_footer']['default_footer'][2] ) : '',
                            'font-size'   => 10,
                            'font-style'  => 'B',
                            'font-family' => 'serif',
                            'color'       => '#000000',
                        ),
                        'line' => 1,
                    )
                );
                break;
            case 'custom_footer':
                $pdf->DefHTMLFooterByName(
                    'pdffooter',
                    $this->_parse_header_footer( $post, parent::$options['pdf_footer']['custom_footer'] )
                );
                break;
            default:
                $print_footer = '';
                break;
        }

        /**
         * Default CSS
         */
        if ( 'default_header' == $header || 'default_footer' == $footer ) {
            $pdf->WriteHTML( file_get_contents( READOFFLINE_PATH . '/templates/pdf/default-print.css' ), 1 );
        }

        /**
         * Theme / Custom CSS, overrides default css
         */

        $css = $this->_get_child_array_key( 'pdf_css', parent::$options['pdf_css']['custom_css'] );
        switch ( $css ) {
            case 'theme_style':
                // $post_styles = $this->_get_post_styles($post->ID);
                // $link = "";
                // foreach ($post_styles as $post_style) {
                // $f = file_get_contents($post_style);
                // if (false !== $f) {
                // $link = $link . "\n" . $f;
                // }

                // }
                // $pdf->CSSselectMedia = 'all';
                // $pdf->WriteHTML($link,1);

                $pdf->WriteHTML( file_get_contents( get_stylesheet_uri() ), 1 );
                break;
            case 'css':
                $pdf->WriteHTML( parent::$options['pdf_css']['css'], 1 );
                break;

        }

        /**
         * Coverart
         */
        $coverart = $this->_get_child_array_key( 'pdf_cover', parent::$options['pdf_cover']['art'] );

        if ( 'none' != $coverart ) {
            // $paper_format = ('custom_paper_format' == $this->_get_child_array_key('pdf_layout',parent::$options['pdf_layout']['paper_format'])) ? parent::$options['pdf_layout']['custom_paper_format'] : parent::$options['pdf_layout']['paper_format'];
            // $dimensions = $pdf->_getPageFormat($paper_format);

            // $w = floor($dimensions[0] / _MPDFK);
            // $h = floor($dimensions[1] / _MPDFK);

            switch ( $coverart ) {

                case 'feature_image':
                    $image_url = wp_get_attachment_url( get_post_thumbnail_id( $post->ID, 'thumbnail' ) );
                    // $image_data = wp_get_attachment_metadata(get_post_thumbnail_id($post->ID, 'thumbnail'));
                    // $left = ($w / 2) - ($image_data['width']  / 2);
                    // $top  = ($h / 2) - ($image_data['height'] / 2);
                    // $pdf->AddPage('','','','','on');
                    if ( '' != $image_url ) {
                        $pdf->AddPageByArray(
                            array(
                                'suppress' => 'on', // supress header
                            )
                        );
                        $pdf->WriteHTML(
                            sprintf(
                                '
                                <div style="position: absolute; left:0; right: 0; top: 0; bottom: 0;">
                                    <img src="%s" style="width: 210mm; height: 297mm; margin: 1mm;" />
                                </div>',
                                $image_url
                            )
                        );
                    }
                    break;

                case 'custom_image':
                    $image_url = parent::$options['pdf_cover']['custom_image'];
                    // $image_data = wp_get_attachment_metadata(get_post_thumbnail_id($post->ID, 'thumbnail'));
                    // $left = ($w / 2) - ($image_data['width']  / 2);
                    // $top  = ($h / 2) - ($image_data['height'] / 2);
                    // $pdf->AddPage('','','','','on');
                    if ( '' != $image_url ) {
                        $pdf->AddPageByArray(
                            array(
                                'suppress' => 'on', // supress header
                            )
                        );
                        $pdf->WriteHTML(
                            sprintf(
                                '<div style="position: absolute; left:0; right: 0; top: 0; bottom: 0;">
                            <img src="%s" style="width: 210mm; height: 297mm; margin: 30;" /></div>',
                                $image_url
                            )
                        );
                    }
                    break;
            }
            // we don't want watermarks on the cover page

            $pdf->showWatermarkImage = false; // @codingStandardsIgnoreLine
            $pdf->showWatermarkText  = false; // @codingStandardsIgnoreLine
        }

        $toc = $this->_get_child_array_key( 'pdf_layout', parent::$options['pdf_layout']['add_toc'] );
        $pdf->AddPageByArray(
            array(
                'suppress'     => 'off', // don't supress headers
                'ohname'       => ( '0' != $header ) ? ( 'custom_header' == $header ) ? 'html_pdfheader' : 'pdfheader' : '',
                'ehname'       => ( '0' != $header ) ? ( 'custom_header' == $header ) ? 'html_pdfheader' : 'pdfheader' : '',
                'ofname'       => ( '0' != $footer ) ? ( 'custom_footer' == $footer ) ? 'html_pdffooter' : 'pdffooter' : '',
                'efname'       => ( '0' != $footer ) ? ( 'custom_footer' == $footer ) ? 'html_pdffooter' : 'pdffooter' : '',
                'ohvalue'      => ( '0' != $header ) ? 1 : 0,
                'ehvalue'      => ( '0' != $header ) ? 1 : 0,
                'ofvalue'      => ( '0' != $footer ) ? 1 : 0,
                'efvalue'      => ( '0' != $footer ) ? 1 : 0,
                'resetpagenum' => ( '0' != $toc ) ? 2 : 1,
            )
        );

        /**
         * Table og contents
         */

        if ( '0' !== $toc ) {
            $toc_start = ( '0' == parent::$options['pdf_layout']['toc'][0] ) ? 1 : parent::$options['pdf_layout']['toc'][0];
            $toc_stop  = ( '0' == parent::$options['pdf_layout']['toc'][1] ) ? 2 : parent::$options['pdf_layout']['toc'][1];
            if ( $toc_start > $toc_stop ) {
                $toc_stop = $toc_start + 1;
            }
            $toc_arr = array();
            $j       = 0;
            for ( $i = $toc_start; $i <= $toc_stop; $i++ ) {
                $toc_arr[ sprintf( 'H%s', $i ) ] = $j++;
            }
            $pdf->h2toc = $toc_arr;
            $pdf->TOCpagebreakByArray(
                array(
                    // 'tocfont' => '',
                    // 'tocfontsize' => '',
                    // 'outdent' => '2em',
                    'TOCusePaging'     => true,
                    'TOCuseLinking'    => true,
                    // 'toc_orientation' => '',
                    // 'toc_mgl' => '',
                    // 'toc_mgr' => '',
                    // 'toc_mgt' => '',
                    // 'toc_mgb' => '',
                    // 'toc_mgh' => '',
                    // 'toc_mgf' => '',
                    // 'toc_ohname' => ('0' != $header ) ? ('custom_header' == $header) ? 'html_pdfheader' : 'pdfheader' : '',
                    // 'toc_ehname' => ('0' != $header ) ? ('custom_header' == $header) ? 'html_pdfheader' : 'pdfheader' : '',
                    // 'toc_ofname' => ('0' != $footer ) ? ('custom_footer' == $footer) ? 'html_pdffooter' : 'pdffooter' : '',
                    // 'toc_efname' => ('0' != $footer ) ? ('custom_footer' == $footer) ? 'html_pdffooter' : 'pdffooter' : '',
                    // 'toc_ohvalue' => ('0' != $header ) ? 1 : 0,
                    // 'toc_ehvalue' => ('0' != $header ) ? 1 : 0,
                    // 'toc_ofvalue' => ('0' != $footer ) ? 1 : 0,
                    // 'toc_efvalue' => ('0' != $footer ) ? 1 : 0,
                    'toc_ohvalue'      => -1,
                    'toc_ehvalue'      => -1,
                    'toc_ofvalue'      => -1,
                    'toc_efvalue'      => -1,
                    'toc_preHTML'      => __( '<h1>Contents</h1>', 'read-offline' ),
                    'toc_postHTML'     => '',
                    'toc_bookmarkText' => __( 'Contents', 'read-offline' ),
                    'resetpagenum'     => 2,
                    'pagenumstyle'     => '',
                    'suppress'         => 'off',
                    'orientation'      => '',
                // 'mgl' => '',
                // 'mgr' => '',
                // 'mgt' => '',
                // 'mgb' => '',
                // 'mgh' => '',
                // 'mgf' => '',
                // 'ohname' => ('0' != $header ) ? ('custom_header' == $header) ? 'html_pdfheader' : 'pdfheader' : '',
                // 'ehname' => ('0' != $header ) ? ('custom_header' == $header) ? 'html_pdfheader' : 'pdfheader' : '',
                // 'ofname' => ('0' != $footer ) ? ('custom_footer' == $footer) ? 'html_pdffooter' : 'pdffooter' : '',
                // 'efname' => ('0' != $footer ) ? ('custom_footer' == $footer) ? 'html_pdffooter' : 'pdffooter' : '',
                // 'ohvalue' => ('0' != $header ) ? 1 : 0,
                // 'ehvalue' => ('0' != $header ) ? 1 : 0,
                // 'ofvalue' => ('0' != $footer ) ? 1 : 0,
                // 'efvalue' => ('0' != $footer ) ? 1 : 0,
                // 'toc_id' => 0,
                // 'pagesel' => '',
                // 'toc_pagesel' => '',
                // 'sheetsize' => '',
                // 'toc_sheetsize' => '',
                )
            );
        }

        // if waters are set, show them
        $pdf->showWatermarkImage = true; // @codingStandardsIgnoreLine
        $pdf->showWatermarkText  = true; // @codingStandardsIgnoreLine

        if ( '1' == parent::$options['pdf_layout']['annotations'] ) {
            $html = $this->_pdf_add_annotations( $html );
        }

        $pdf->WriteHTML( $html );
        $pdf->Output( $post->post_name . '.pdf', 'D' );

    }

    /**
     * Check if URL is valid, code is borrowed form wp_ajax_test_url() (new in 4.6)
     *
     * @author soderlind
     * @version 0.6.3
     * @param   string $url URL to test
     * @return  boolean   result, false if URL is 404
     */
    function _url_exists( $url ) {


        if ( '' === $url ) {
            return false;
        }

        $href = esc_url_raw( $url );

        // Relative URL
        if ( strpos( $href, '//' ) !== 0 && in_array( substr( $href, 0, 1 ) , array( '/', '#', '?' ), true ) ) {
                $href = get_bloginfo( 'url' ) . $href;
        }

        $response              = wp_remote_head( $href, array( 'timeout' => 5 ) );
        $accepted_status_codes = array( 200, 301, 302 );
        if ( ! is_wp_error( $response ) && in_array( wp_remote_retrieve_response_code( $response ), $accepted_status_codes, true ) ) {
            return true;
        }

        return false;

    }

    private function _strip_img( $html ) {
        $doc = new DOMDocument();
        // START LibXML error management.
        // Modify state
        $libxml_previous_state = libxml_use_internal_errors( true );
        $doc->loadHTML( mb_convert_encoding( $html, 'HTML-ENTITIES', 'UTF-8' ) );
        // handle errors
        libxml_clear_errors();
        // restore
        libxml_use_internal_errors( $libxml_previous_state );
        // END LibXML error management.

        $doc->preserveWhiteSpace = false; // @codingStandardsIgnoreLine
        // Here we strip all the img tags in the document
        $images = $doc->getElementsByTagName( 'img' );
        $imgs   = array();
        foreach ( $images as $img ) {
            $imgs[] = $img;
        }
        foreach ( $imgs as $img ) {
            $img->parentNode->removeChild( $img ); // @codingStandardsIgnoreLine
        }
        return $doc->saveHTML();
    }

    private function _pdf_add_annotations( $content ) {

        $anchors = array();
        $doc     = new DOMDocument();
        // START LibXML error management.
        // Modify state
        $libxml_previous_state = libxml_use_internal_errors( true );
        $doc->loadHTML( mb_convert_encoding( $content, 'HTML-ENTITIES', 'UTF-8' ) );
        // handle errors
        libxml_clear_errors();
        // restore
        libxml_use_internal_errors( $libxml_previous_state );
        // END LibXML error management.

        $sups     = $doc->getElementsByTagName( 'sup' );
        $tmp_sups = array();
        $tmp_li   = array();
        foreach ( $sups as $sup ) {
            // <sup><a id="footnote-ref-884344386868178-4" href="#footnote-884344386868178-4">[4]</a></sup>
            $node = $sup->firstChild;  // @codingStandardsIgnoreLine
            if ( XML_ELEMENT_NODE == $node->nodeType && $node->hasAttribute( 'href' ) ) {

                if ( false !== ( $ref = $node->getAttribute( 'href' ) ) && false !== stristr( $ref, 'note' ) ) {
                    $tmp_sups[] = $sup;
                    // find <li id="footnote-884344386868178-2" ..>
                    $li       = $doc->getElementById( substr( $ref, 1 ) ); // substr removes leading #
                    $tmp_li[] = $li;
                    $slug = $tmpslug = str_replace( '↑','', htmlspecialchars( wp_strip_all_tags( $li->nodeValue ), ENT_QUOTES ) ); // @codingStandardsIgnoreLine

                    // create annotation https://mpdf.github.io/reference/html-control-tags/annotation.html
                    $annotation = $doc->createElement( 'annotation' );
                    $annotation->setAttribute( 'content', $slug );
                    // $annotation->setAttribute( 'icon', 'Comment' );

                    $sup->parentNode->insertBefore( $annotation, $sup ); // @codingStandardsIgnoreLine
                }
            }
        }

        // remove sup
        foreach ( $tmp_sups as $sup ) {
            $sup->parentNode->removeChild( $sup ); // @codingStandardsIgnoreLine
        }
        // remove foot- / endnote list at the end of doc
        foreach ( $tmp_li as $li ) {
            $li->parentNode->removeChild( $li ); // @codingStandardsIgnoreLine
        }

        return $doc->saveHTML();
    }

    private function _remove_dont_readoffline( $content, $classname = 'not-readoffline' ) {

        $doc = new DOMDocument();
        // START LibXML error management.
        // Modify state
        $libxml_previous_state = libxml_use_internal_errors( true );
        $doc->loadHTML( mb_convert_encoding( $content, 'HTML-ENTITIES', 'UTF-8' ) );
        // handle errors
        libxml_clear_errors();
        // restore
        libxml_use_internal_errors( $libxml_previous_state );
        // END LibXML error management.
        $finder = new DomXPath( $doc );

        $nodes     = $finder->query( "//*[contains(concat(' ', normalize-space(@class), ' '), ' $classname ')]" );
        $tmp_nodes = array();
        foreach ( $nodes as $node ) {
            $tmp_nodes[] = $node;
        }
        foreach ( $tmp_nodes as $node ) {
            $node->parentNode->removeChild( $node ); // @codingStandardsIgnoreLine
        }
        return $doc->saveHTML();
    }

    private function _get_child_array_key( $parent_element, $org ) {
        // $org: #fieldrow-pdf_header_default_header
        if ( false !== strpos( $org, '#fieldrow' ) ) {
            if ( false !== strpos( $org, ',' ) ) {
                $parts = explode( ',', $org );
                $org   = $parts[0];
            }
            return str_replace( '#fieldrow-' . $parent_element . '_', '', $org );
        } else {
            return $org;
        }
    }

    private function _header_footer( $post, $type ) {
        $val = '';
        switch ( $type ) {
            case 'document_title':
                $val = $post->post_title;
                break;
            case 'author':
                $val = get_the_author_meta( 'display_name', $post->post_author );
                break;
            case 'document_url':
                $val = get_permalink( $post->ID );
                break;
            case 'site_url':
                $val = home_url();
                break;
            case 'site_title':
                $val = get_bloginfo( 'name' );
                break;
            case 'page_number':
                $val = '{PAGENO}/{nbpg}';
                break;
            case 'date':
                $val = get_the_date( get_option( 'date_format' ), $post );
                break;
        }
        return $val;
    }

    private function _parse_header_footer( $post, $html, $strip_tages = false ) {
        // {DATE}, {TODAY}, {TITLE}, {AUTHOR}, {DOCURL}, {SITENAME}, {SITEURL}
        if ( false !== $strip_tages ) {
            $html = addslashes( strip_tags( $html ) );
        }

        $html = str_replace( '{DATE}', get_the_date( get_option( 'date_format' ), $post ), $html );
        $html = str_replace( '{TODAY}', sprintf( '{DATE %s}', get_option( 'date_format' ) ), $html );
        $html = str_replace( '{TITLE}', $post->post_title, $html );
        $html = str_replace( '{AUTHOR}', get_the_author_meta( 'display_name', $post->post_author ), $html );
        $html = str_replace( '{DOCURL}', get_permalink( $post->ID ), $html );
        $html = str_replace( '{SITENAME}', get_bloginfo( 'name' ), $html );
        $html = str_replace( '{SITEURL}', home_url(), $html );
        return $html;
    }


    // get taxonomies terms links
    private function _get_taxonomies_terms( $post ) {
        // get post type by post
        $post_type = $post->post_type;

        // get post type taxonomies
        $taxonomies = get_object_taxonomies( $post_type, 'objects' );

        $out = array();
        foreach ( $taxonomies as $taxonomy_slug => $taxonomy ) {
            // get the terms related to post
            $terms = get_the_terms( $post->ID, $taxonomy_slug );
            if ( ! empty( $terms ) ) {
                foreach ( $terms as $term ) {
                    $out[] = $term->name;
                }
            }
        }

        return ( count( $out ) ) ? implode( ', ', $out ) : '';
    }

    // from https://philipnewcomer.net/2012/11/get-the-attachment-id-from-an-image-url-in-wordpress/
    private function _get_attachment_id_from_url( $attachment_url = '' ) {
        global $wpdb;
        $attachment_id = false;
        // If there is no url, return.
        if ( '' == $attachment_url ) {
            return; }
        // Get the upload directory paths
        $upload_dir_paths = wp_upload_dir();
        // Make sure the upload path base directory exists in the attachment URL, to verify that we're working with a media library image
        if ( false !== strpos( $attachment_url, $upload_dir_paths['baseurl'] ) ) {
            // If this is the URL of an auto-generated thumbnail, get the URL of the original image
            $attachment_url = preg_replace( '/-\d+x\d+(?=\.(jpg|jpeg|png|gif)$)/i', '', $attachment_url );
            // Remove the upload path base directory from the attachment URL
            $attachment_url = str_replace( $upload_dir_paths['baseurl'] . '/', '', $attachment_url );
            // Finally, run a custom database query to get the attachment ID from the modified attachment URL
            $attachment_id = $wpdb->get_var( $wpdb->prepare( "SELECT wposts.ID FROM $wpdb->posts wposts, $wpdb->postmeta wpostmeta WHERE wposts.ID = wpostmeta.post_id AND wpostmeta.meta_key = '_wp_attached_file' AND wpostmeta.meta_value = '%s' AND wposts.post_type = 'attachment'", $attachment_url ) );
        }
        return $attachment_id;
    }

    private function _get_post_styles( $post_id ) {
        $transient_id = 'read_offline_post_styles_' . $post_id;
        $transient    = get_transient( $transient_id );
        return get_transient( $transient_id );
    }

    /**
     * Split html on header tag (h1-h6)
     *
     * @author soderlind
     * @version 0.6.4
     * @param   string $html   HTML content
     * @param   string $header 1-6 or 'all'
     * @return  array
     */
    private function _split_content( $html, $header ) {

        $all_tags   = ( 'all' === $header );
        $content    = array();
        $title      = '';
        $num_title  = -1;
        $have_title = 'end';
        $level      = 0;
        $html_array = wp_html_split( $html );

        foreach ( $html_array as $value ) {
            if ( '' !== $value ) {
                switch ( strtolower( $value ) ) {
                    case '<h' . trim( $header ) . '>':
                    case ( $all_tags && ( preg_match( '/<h(\d).*?>/i', $value, $matches ) ? $value : ! $value ) ):
                        $have_title = 'start';
                        $level      = ( $all_tags && isset( $matches ) ) ? $matches[1] : $header;
                        $title      = '';
                        break;
                    case '</h' . trim( $header ) . '>':
                    case ( $all_tags && ( preg_match( '/<(\/h\d*)>/i', $value ) ? $value : ! $value ) ):
                        $have_title = 'end';
                        break;
                    default:
                        if ( 'start' === $have_title ) {
                            $num_title++;
                            $title .= trim( wp_strip_all_tags( $value ) );
                        }
                        if ( 'end' === $have_title ) {
                            if ( ! isset( $content[ $num_title ] ) ) {
                                $content[ $num_title ] = array(
                                    'title'   => $title,
                                    'level'   => $level,
                                    'content' => '',
                                );
                            }
                            $content[ $num_title ]['content'] .= $value;
                        }
                        break;
                }
            }
        }
        return $content;
    }


    function _get_first_imageurl( $content ) {

        $doc = new DOMDocument();
        // START LibXML error management.
        // Modify state
        $libxml_previous_state = libxml_use_internal_errors( true );
        $doc->loadHTML( mb_convert_encoding( $content, 'HTML-ENTITIES', 'UTF-8' ) );
        // handle errors
        libxml_clear_errors();
        // restore
        libxml_use_internal_errors( $libxml_previous_state );
        // END LibXML error management.
        $tags = $doc->getElementsByTagName( 'img' );

        foreach ( $tags as $tag ) {
            $url = $tag->getAttribute( 'src' );
            // @codingStandardsIgnoreStart
            // printf( '<pre>%s</pre>', print_r( $url, true ) );
            // @codingStandardsIgnoreEnd
            // if ( file_exists( $url ) ) {
                return $url;
            // }
        }
        return false;
    }

    function _image_create_from_url( $url ) {
        $info = pathinfo( $url );
        switch ( $info['extension'] ) {
            case 'jpeg':
            case 'jpg':
                return imagecreatefromjpeg( $url );
            break;

            case 'png':
                return imagecreatefrompng( $url );
            break;

            case 'gif':
                return imagecreatefromgif( $url );
            break;

            // default:
            // throw new InvalidArgumentException('File "'.$filename.'" is not valid jpg, png or gif image.');
            // break;
        }
    }
}

/**
 *
 */
class Read_Offline_MobiFile extends MobiFile {
    private function addTOC( $str, $entries ) {
        $this->resolveFilepos( $str, self::TOC_LINK );
        $str->append( '<h2>' . __( 'Contentssss', 'read-offline' ) . '</h2>' );
        $str->append( '<blockquote><table summary="' . __( 'Table of Contents', 'read-offline' ) . '"><col/><tbody>' );
        for ( $i = 0, $len = sizeof( $entries ); $i < $len; $i++ ) {
            $entry = $entries[ $i ];

            $str->append( '<tr><td><a href="#' . $entry['id'] . '" filepos=' );
            $this->addFilepos( $str, $entry['id'] );
            $str->append( '>' . $entry['title'] . '</a></td></tr>' );
        }
        $str->append( '</tbody></b></table></blockquote><mbp:pagebreak/>' );
    }
}