1
0
Fork 0
mirror of https://github.com/geometer/FBReaderJ.git synced 2025-10-06 03:50:19 +02:00

images support in native code (in progress)

This commit is contained in:
Nikolay Pultsin 2012-03-25 16:35:13 +01:00
parent e33d26bc6c
commit cd7c0f3c45
16 changed files with 99 additions and 121 deletions

View file

@ -1,4 +1,4 @@
#APP_ABI := armeabi APP_ABI := armeabi
#APP_ABI := armeabi armeabi-v7a x86 mips mips-r2 mips-r2-sf #APP_ABI := armeabi armeabi-v7a x86 mips mips-r2 mips-r2-sf
APP_ABI := all #APP_ABI := all
APP_STL := stlport_static APP_STL := stlport_static

View file

@ -214,16 +214,16 @@ void BookReader::insertEndOfTextParagraph() {
insertEndParagraph(ZLTextParagraph::END_OF_TEXT_PARAGRAPH); 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) { if (myCurrentTextModel != 0) {
mySectionContainsRegularContents = true; mySectionContainsRegularContents = true;
if (myTextParagraphExists) { if (myTextParagraphExists) {
flushTextBufferToParagraph(); flushTextBufferToParagraph();
myCurrentTextModel->addImage(id, vOffset); myCurrentTextModel->addImage(id, vOffset, isCover);
} else { } else {
beginParagraph(); beginParagraph();
myCurrentTextModel->addControl(IMAGE, true); myCurrentTextModel->addControl(IMAGE, true);
myCurrentTextModel->addImage(id, vOffset); myCurrentTextModel->addImage(id, vOffset, isCover);
myCurrentTextModel->addControl(IMAGE, false); myCurrentTextModel->addControl(IMAGE, false);
endParagraph(); endParagraph();
} }

View file

@ -60,7 +60,7 @@ public:
void addHyperlinkLabel(const std::string &label, int paragraphNumber); void addHyperlinkLabel(const std::string &label, int paragraphNumber);
void addFixedHSpace(unsigned char length); 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<const ZLImage> image); void addImage(const std::string &id, shared_ptr<const ZLImage> image);
void beginContentsParagraph(int referenceNumber = -1); void beginContentsParagraph(int referenceNumber = -1);

View file

@ -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) { void RtfBookReader::insertImage(const std::string &mimeType, const std::string &fileName, size_t startOffset, size_t size) {
std::string id; std::string id;
ZLStringUtil::appendNumber(id, myImageIndex++); ZLStringUtil::appendNumber(id, myImageIndex++);
myBookReader.addImageReference(id); myBookReader.addImageReference(id, 0, false);
//myBookReader.addImage(id, new RtfImage(mimeType, fileName, startOffset, size)); //myBookReader.addImage(id, new RtfImage(mimeType, fileName, startOffset, size));
} }

View file

