From cd7c0f3c45c8cefbd8b97e104dd9e857a756a6ac Mon Sep 17 00:00:00 2001 From: Nikolay Pultsin Date: Sun, 25 Mar 2012 16:35:13 +0100 Subject: [PATCH] images support in native code (in progress) --- jni/Application.mk | 4 +- .../fbreader/src/bookmodel/BookReader.cpp | 6 +- .../fbreader/src/bookmodel/BookReader.h | 2 +- .../src/formats/rtf/RtfBookReader.cpp | 2 +- .../text/src/model/ZLCachedMemoryAllocator.h | 25 +++++-- .../text/src/model/ZLImageMapWriter.cpp | 69 ++++--------------- .../zlibrary/text/src/model/ZLTextModel.cpp | 5 +- .../zlibrary/text/src/model/ZLTextModel.h | 2 +- .../fbreader/image/ImageViewActivity.java | 12 ++-- .../fbreader/formats/NativeFormatPlugin.java | 2 + .../formats/pdb/MobipocketHtmlBookReader.java | 2 +- .../formats/pdb/MobipocketPlugin.java | 2 +- .../core/image/ZLBase64EncodedImage.java | 2 +- .../zlibrary/core/image/ZLFileImage.java | 27 +++++++- .../zlibrary/core/image/ZLSingleImage.java | 6 -- .../zlibrary/text/model/ZLImageMapReader.java | 52 ++++++-------- 16 files changed, 99 insertions(+), 121 deletions(-) diff --git a/jni/Application.mk b/jni/Application.mk index 1ad5914aa..fe55d31c4 100644 --- a/jni/Application.mk +++ b/jni/Application.mk @@ -1,4 +1,4 @@ -#APP_ABI := armeabi +APP_ABI := armeabi #APP_ABI := armeabi armeabi-v7a x86 mips mips-r2 mips-r2-sf -APP_ABI := all +#APP_ABI := all APP_STL := stlport_static diff --git a/jni/NativeFormats/fbreader/src/bookmodel/BookReader.cpp b/jni/NativeFormats/fbreader/src/bookmodel/BookReader.cpp index 7e8ffa273..a21d87a24 100644 --- a/jni/NativeFormats/fbreader/src/bookmodel/BookReader.cpp +++ b/jni/NativeFormats/fbreader/src/bookmodel/BookReader.cpp @@ -214,16 +214,16 @@ void BookReader::insertEndOfTextParagraph() { insertEndParagraph(ZLTextParagraph::END_OF_TEXT_PARAGRAPH); } -void BookReader::addImageReference(const std::string &id, short vOffset) { +void BookReader::addImageReference(const std::string &id, short vOffset, bool isCover) { if (myCurrentTextModel != 0) { mySectionContainsRegularContents = true; if (myTextParagraphExists) { flushTextBufferToParagraph(); - myCurrentTextModel->addImage(id, vOffset); + myCurrentTextModel->addImage(id, vOffset, isCover); } else { beginParagraph(); myCurrentTextModel->addControl(IMAGE, true); - myCurrentTextModel->addImage(id, vOffset); + myCurrentTextModel->addImage(id, vOffset, isCover); myCurrentTextModel->addControl(IMAGE, false); endParagraph(); } diff --git a/jni/NativeFormats/fbreader/src/bookmodel/BookReader.h b/jni/NativeFormats/fbreader/src/bookmodel/BookReader.h index 03c477215..2142cd953 100644 --- a/jni/NativeFormats/fbreader/src/bookmodel/BookReader.h +++ b/jni/NativeFormats/fbreader/src/bookmodel/BookReader.h @@ -60,7 +60,7 @@ public: void addHyperlinkLabel(const std::string &label, int paragraphNumber); void addFixedHSpace(unsigned char length); - void addImageReference(const std::string &id, short vOffset = 0); + void addImageReference(const std::string &id, short vOffset, bool isCover); void addImage(const std::string &id, shared_ptr image); void beginContentsParagraph(int referenceNumber = -1); diff --git a/jni/NativeFormats/fbreader/src/formats/rtf/RtfBookReader.cpp b/jni/NativeFormats/fbreader/src/formats/rtf/RtfBookReader.cpp index d1dc6a30e..047511796 100644 --- a/jni/NativeFormats/fbreader/src/formats/rtf/RtfBookReader.cpp +++ b/jni/NativeFormats/fbreader/src/formats/rtf/RtfBookReader.cpp @@ -120,7 +120,7 @@ void RtfBookReader::switchDestination(DestinationType destination, bool on) { void RtfBookReader::insertImage(const std::string &mimeType, const std::string &fileName, size_t startOffset, size_t size) { std::string id; ZLStringUtil::appendNumber(id, myImageIndex++); - myBookReader.addImageReference(id); + myBookReader.addImageReference(id, 0, false); //myBookReader.addImage(id, new RtfImage(mimeType, fileName, startOffset, size)); } diff --git a/jni/NativeFormats/zlibrary/text/src/model/ZLCachedMemoryAllocator.h b/jni/NativeFormats/zlibrary/text/src/model/ZLCachedMemoryAllocator.h index 54f36cf98..5ac314060 100644 --- a/jni/NativeFormats/zlibrary/text/src/model/ZLCachedMemoryAllocator.h +++ b/jni/NativeFormats/zlibrary/text/src/model/ZLCachedMemoryAllocator.h @@ -22,6 +22,8 @@ #include +#include + class ZLCachedMemoryAllocator { public: @@ -33,8 +35,9 @@ public: void flush(); - static void writeUInt16(char *ptr, uint16_t value); - static void writeUInt32(char *ptr, uint32_t value); + static char *writeUInt16(char *ptr, uint16_t value); + static char *writeUInt32(char *ptr, uint32_t value); + static char *writeString(char *ptr, const ZLUnicodeUtil::Ucs2String &str); static uint16_t readUInt16(const char *ptr); static uint32_t readUInt32(const char *ptr); @@ -69,18 +72,28 @@ inline const std::string &ZLCachedMemoryAllocator::fileExtension() const { retur inline size_t ZLCachedMemoryAllocator::blocksNumber() const { return myPool.size(); } inline size_t ZLCachedMemoryAllocator::currentBytesOffset() const { return myOffset; } -inline void ZLCachedMemoryAllocator::writeUInt16(char *ptr, uint16_t value) { +inline char *ZLCachedMemoryAllocator::writeUInt16(char *ptr, uint16_t value) { *ptr++ = value; - *ptr = value >> 8; + *ptr++ = value >> 8; + return ptr; } -inline void ZLCachedMemoryAllocator::writeUInt32(char *ptr, uint32_t value) { +inline char *ZLCachedMemoryAllocator::writeUInt32(char *ptr, uint32_t value) { *ptr++ = value; value >>= 8; *ptr++ = value; value >>= 8; *ptr++ = value; - *ptr = value >> 8; + value >>= 8; + *ptr++ = value; + return ptr; } +inline char *ZLCachedMemoryAllocator::writeString(char *ptr, const ZLUnicodeUtil::Ucs2String &str) { + const size_t size = str.size(); + writeUInt16(ptr, size); + memcpy(ptr + 2, &str.front(), size * 2); + return ptr + size * 2 + 2; +} + inline uint16_t ZLCachedMemoryAllocator::readUInt16(const char *ptr) { const uint8_t *tmp = (const uint8_t*)ptr; return *tmp + ((uint16_t)*(tmp + 1) << 8); diff --git a/jni/NativeFormats/zlibrary/text/src/model/ZLImageMapWriter.cpp b/jni/NativeFormats/zlibrary/text/src/model/ZLImageMapWriter.cpp index 5b0c3121f..2ffbec3bb 100644 --- a/jni/NativeFormats/zlibrary/text/src/model/ZLImageMapWriter.cpp +++ b/jni/NativeFormats/zlibrary/text/src/model/ZLImageMapWriter.cpp @@ -45,65 +45,26 @@ void ZLImageMapWriter::addImage(const std::string &id, const ZLImage &image) { } void ZLImageMapWriter::addSingleImageEntry(const ZLSingleImage &image) { - ZLUnicodeUtil::Ucs2String ucs2mime; - ZLUnicodeUtil::utf8ToUcs2(ucs2mime, image.mimeType()); - const size_t mimeSize = ucs2mime.size() * 2; + const ZLFileImage &fileImage = (const ZLFileImage&)image; - const size_t len = 4 + mimeSize; - char *address = myAllocator.allocate(len); + ZLUnicodeUtil::Ucs2String mime; + ZLUnicodeUtil::utf8ToUcs2(mime, image.mimeType()); + ZLUnicodeUtil::Ucs2String path; + ZLUnicodeUtil::utf8ToUcs2(path, fileImage.file().path()); + ZLUnicodeUtil::Ucs2String encoding; - char *ptr = address; - *ptr++ = image.kind(); + const size_t len = 16 + mime.size() * 2 + path.size() * 2 + encoding.size() * 2; + char *ptr = myAllocator.allocate(len); + + *ptr++ = 0;//image.kind(); *ptr++ = 0; // multi ? 1 : 0 - ZLCachedMemoryAllocator::writeUInt16(ptr, ucs2mime.size()); - memcpy(ptr + 2, &ucs2mime.front(), mimeSize); - switch (image.kind()) { - case ZLSingleImage::BASE64_ENCODED_IMAGE: - case ZLSingleImage::REGULAR_IMAGE: - { - const shared_ptr data = image.stringData(); - size_t length = data.isNull() ? 0 : data->length(); - size_t dataSize = (length + 1) / 2; + ptr = ZLCachedMemoryAllocator::writeString(ptr, mime); + ptr = ZLCachedMemoryAllocator::writeString(ptr, path); + ptr = ZLCachedMemoryAllocator::writeString(ptr, encoding); - const size_t newlen = len + 4 + dataSize * 2; - address = myAllocator.reallocateLast(address, newlen); - ptr = address + len; - - ZLCachedMemoryAllocator::writeUInt32(ptr, dataSize); - ptr += 4; - if (length > 0) { - memcpy(ptr, data->data(), length); - ptr += length; - if (length % 2) { - *ptr++ = 0; - } - } - break; - } - case ZLSingleImage::FILE_IMAGE: - { - const ZLFileImage &fileImage = (const ZLFileImage&)image; - - ZLUnicodeUtil::Ucs2String ucs2path; - ZLUnicodeUtil::utf8ToUcs2(ucs2path, fileImage.file().path()); - const size_t pathSize = ucs2path.size() * 2; - - const size_t newlen = len + 10 + pathSize; - address = myAllocator.reallocateLast(address, newlen); - ptr = address + len; - - ZLCachedMemoryAllocator::writeUInt32(ptr, fileImage.offset()); - ptr += 4; - ZLCachedMemoryAllocator::writeUInt32(ptr, fileImage.size()); - ptr += 4; - ZLCachedMemoryAllocator::writeUInt16(ptr, ucs2path.size()); - ptr += 2; - memcpy(ptr, &ucs2path.front(), pathSize); - ptr += pathSize; - break; - } - } + ptr = ZLCachedMemoryAllocator::writeUInt32(ptr, fileImage.offset()); + ptr = ZLCachedMemoryAllocator::writeUInt32(ptr, fileImage.size()); } void ZLImageMapWriter::addMultiImageEntry(const ZLMultiImage &image) { diff --git a/jni/NativeFormats/zlibrary/text/src/model/ZLTextModel.cpp b/jni/NativeFormats/zlibrary/text/src/model/ZLTextModel.cpp index fd2299e11..16ade2223 100644 --- a/jni/NativeFormats/zlibrary/text/src/model/ZLTextModel.cpp +++ b/jni/NativeFormats/zlibrary/text/src/model/ZLTextModel.cpp @@ -346,7 +346,7 @@ void ZLTextModel::addHyperlinkControl(ZLTextKind textKind, ZLHyperlinkType hyper ++myParagraphLengths.back(); } -void ZLTextModel::addImage(const std::string &id, short vOffset) { +void ZLTextModel::addImage(const std::string &id, short vOffset, bool isCover) { checkUtf8Text(); ZLUnicodeUtil::Ucs2String ucs2id; @@ -354,12 +354,13 @@ void ZLTextModel::addImage(const std::string &id, short vOffset) { const size_t len = ucs2id.size() * 2; - myLastEntryStart = myAllocator.allocate(len + 6); + myLastEntryStart = myAllocator.allocate(len + 8); *myLastEntryStart = ZLTextParagraphEntry::IMAGE_ENTRY; *(myLastEntryStart + 1) = 0; ZLCachedMemoryAllocator::writeUInt16(myLastEntryStart + 2, vOffset); ZLCachedMemoryAllocator::writeUInt16(myLastEntryStart + 4, ucs2id.size()); memcpy(myLastEntryStart + 6, &ucs2id.front(), len); + ZLCachedMemoryAllocator::writeUInt16(myLastEntryStart + 6 + len, isCover ? 1 : 0); myParagraphs.back()->addEntry(myLastEntryStart); ++myParagraphLengths.back(); } diff --git a/jni/NativeFormats/zlibrary/text/src/model/ZLTextModel.h b/jni/NativeFormats/zlibrary/text/src/model/ZLTextModel.h index 6a290324c..a94753762 100644 --- a/jni/NativeFormats/zlibrary/text/src/model/ZLTextModel.h +++ b/jni/NativeFormats/zlibrary/text/src/model/ZLTextModel.h @@ -75,7 +75,7 @@ public: void addHyperlinkControl(ZLTextKind textKind, ZLHyperlinkType hyperlinkType, const std::string &label); void addText(const std::string &text); void addText(const std::vector &text); - void addImage(const std::string &id, short vOffset); + void addImage(const std::string &id, short vOffset, bool isCover); void addFixedHSpace(unsigned char length); void addBidiReset(); diff --git a/src/org/geometerplus/android/fbreader/image/ImageViewActivity.java b/src/org/geometerplus/android/fbreader/image/ImageViewActivity.java index af9a2eca1..54ece0991 100644 --- a/src/org/geometerplus/android/fbreader/image/ImageViewActivity.java +++ b/src/org/geometerplus/android/fbreader/image/ImageViewActivity.java @@ -68,14 +68,12 @@ public class ImageViewActivity extends Activity { final Uri uri = intent.getData(); if (ZLFileImage.SCHEME.equals(uri.getScheme())) { + final ZLFileImage image = ZLFileImage.byUrlPath(uri.getPath()); + if (image == null) { + // TODO: error message (?) + finish(); + } try { - final String[] data = uri.getPath().split("\000"); - final ZLFileImage image = new ZLFileImage( - MimeType.IMAGE_AUTO, - ZLFile.createFileByPath(data[0]), - Integer.parseInt(data[1]), - Integer.parseInt(data[2]) - ); final ZLImageData imageData = ZLImageManager.Instance().getImageData(image); myBitmap = ((ZLAndroidImageData)imageData).getFullSizeBitmap(); } catch (Exception e) { diff --git a/src/org/geometerplus/fbreader/formats/NativeFormatPlugin.java b/src/org/geometerplus/fbreader/formats/NativeFormatPlugin.java index f4ff8892c..12ed02b5e 100644 --- a/src/org/geometerplus/fbreader/formats/NativeFormatPlugin.java +++ b/src/org/geometerplus/fbreader/formats/NativeFormatPlugin.java @@ -84,9 +84,11 @@ public class NativeFormatPlugin extends FormatPlugin { protected native ZLImage readCoverInternal(ZLFile file); + /* public static ZLImage createImage(String mimeType, String fileName, int offset, int length) { return new ZLFileImage(MimeType.get(mimeType), ZLFile.createFileByPath(fileName), offset, length); } + */ // FIXME: temporary implementation; implement as a native code @Override diff --git a/src/org/geometerplus/fbreader/formats/pdb/MobipocketHtmlBookReader.java b/src/org/geometerplus/fbreader/formats/pdb/MobipocketHtmlBookReader.java index eaf1d7247..220d26da5 100644 --- a/src/org/geometerplus/fbreader/formats/pdb/MobipocketHtmlBookReader.java +++ b/src/org/geometerplus/fbreader/formats/pdb/MobipocketHtmlBookReader.java @@ -182,7 +182,7 @@ public class MobipocketHtmlBookReader extends HtmlReader { if (length <= 0) { break; } - addImage("" + (index + 1), new ZLFileImage(MimeType.IMAGE_AUTO, Model.Book.File, offset, length)); + addImage(String.valueOf(index + 1), new ZLFileImage(MimeType.IMAGE_AUTO, Model.Book.File, ZLFileImage.ENCODING_NONE, offset, length)); } } diff --git a/src/org/geometerplus/fbreader/formats/pdb/MobipocketPlugin.java b/src/org/geometerplus/fbreader/formats/pdb/MobipocketPlugin.java index e219c725f..2450be9a8 100644 --- a/src/org/geometerplus/fbreader/formats/pdb/MobipocketPlugin.java +++ b/src/org/geometerplus/fbreader/formats/pdb/MobipocketPlugin.java @@ -225,7 +225,7 @@ public class MobipocketPlugin extends JavaFormatPlugin { if (start >= 0) { int len = myMobipocketStream.getImageLength(coverIndex); if (len > 0) { - return new ZLFileImage(MimeType.IMAGE_AUTO, file, start, len); + return new ZLFileImage(MimeType.IMAGE_AUTO, file, ZLFileImage.ENCODING_NONE, start, len); } } return null; diff --git a/src/org/geometerplus/zlibrary/core/image/ZLBase64EncodedImage.java b/src/org/geometerplus/zlibrary/core/image/ZLBase64EncodedImage.java index 293aa2e59..5440f9001 100644 --- a/src/org/geometerplus/zlibrary/core/image/ZLBase64EncodedImage.java +++ b/src/org/geometerplus/zlibrary/core/image/ZLBase64EncodedImage.java @@ -61,7 +61,7 @@ public abstract class ZLBase64EncodedImage extends ZLSingleImage { try { decode(); final File file = new File(decodedFileName()); - return ZLFileImage.SCHEME + "://" + decodedFileName() + "\0000\000" + (int)file.length(); + return ZLFileImage.SCHEME + "://" + decodedFileName() + "\000\0000\000" + (int)file.length(); } catch (Exception e) { return null; } diff --git a/src/org/geometerplus/zlibrary/core/image/ZLFileImage.java b/src/org/geometerplus/zlibrary/core/image/ZLFileImage.java index 390cbcb72..091a74591 100644 --- a/src/org/geometerplus/zlibrary/core/image/ZLFileImage.java +++ b/src/org/geometerplus/zlibrary/core/image/ZLFileImage.java @@ -28,23 +28,44 @@ import org.geometerplus.zlibrary.core.util.SliceInputStream; public class ZLFileImage extends ZLSingleImage { public static final String SCHEME = "imagefile"; + public static final String ENCODING_NONE = ""; + public static final String ENCODING_HEX = "hex"; + + public static ZLFileImage byUrlPath(String urlPath) { + try { + final String[] data = urlPath.split("\000"); + return new ZLFileImage( + MimeType.IMAGE_AUTO, + ZLFile.createFileByPath(data[0]), + data[1], + Integer.parseInt(data[2]), + Integer.parseInt(data[3]) + ); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + private final ZLFile myFile; + private final String myEncoding; private final int myOffset; private final int myLength; - public ZLFileImage(MimeType mimeType, ZLFile file, int offset, int length) { + public ZLFileImage(MimeType mimeType, ZLFile file, String encoding, int offset, int length) { super(mimeType); myFile = file; + myEncoding = encoding; myOffset = offset; myLength = length; } public ZLFileImage(MimeType mimeType, ZLFile file) { - this(mimeType, file, 0, (int)file.size()); + this(mimeType, file, ENCODING_NONE, 0, (int)file.size()); } public String getURI() { - return SCHEME + "://" + myFile.getPath() + "\000" + myOffset + "\000" + myLength; + return SCHEME + "://" + myFile.getPath() + "\000" + myEncoding + "\000" + myOffset + "\000" + myLength; } @Override diff --git a/src/org/geometerplus/zlibrary/core/image/ZLSingleImage.java b/src/org/geometerplus/zlibrary/core/image/ZLSingleImage.java index 469756d26..0f1eb1447 100644 --- a/src/org/geometerplus/zlibrary/core/image/ZLSingleImage.java +++ b/src/org/geometerplus/zlibrary/core/image/ZLSingleImage.java @@ -24,12 +24,6 @@ import java.io.InputStream; import org.geometerplus.zlibrary.core.util.MimeType; public abstract class ZLSingleImage implements ZLImage { - public interface Kind { - byte REGULAR_IMAGE = 1; - byte FILE_IMAGE = 2; - byte BASE64_ENCODED_IMAGE = 3; - }; - private final MimeType myMimeType; public ZLSingleImage(final MimeType mimeType) { diff --git a/src/org/geometerplus/zlibrary/text/model/ZLImageMapReader.java b/src/org/geometerplus/zlibrary/text/model/ZLImageMapReader.java index dd6240e82..5b22fd6c1 100644 --- a/src/org/geometerplus/zlibrary/text/model/ZLImageMapReader.java +++ b/src/org/geometerplus/zlibrary/text/model/ZLImageMapReader.java @@ -38,12 +38,11 @@ class ZLImageMapReader { data = myStorage.block(++index); offset = 0; } - final byte kind = (byte)data[offset]; final boolean multi = ((byte)(data[offset] >> 8)) != 0; if (multi) { return readMultiImage(index, offset + 1, data); } else { - return readSingleImage(index, offset + 1, data, kind); + return readSingleImage(index, offset + 1, data); } } @@ -52,37 +51,26 @@ class ZLImageMapReader { return null; } - private ZLImage readSingleImage(int index, int offset, char[] data, byte kind) { - final short mimeLength = (short)data[offset++]; - final String mime = new String(data, offset, mimeLength); - offset += mimeLength; + private ZLImage readSingleImage(int index, int offset, char[] data) { + short len = (short)data[offset++]; + final String mime = new String(data, offset, len); + offset += len; - switch (kind) { - case ZLSingleImage.Kind.BASE64_ENCODED_IMAGE: - case ZLSingleImage.Kind.REGULAR_IMAGE: - { - final int dataSize = (int)data[offset] + (((int)data[offset + 1]) << 16); - offset += 2; - final String path = myStorage.fileName(index); - return new ZLFileImage( - MimeType.get(mime), ZLFile.createFileByPath(path), offset * 2, dataSize * 2 - ); - } - case ZLSingleImage.Kind.FILE_IMAGE: - { - final int fileOffset = (int)data[offset] + (((int)data[offset + 1]) << 16); - offset += 2; - final int fileSize = (int)data[offset] + (((int)data[offset + 1]) << 16); - offset += 2; - final short pathLength = (short)data[offset++]; - final String path = new String(data, offset, pathLength); - offset += pathLength; - return new ZLFileImage( - MimeType.get(mime), ZLFile.createFileByPath(path), fileOffset, fileSize - ); - } - } + len = (short)data[offset++]; + final String path = new String(data, offset, len); + offset += len; - return null; + len = (short)data[offset++]; + final String encoding = new String(data, offset, len); + offset += len; + + final int fileOffset = (int)data[offset] + (((int)data[offset + 1]) << 16); + offset += 2; + final int fileSize = (int)data[offset] + (((int)data[offset + 1]) << 16); + offset += 2; + + return new ZLFileImage( + MimeType.get(mime), ZLFile.createFileByPath(path), encoding, fileOffset, fileSize + ); } }