Exemplo n.º 1
0
Pixels readPDFImage(PoDoFo::PdfObject* object, const PixelType type,
    const ColorSpace colorspace, const PoDoFo::pdf_int64 componentbits,
    const std::string& filename, Form& form)
{
    Pixels pixels;

    if (!object->GetDictionary().HasKey(PoDoFo::PdfName("Width")) ||
        !object->GetDictionary().HasKey(PoDoFo::PdfName("Height")))
        return pixels;

    const unsigned int width  = object->GetDictionary().GetKey(PoDoFo::PdfName("Width"))->GetNumber();
    const unsigned int height = object->GetDictionary().GetKey(PoDoFo::PdfName("Height"))->GetNumber();

    if (type == PixelType::JPG)
    {
        PoDoFo::PdfMemStream* stream = dynamic_cast<PoDoFo::PdfMemStream*>(object->GetStream());
        pixels = Pixels(IL_JPG, stream->Get(), stream->GetLength(), filename);
    }
    else if (type == PixelType::TIF)
    {
        // Monochrome, otherwise wouldn't have used CCITT
        const unsigned int bits = 1;
        const unsigned int samples = 1;

        if (bits != componentbits)
            form.log("BitsPerComponent is not 1 for CCITTFaxDecode image in PDF", LogType::Warning);

        std::ostringstream os;
        TIFF* tif = TIFFStreamOpen("Input", &os);
        TIFFSetField(tif, TIFFTAG_IMAGEWIDTH,       width);
        TIFFSetField(tif, TIFFTAG_IMAGELENGTH,      height);
        TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE,    bits);
        TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL,  samples);
        TIFFSetField(tif, TIFFTAG_FILLORDER,        FILLORDER_MSB2LSB);
        TIFFSetField(tif, TIFFTAG_PLANARCONFIG,     PLANARCONFIG_CONTIG);
        TIFFSetField(tif, TIFFTAG_PHOTOMETRIC,      PHOTOMETRIC_MINISWHITE);
        TIFFSetField(tif, TIFFTAG_XRESOLUTION,      204.0); // From fax2tiff
        TIFFSetField(tif, TIFFTAG_YRESOLUTION,      196.0); // ditto
        TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT,   RESUNIT_INCH);
        TIFFSetField(tif, TIFFTAG_COMPRESSION,      COMPRESSION_CCITTFAX4);
        TIFFSetField(tif, TIFFTAG_ORIENTATION,      ORIENTATION_TOPLEFT);
        TIFFSetField(tif, TIFFTAG_FAXMODE,      FAXMODE_CLASSF);
        TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP,     (uint32)-1L);

        // stream->Get returns read-only, so copy it
        PoDoFo::PdfMemStream* stream = dynamic_cast<PoDoFo::PdfMemStream*>(object->GetStream());
        const char* readonly = stream->Get();
        PoDoFo::pdf_long len = stream->GetLength();
        char* buffer = new char[len];
        std::memcpy(buffer, readonly, len);

        TIFFWriteRawStrip(tif, 0, buffer, len);
        TIFFWriteDirectory(tif);
        TIFFClose(tif);

        delete[] buffer;

        pixels = Pixels(IL_TIF, os.str().c_str(), os.tellp(), filename);
    }
    else
    {
        std::ostringstream os;

        // P4 is bitmap (1 bit), P5 is graymap (8 bit), P6 is pixmap (24 bit or
        // 8-bit/channel). See:
        // http://netpbm.sourceforge.net/doc/pbm.html
        // http://en.wikipedia.org/wiki/Portable_anymap#File_format_description
        if (colorspace == ColorSpace::Gray)
            os << ((componentbits == 1)?"P4\n":"P5\n");
        else
            os << "P6\n";

        os << width  << " "
           << height << "\n";

        if (componentbits != 1)
           os << "255\n";

        std::string s = os.str();

        char* buffer;
        PoDoFo::pdf_long len;

        object->GetStream()->GetFilteredCopy(&buffer, &len);

        // Warn if unknown colorspace
        if (colorspace == ColorSpace::Unknown)
            form.log("unknown color space on PDF image", LogType::Warning);

        // If the buffer isn't the correct size for the image data, don't try
        // reading the image from this invalid data
        if (len != correctLength(width, height, colorspace, componentbits))
        {
            std::ostringstream ss;
            ss << "wrong buffer size for PDF image of size "
               << width << "x" << height
               << " (" << colorspace << "): " << len;
            form.log(ss.str(), LogType::Warning);

            std::free(buffer);
            return pixels;
        }

        std::unique_ptr<char> stream(new char[len+s.size()]);
        std::memcpy(stream.get(), s.c_str(), s.size());
        std::memcpy(stream.get()+s.size(), buffer, len);
        std::free(buffer);

        pixels = Pixels(IL_PNM, stream.get(), len+s.size(), filename);
    }

    return pixels;
}