@ -22,6 +22,8 @@
#include <vector> #include <vector>
#include <ZLUnicodeUtil.h>
class ZLCachedMemoryAllocator { class ZLCachedMemoryAllocator {
public: public:
@ -33,8 +35,9 @@ public:
void flush(); void flush();
static void writeUInt16(char *ptr, uint16_t value); static char *writeUInt16(char *ptr, uint16_t value);
static void writeUInt32(char *ptr, uint32_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 uint16_t readUInt16(const char *ptr);
static uint32_t readUInt32(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::blocksNumber() const { return myPool.size(); }
inline size_t ZLCachedMemoryAllocator::currentBytesOffset() const { return myOffset; } 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;
*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; *ptr++ = value;
value >>= 8; value >>= 8;
*ptr++ = value; *ptr++ = value;
value >>= 8; value >>= 8;
*ptr++ = value; *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) { inline uint16_t ZLCachedMemoryAllocator::readUInt16(const char *ptr) {
const uint8_t *tmp = (const uint8_t*)ptr; const uint8_t *tmp = (const uint8_t*)ptr;
return *tmp + ((uint16_t)*(tmp + 1) << 8); return *tmp + ((uint16_t)*(tmp + 1) << 8);

View file

@ -45,65 +45,26 @@ void ZLImageMapWriter::addImage(const std::string &id, const ZLImage &image) {
} }
void ZLImageMapWriter::addSingleImageEntry(const ZLSingleImage &image) { void ZLImageMapWriter::addSingleImageEntry(const ZLSingleImage &image) {
ZLUnicodeUtil::Ucs2String ucs2mime; const ZLFileImage &fileImage = (const ZLFileImage&)image;
ZLUnicodeUtil::utf8ToUcs2(ucs2mime, image.mimeType());
const size_t mimeSize = ucs2mime.size() * 2;
const size_t len = 4 + mimeSize; ZLUnicodeUtil::Ucs2String mime;
char *address = myAllocator.allocate(len); ZLUnicodeUtil::utf8ToUcs2(mime, image.mimeType());
ZLUnicodeUtil::Ucs2String path;
ZLUnicodeUtil::utf8ToUcs2(path, fileImage.file().path());
ZLUnicodeUtil::Ucs2String encoding;
char *ptr = address; const size_t len = 16 + mime.size() * 2 + path.size() * 2 + encoding.size() * 2;
*ptr++ = image.kind(); char *ptr = myAllocator.allocate(len);
*ptr++ = 0;//image.kind();
*ptr++ = 0; // multi ? 1 : 0 *ptr++ = 0; // multi ? 1 : 0
ZLCachedMemoryAllocator::writeUInt16(ptr, ucs2mime.size());
memcpy(ptr + 2, &ucs2mime.front(), mimeSize);
switch (image.kind()) { ptr = ZLCachedMemoryAllocator::writeString(ptr, mime);
case ZLSingleImage::BASE64_ENCODED_IMAGE: ptr = ZLCachedMemoryAllocator::writeString(ptr, path);
case ZLSingleImage::REGULAR_IMAGE: ptr = ZLCachedMemoryAllocator::writeString(ptr, encoding);
{
const shared_ptr<std::string> data = image.stringData();
size_t length = data.isNull() ? 0 : data->length();
size_t dataSize = (length + 1) / 2;
const size_t newlen = len + 4 + dataSize * 2; ptr = ZLCachedMemoryAllocator::writeUInt32(ptr, fileImage.offset());
address = myAllocator.reallocateLast(address, newlen); ptr = ZLCachedMemoryAllocator::writeUInt32(ptr, fileImage.size());
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;
}
}
} }
void ZLImageMapWriter::addMultiImageEntry(const ZLMultiImage &image) { void ZLImageMapWriter::addMultiImageEntry(const ZLMultiImage &image) {

View file

@ -346,7 +346,7 @@ void ZLTextModel::addHyperlinkControl(ZLTextKind textKind, ZLHyperlinkType hyper
++myParagraphLengths.back(); ++myParagraphLengths.back();
} }
void ZLTextModel::addImage(const std::string &id, short vOffset) { void ZLTextModel::addImage(const std::string &id, short vOffset, bool isCover) {
checkUtf8Text(); checkUtf8Text();
ZLUnicodeUtil::Ucs2String ucs2id; ZLUnicodeUtil::Ucs2String ucs2id;
@ -354,12 +354,13 @@ void ZLTextModel::addImage(const std::string &id, short vOffset) {
const size_t len = ucs2id.size() * 2; const size_t len = ucs2id.size() * 2;
myLastEntryStart = myAllocator.allocate(len + 6); myLastEntryStart = myAllocator.allocate(len + 8);
*myLastEntryStart = ZLTextParagraphEntry::IMAGE_ENTRY; *myLastEntryStart = ZLTextParagraphEntry::IMAGE_ENTRY;
*(myLastEntryStart + 1) = 0; *(myLastEntryStart + 1) = 0;
ZLCachedMemoryAllocator::writeUInt16(myLastEntryStart + 2, vOffset); ZLCachedMemoryAllocator::writeUInt16(myLastEntryStart + 2, vOffset);
ZLCachedMemoryAllocator::writeUInt16(myLastEntryStart + 4, ucs2id.size()); ZLCachedMemoryAllocator::writeUInt16(myLastEntryStart + 4, ucs2id.size());
memcpy(myLastEntryStart + 6, &ucs2id.front(), len); memcpy(myLastEntryStart + 6, &ucs2id.front(), len);
ZLCachedMemoryAllocator::writeUInt16(myLastEntryStart + 6 + len, isCover ? 1 : 0);
myParagraphs.back()->addEntry(myLastEntryStart); myParagraphs.back()->addEntry(myLastEntryStart);
++myParagraphLengths.back(); ++myParagraphLengths.back();
} }

View file

@ -75,7 +75,7 @@ public:
void addHyperlinkControl(ZLTextKind textKind, ZLHyperlinkType hyperlinkType, const std::string &label); void addHyperlinkControl(ZLTextKind textKind, ZLHyperlinkType hyperlinkType, const std::string &label);
void addText(const std::string &text); void addText(const std::string &text);
void addText(const std::vector<std::string> &text); void addText(const std::vector<std::string> &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 addFixedHSpace(unsigned char length);
void addBidiReset(); void addBidiReset();

View file

@ -68,14 +68,12 @@ public class ImageViewActivity extends Activity {
final Uri uri = intent.getData(); final Uri uri = intent.getData();
if (ZLFileImage.SCHEME.equals(uri.getScheme())) { if (ZLFileImage.SCHEME.equals(uri.getScheme())) {
final ZLFileImage image = ZLFileImage.byUrlPath(uri.getPath());
if (image == null) {
// TODO: error message (?)
finish();
}
try { 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); final ZLImageData imageData = ZLImageManager.Instance().getImageData(image);
myBitmap = ((ZLAndroidImageData)imageData).getFullSizeBitmap(); myBitmap = ((ZLAndroidImageData)imageData).getFullSizeBitmap();
} catch (Exception e) { } catch (Exception e) {

View file

@ -84,9 +84,11 @@ public class NativeFormatPlugin extends FormatPlugin {
protected native ZLImage readCoverInternal(ZLFile file); protected native ZLImage readCoverInternal(ZLFile file);
/*
public static ZLImage createImage(String mimeType, String fileName, int offset, int length) { public static ZLImage createImage(String mimeType, String fileName, int offset, int length) {
return new ZLFileImage(MimeType.get(mimeType), ZLFile.createFileByPath(fileName), offset, length); return new ZLFileImage(MimeType.get(mimeType), ZLFile.createFileByPath(fileName), offset, length);
} }
*/
// FIXME: temporary implementation; implement as a native code // FIXME: temporary implementation; implement as a native code
@Override @Override

View file

@ -182,7 +182,7 @@ public class MobipocketHtmlBookReader extends HtmlReader {
if (length <= 0) { if (length <= 0) {
break; 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));
} }
} }

View file

@ -225,7 +225,7 @@ public class MobipocketPlugin extends JavaFormatPlugin {
if (start >= 0) { if (start >= 0) {
int len = myMobipocketStream.getImageLength(coverIndex); int len = myMobipocketStream.getImageLength(coverIndex);
if (len > 0) { 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; return null;

View file

@ -61,7 +61,7 @@ public abstract class ZLBase64EncodedImage extends ZLSingleImage {
try { try {
decode(); decode();
final File file = new File(decodedFileName()); 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) { } catch (Exception e) {
return null; return null;
} }

View file

@ -28,23 +28,44 @@ import org.geometerplus.zlibrary.core.util.SliceInputStream;
public class ZLFileImage extends ZLSingleImage { public class ZLFileImage extends ZLSingleImage {
public static final String SCHEME = "imagefile"; 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 ZLFile myFile;
private final String myEncoding;
private final int myOffset; private final int myOffset;
private final int myLength; 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); super(mimeType);
myFile = file; myFile = file;
myEncoding = encoding;
myOffset = offset; myOffset = offset;
myLength = length; myLength = length;
} }
public ZLFileImage(MimeType mimeType, ZLFile file) { 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() { public String getURI() {
return SCHEME + "://" + myFile.getPath() + "\000" + myOffset + "\000" + myLength; return SCHEME + "://" + myFile.getPath() + "\000" + myEncoding + "\000" + myOffset + "\000" + myLength;
} }
@Override @Override

View file

@ -24,12 +24,6 @@ import java.io.InputStream;
import org.geometerplus.zlibrary.core.util.MimeType; import org.geometerplus.zlibrary.core.util.MimeType;
public abstract class ZLSingleImage implements ZLImage { 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; private final MimeType myMimeType;
public ZLSingleImage(final MimeType mimeType) { public ZLSingleImage(final MimeType mimeType) {

View file

@ -38,12 +38,11 @@ class ZLImageMapReader {
data = myStorage.block(++index); data = myStorage.block(++index);
offset = 0; offset = 0;
} }
final byte kind = (byte)data[offset];
final boolean multi = ((byte)(data[offset] >> 8)) != 0; final boolean multi = ((byte)(data[offset] >> 8)) != 0;
if (multi) { if (multi) {
return readMultiImage(index, offset + 1, data); return readMultiImage(index, offset + 1, data);
} else { } else {
return readSingleImage(index, offset + 1, data, kind); return readSingleImage(index, offset + 1, data);
} }
} }
@ -52,37 +51,26 @@ class ZLImageMapReader {
return null; return null;
} }
private ZLImage readSingleImage(int index, int offset, char[] data, byte kind) { private ZLImage readSingleImage(int index, int offset, char[] data) {
final short mimeLength = (short)data[offset++]; short len = (short)data[offset++];
final String mime = new String(data, offset, mimeLength); final String mime = new String(data, offset, len);
offset += mimeLength; offset += len;
switch (kind) { len = (short)data[offset++];
case ZLSingleImage.Kind.BASE64_ENCODED_IMAGE: final String path = new String(data, offset, len);
case ZLSingleImage.Kind.REGULAR_IMAGE: offset += len;
{
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
);
}
}
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
);
} }
} }