diff options
Diffstat (limited to 'skia/images/SkImageDecoder_fpdfemb.cpp')
-rw-r--r-- | skia/images/SkImageDecoder_fpdfemb.cpp | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/skia/images/SkImageDecoder_fpdfemb.cpp b/skia/images/SkImageDecoder_fpdfemb.cpp new file mode 100644 index 0000000..7f37e3d --- /dev/null +++ b/skia/images/SkImageDecoder_fpdfemb.cpp @@ -0,0 +1,236 @@ +/* + * Copyright 2007, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "SkImageDecoder.h" +#include "SkScaledBitmapSampler.h" +#include "SkStream.h" +#include "SkColorPriv.h" +#include "SkTDArray.h" + +#include "fpdfemb.h" + +class SkFPDFEMBImageDecoder : public SkImageDecoder { +public: + SkFPDFEMBImageDecoder() {} + + virtual Format getFormat() const { + return kBMP_Format; + } + +protected: + virtual bool onDecode(SkStream* stream, SkBitmap* bm, + SkBitmap::Config pref, Mode mode); + +private: + bool render(FPDFEMB_PAGE page, const FPDFEMB_RECT& bounds, SkBitmap* bm, + SkBitmap::Config prefConfig, SkImageDecoder::Mode mode); +}; + +SkImageDecoder* SkImageDecoder_FPDFEMB_Factory(SkStream*); +SkImageDecoder* SkImageDecoder_FPDFEMB_Factory(SkStream* stream) { + static const char kPDFSig[] = { '%', 'P', 'D', 'F' }; + + size_t len = stream->getLength(); + char buffer[sizeof(kPDFSig)]; + + SkDebugf("---- SkImageDecoder_FPDFEMB_Factory len=%d\n", len); + + if (len != 12683) { return NULL; } + + if (len > sizeof(kPDFSig) && + stream->read(buffer, sizeof(kPDFSig)) == sizeof(kPDFSig) && + !memcmp(buffer, kPDFSig, sizeof(kPDFSig))) { + return SkNEW(SkFPDFEMBImageDecoder); + } + return NULL; +} + +/////////////////////////////////////////////////////////////////////////////// + +extern "C" { + static void* pdf_alloc(FPDFEMB_MEMMGR* pMgr, unsigned int size) { + void* addr = sk_malloc_throw(size); + // SkDebugf("---- pdf_alloc %d %p\n", size, addr); + return addr; + } + + static void* pdf_alloc_nl(FPDFEMB_MEMMGR* pMgr, unsigned int size) { + void* addr = sk_malloc_flags(size, 0); + // SkDebugf("---- pdf_alloc_nl %d %p\n", size, addr); + return addr; + } + + static void* pdf_realloc(FPDFEMB_MEMMGR*, void* addr, unsigned int size) { + void* newaddr = sk_realloc_throw(addr, size); + // SkDebugf("---- pdf_realloc %p %d %p\n", addr, size, newaddr); + return newaddr; + } + + static void pdf_free(FPDFEMB_MEMMGR* pMgr, void* pointer) { + // SkDebugf("---- pdf_free %p\n", pointer); + sk_free(pointer); + } + + void FX_OUTPUT_LOG_FUNC(const char* format, ...) { + SkDebugf("---- LOG_FUNC %s\n", format); + } + + static unsigned int file_getsize(FPDFEMB_FILE_ACCESS* file) { + SkStream* stream = (SkStream*)file->user; + return stream->getLength(); + } + + static FPDFEMB_RESULT file_readblock(FPDFEMB_FILE_ACCESS* file, void* dst, + unsigned int offset, unsigned int size) { + SkStream* stream = (SkStream*)file->user; +// SkDebugf("---- readblock %p %p %d %d\n", stream, dst, offset, size); + if (!stream->rewind()) { + SkDebugf("---- rewind failed\n"); + return FPDFERR_ERROR; + } + if (stream->skip(offset) != offset) { + SkDebugf("---- skip failed\n"); + return FPDFERR_ERROR; + } + if (stream->read(dst, size) != size) { + SkDebugf("---- read failed\n"); + return FPDFERR_ERROR; + } + return FPDFERR_SUCCESS; + } + + static void pdf_oom_handler(void* memory, int size) { + SkDebugf("======== pdf OOM %p %d\n", memory, size); + } +} + +static inline int PDF2Pixels(int x) { return x / 100; } +static inline SkScalar PDF2Scalar(int x) { + return SkScalarMulDiv(SK_Scalar1, x, 100); +} + +bool SkFPDFEMBImageDecoder::render(FPDFEMB_PAGE page, const FPDFEMB_RECT& bounds, SkBitmap* bm, + SkBitmap::Config prefConfig, SkImageDecoder::Mode mode) { + int width = PDF2Pixels(bounds.right - bounds.left); + int height = PDF2Pixels(bounds.top - bounds.bottom); + + SkDebugf("----- bitmap size [%d %d], mode=%d\n", width, height, mode); + bm->setConfig(SkBitmap::kARGB_8888_Config, width, height); + if (SkImageDecoder::kDecodeBounds_Mode == mode) { + return true; + } + + // USE THE CODEC TO ALLOCATE THE PIXELS!!!! + if (!this->allocPixelRef(bm, NULL)) { + SkDebugf("----- failed to alloc pixels\n"); + return false; + } + + bm->eraseColor(0); + + FPDFEMB_RESULT result; + FPDFEMB_BITMAP dib; + + result = FPDFEMB_CreateDIB(width, height, FPDFDIB_BGRA, bm->getPixels(), + bm->rowBytes(), &dib); + SkDebugf("---- createdib %d\n", result); + + result = FPDFEMB_StartRender(dib, page, 0, 0, width, height, 0, 0, NULL, NULL); + SkDebugf("---- render %d\n", result); + + result = FPDFEMB_DestroyDIB(dib); + SkDebugf("---- destroydib %d\n", result); + + SkPMColor* dst = bm->getAddr32(0, 0); + const uint8_t* src = (uint8_t*)dst; + int n = bm->getSize() >> 2; + for (int i = 0; i < n; i++) { + int b = *src++; + int g = *src++; + int r = *src++; + int a = *src++; + *dst++ = SkPackARGB32(a, r, g, b); + } + + return true; +} + +#define USE_FIXED_MEM (4 * 1024 * 1024) + +bool SkFPDFEMBImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, + SkBitmap::Config prefConfig, Mode mode) { + + FPDFEMB_RESULT result; +#ifdef USE_FIXED_MEM + SkAutoMalloc storage(USE_FIXED_MEM); + result = FPDFEMB_InitFixedMemory(storage.get(), USE_FIXED_MEM, + pdf_oom_handler); +#else + FPDFEMB_MEMMGR memmgr; + memmgr.Alloc = pdf_alloc; + memmgr.AllocNL = pdf_alloc_nl; + memmgr.Realloc = pdf_realloc; + memmgr.Free = pdf_free; + + result = FPDFEMB_Init(&memmgr); +#endif + SkDebugf("----- SkImageDecoder_FPDFEMB_Factory init %d, streamLen = %d\n", result, stream->getLength()); + + FPDFEMB_FILE_ACCESS file; + file.GetSize = file_getsize; + file.ReadBlock = file_readblock; + file.user = stream; + + FPDFEMB_DOCUMENT document; + result = FPDFEMB_StartLoadDocument(&file, NULL, &document, NULL); + SkDebugf("----- SkImageDecoder_FPDFEMB_Factory open %d %p\n", result, document); + + int pageCount = FPDFEMB_GetPageCount(document); + SkDebugf("----- SkImageDecoder_FPDFEMB_Factory pageCount %d\n", pageCount); + + if (pageCount > 0) { + FPDFEMB_PAGE page; + result = FPDFEMB_LoadPage(document, 0, &page); + SkDebugf("----- SkImageDecoder_FPDFEMB_Factory load page %d\n", result); + + int width, height; + result = FPDFEMB_GetPageSize(page, &width, &height); + SkDebugf("----- SkImageDecoder_FPDFEMB_Factory page size %d [%d %d]\n", result, width, height); + + FPDFEMB_RECT rect; + result = FPDFEMB_GetPageBBox(page, &rect); + SkDebugf("----- SkImageDecoder_FPDFEMB_Factory page rect %d [%d %d %d %d]\n", result, + rect.left, rect.top, rect.right, rect.bottom); + + SkDebugf("----- SkImageDecoder_FPDFEMB_Factory begin page parse...\n"); + result = FPDFEMB_StartParse(page, false, NULL); + SkDebugf("----- SkImageDecoder_FPDFEMB_Factory page parse %d\n", result); + + if (0 == result) { + this->render(page, rect, bm, prefConfig, mode); + } + + result = FPDFEMB_ClosePage(page); + SkDebugf("----- SkImageDecoder_FPDFEMB_Factory close page %d\n", result); + } + + result = FPDFEMB_CloseDocument(document); + SkDebugf("----- SkImageDecoder_FPDFEMB_Factory close %d\n", result); + + // FPDFEMB_Exit(); + + return true; +} |