package org.emdev.common.textmarkup.image; import org.ebookdroid.droids.fb2.codec.FB2Page; import android.graphics.BitmapFactory; import android.graphics.BitmapFactory.Options; import android.graphics.RectF; import java.io.IOException; import java.io.InputStream; import org.emdev.utils.LengthUtils; import org.emdev.utils.base64.Base64; import org.emdev.utils.base64.Base64InputStream; public abstract class AbstractImageData implements IImageData { protected AbstractImageData() { } @Override public final RectF getImageRect(final boolean inline) { float w = 0, h = 0; final Options opts = getImageSize(); if (opts != null) { final int origWidth = opts.outWidth; final int origHeight = opts.outHeight; if (origWidth <= FB2Page.PAGE_WIDTH - 2 * FB2Page.MARGIN_X && origHeight <= FB2Page.PAGE_HEIGHT - 2 * FB2Page.MARGIN_Y && inline) { w = origWidth; h = origHeight; } else { if (origWidth > FB2Page.PAGE_WIDTH - 2 * FB2Page.MARGIN_X || !inline) { w = FB2Page.PAGE_WIDTH - 2 * FB2Page.MARGIN_X; h = origHeight * w / origWidth; } else { w = origWidth; h = origHeight; } if (h > FB2Page.PAGE_HEIGHT - 2 * FB2Page.MARGIN_X) { w = w * (FB2Page.PAGE_HEIGHT - 2 * FB2Page.MARGIN_Y) / h; h = FB2Page.PAGE_HEIGHT - 2 * FB2Page.MARGIN_X; } } } return new RectF(0f, 0f, w, h); } protected abstract Options getImageSize(); protected Options getImageSize(final String encoded) { final Options opts = new Options(); opts.inJustDecodeBounds = true; final Base64InputStream stream = new Base64InputStream(new AsciiCharStringInputStream(encoded), Base64.DEFAULT); BitmapFactory.decodeStream(stream, null, opts); try { stream.close(); } catch (final IOException ex) { } return opts; } protected Options getImageSize(char[] ch, int start, int length) { final Options opts = new Options(); opts.inJustDecodeBounds = true; final Base64InputStream stream = new Base64InputStream(new AsciiCharInputStream(ch, start, length), Base64.DEFAULT); BitmapFactory.decodeStream(stream, null, opts); try { stream.close(); } catch (final IOException ex) { } return opts; } protected static class AsciiCharStringInputStream extends InputStream { private final String str; private int index; private final int length; public AsciiCharStringInputStream(final String str) { this.length = LengthUtils.length(str); this.str = str; } @Override public int read() throws IOException { return index >= length ? -1 : (0xFF & str.charAt(index++)); } @Override public int available() throws IOException { return length - index; } @Override public int read(final byte[] buffer, final int offset, final int length) throws IOException { final int available = available(); if (available <= 0) { return -1; } final int read = Math.min(available, length); for (int i = 0; i < read; i++) { final int c = (0xFF & str.charAt(index++)); buffer[offset + i] = (byte) c; } return read; } } protected static class AsciiCharInputStream extends InputStream { private final char[] chars; private int index; private final int start; private final int length; public AsciiCharInputStream(char[] ch, int start, int length) { this.length = length; this.start = start; this.chars = ch; this.index = start; } @Override public int read() throws IOException { return index >= start + length ? -1 : (0xFF & chars[index++]); } @Override public int available() throws IOException { return start + length - index; } @Override public int read(final byte[] buffer, final int offset, final int length) throws IOException { final int available = available(); if (available <= 0) { return -1; } final int read = Math.min(available, length); for (int i = 0; i < read; i++) { final int c = (0xFF & chars[index++]); buffer[offset + i] = (byte) c; } return read; } } }