/* * 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; }