diff options
-rw-r--r-- | include/config/SkUserConfig.h | 6 | ||||
-rw-r--r-- | include/core/SkFlate.h | 48 | ||||
-rw-r--r-- | include/pdf/SkPDFStream.h | 7 | ||||
-rw-r--r-- | src/core/SkFlate.cpp | 129 | ||||
-rw-r--r-- | src/core/core_files.mk | 1 | ||||
-rw-r--r-- | src/pdf/SkPDFStream.cpp | 24 |
6 files changed, 209 insertions, 6 deletions
diff --git a/include/config/SkUserConfig.h b/include/config/SkUserConfig.h index 8f63ce45a7..a2df7456e3 100644 --- a/include/config/SkUserConfig.h +++ b/include/config/SkUserConfig.h @@ -117,6 +117,12 @@ */ //#define SK_SUPPORT_LCDTEXT +/* If zlib is available and you want to support the flate compression + algorithm (used in PDF generation), define SK_ZLIB_INCLUDE to be the + include path. + */ +//#define SK_ZLIB_INCLUDE <zlib.h> + /* If SK_DEBUG is defined, then you can optionally define SK_SUPPORT_UNITTEST which will run additional self-tests at startup. These can take a long time, so this flag is optional. diff --git a/include/core/SkFlate.h b/include/core/SkFlate.h new file mode 100644 index 0000000000..c496b6fc97 --- /dev/null +++ b/include/core/SkFlate.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2010 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. + */ + +#ifndef SkFlate_DEFINED +#define SkFlate_DEFINED + +#include "SkTypes.h" + +class SkDynamicMemoryWStream; +class SkStream; + +/** \class SkFlate + A class to provide access to the flate compression algorithm. +*/ +class SkFlate { +public: + /** Indicates if the flate algorithm is available. + */ + static bool HaveFlate(); + + /** Use the flate compression algorithm to compress the data in src, + putting the result into dst. Returns false if an error occurs. + */ + static bool Deflate(SkStream* src, SkDynamicMemoryWStream* dst); + + /** Use the flate compression algorithm to decompress the data in src, + putting the result into dst. Returns false if an error occurs. + */ + static bool Inflate(SkStream* src, SkDynamicMemoryWStream* dst); + +private: + static const size_t kBufferSize; +}; + +#endif diff --git a/include/pdf/SkPDFStream.h b/include/pdf/SkPDFStream.h index 24a96422be..10a40b6f98 100644 --- a/include/pdf/SkPDFStream.h +++ b/include/pdf/SkPDFStream.h @@ -19,9 +19,9 @@ #include "SkPDFTypes.h" #include "SkRefCnt.h" +#include "SkStream.h" #include "SkTemplates.h" -class SkStream; class SkPDFCatalog; /** \class SkPDFStream @@ -57,7 +57,10 @@ public: private: SkPDFDict fDict; - SkRefPtr<SkStream> fData; + size_t fLength; + // Only one of the two streams will be valid. + SkRefPtr<SkStream> fPlainData; + SkDynamicMemoryWStream fCompressedData; }; #endif diff --git a/src/core/SkFlate.cpp b/src/core/SkFlate.cpp new file mode 100644 index 0000000000..a9adece75e --- /dev/null +++ b/src/core/SkFlate.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2010 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 "SkFlate.h" +#include "SkStream.h" + +#ifndef SK_ZLIB_INCLUDE +bool SkFlate::HaveFlate() { return false; } +bool SkFlate::Deflate(SkStream*, SkDynamicMemoryWStream*) { return false; } +bool SkFlate::Inflate(SkStream*, SkDynamicMemoryWStream*) { return false; } +#else + +// static +const size_t SkFlate::kBufferSize = 1024; + +// static +bool SkFlate::HaveFlate() { + return true; +} + +namespace { + +#include SK_ZLIB_INCLUDE + +bool doFlate(bool compress, const size_t kBufferSize, SkStream* src, + SkDynamicMemoryWStream* dst) { + uint8_t inputBuffer[kBufferSize]; + uint8_t outputBuffer[kBufferSize]; + z_stream flateData; + flateData.zalloc = NULL; + flateData.zfree = NULL; + flateData.next_in = NULL; + flateData.avail_in = 0; + flateData.next_out = outputBuffer; + flateData.avail_out = kBufferSize; + int rc; + if (compress) + rc = deflateInit(&flateData, Z_DEFAULT_COMPRESSION); + else + rc = inflateInit(&flateData); + if (rc != Z_OK) + return false; + + uint8_t* input = (uint8_t*)src->getMemoryBase(); + size_t inputLength = src->getLength(); + if (input == NULL || inputLength < 0) { + input = NULL; + flateData.next_in = inputBuffer; + flateData.avail_in = 0; + } else { + flateData.next_in = input; + flateData.avail_in = inputLength; + } + + rc = Z_OK; + while (true) { + if (flateData.avail_out < kBufferSize) { + if (!dst->write(outputBuffer, kBufferSize - flateData.avail_out)) { + rc = Z_BUF_ERROR; + break; + } + flateData.next_out = outputBuffer; + flateData.avail_out = kBufferSize; + } + if (flateData.avail_in == 0) { + if (input != NULL) + break; + size_t read = src->read(&inputBuffer, kBufferSize); + if (read == 0) + break; + flateData.next_in = inputBuffer; + flateData.avail_in = read; + } + if (compress) + rc = deflate(&flateData, Z_NO_FLUSH); + else + rc = inflate(&flateData, Z_NO_FLUSH); + if (rc != Z_OK) + break; + } + while (rc == Z_OK) { + if (compress) + rc = deflate(&flateData, Z_FINISH); + else + rc = inflate(&flateData, Z_FINISH); + if (flateData.avail_out > 0) { + if (!dst->write(outputBuffer, kBufferSize - flateData.avail_out)) + return false; + flateData.next_out = outputBuffer; + flateData.avail_out = kBufferSize; + } + } + + if (compress) + deflateEnd(&flateData); + else + inflateEnd(&flateData); + if (rc == Z_STREAM_END) + return true; + return false; +} + +} + +// static +bool SkFlate::Deflate(SkStream* src, SkDynamicMemoryWStream* dst) { + return doFlate(true, kBufferSize, src, dst); +} + +// static +bool SkFlate::Inflate(SkStream* src, SkDynamicMemoryWStream* dst) { + return doFlate(false, kBufferSize, src, dst); +} + +#endif + diff --git a/src/core/core_files.mk b/src/core/core_files.mk index e84365a7cb..af7b876859 100644 --- a/src/core/core_files.mk +++ b/src/core/core_files.mk @@ -37,6 +37,7 @@ SOURCE := \ SkEdgeBuilder.cpp \ SkEdgeClipper.cpp \ SkFilterProc.cpp \ + SkFlate.cpp \ SkFlattenable.cpp \ SkFloat.cpp \ SkFloatBits.cpp \ diff --git a/src/pdf/SkPDFStream.cpp b/src/pdf/SkPDFStream.cpp index 8be4f118ec..6947ae4df9 100644 --- a/src/pdf/SkPDFStream.cpp +++ b/src/pdf/SkPDFStream.cpp @@ -14,12 +14,25 @@ * limitations under the License. */ +#include "SkFlate.h" #include "SkPDFCatalog.h" #include "SkPDFStream.h" #include "SkStream.h" -SkPDFStream::SkPDFStream(SkStream* stream) : fData(stream) { - SkRefPtr<SkPDFInt> lenValue = new SkPDFInt(fData->read(NULL, 0)); +SkPDFStream::SkPDFStream(SkStream* stream) { + if (SkFlate::HaveFlate()) { + SkAssertResult(SkFlate::Deflate(stream, &fCompressedData)); + fLength = fCompressedData.getOffset(); + + SkRefPtr<SkPDFName> flateFilter = new SkPDFName("FlateDecode"); + flateFilter->unref(); // SkRefPtr and new both took a reference. + fDict.insert("Filter", flateFilter.get()); + } else { + fPlainData = stream; + fLength = fPlainData->getLength(); + } + + SkRefPtr<SkPDFInt> lenValue = new SkPDFInt(fLength); lenValue->unref(); // SkRefPtr and new both took a reference. fDict.insert("Length", lenValue.get()); } @@ -34,7 +47,10 @@ void SkPDFStream::emitObject(SkWStream* stream, SkPDFCatalog* catalog, fDict.emitObject(stream, catalog, false); stream->writeText(" stream\n"); - stream->write(fData->getMemoryBase(), fData->read(NULL, 0)); + if (fPlainData.get()) + stream->write(fPlainData->getMemoryBase(), fLength); + else + stream->write(fCompressedData.getStream(), fLength); stream->writeText("\nendstream"); } @@ -43,7 +59,7 @@ size_t SkPDFStream::getOutputSize(SkPDFCatalog* catalog, bool indirect) { return getIndirectOutputSize(catalog); return fDict.getOutputSize(catalog, false) + - strlen(" stream\n\nendstream") + fData->read(NULL, 0); + strlen(" stream\n\nendstream") + fLength; } void SkPDFStream::insert(SkPDFName* key, SkPDFObject* value) { |