/******************************************************************************* * Copyright 2009 Robot Media SL * * 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. ******************************************************************************/ package net.robotmedia.acv.comic; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import android.net.Uri; import android.util.Log; import java.util.ArrayList; import java.util.List; import java.util.TreeMap; import com.github.junrar.Archive; import com.github.junrar.rarfile.FileHeader; import com.github.junrar.unpack.decode.Compress; import net.robotmedia.acv.logic.TrackingManager; import net.robotmedia.acv.utils.FileUtils; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Bitmap.Config; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; public class RarComic extends Comic { private Archive arc = null; private ArrayList<String> orderedScreens; private TreeMap<String, FileHeader> fileHeaders; protected RarComic(String comicPath) { super(comicPath); File file = new File(comicPath); try { arc = new Archive(file); } catch (Exception e) { e.printStackTrace(); TrackingManager.trackError("RarComic", e); } if (arc != null && !arc.isEncrypted()) { final TreeMap<String, String> headers = new TreeMap<String, String>(); fileHeaders = new TreeMap<String, FileHeader>(); List<FileHeader> files = arc.getFileHeaders(); for (FileHeader fh : files) { if (!fh.isEncrypted() && fh.isFileHeader()) { String fileName; if (fh.isUnicode()) { fileName = fh.getFileNameW(); } else { fileName = fh.getFileNameString(); } String extension = FileUtils.getFileExtension(fileName); if (FileUtils.isImage(extension)) { fileHeaders.put(fileName, fh); final String key = this.addLeadingZeroes(fileName); headers.put(key, fileName); } } } ArrayList<String> ordered = new ArrayList<String>(headers.keySet()); orderedScreens = new ArrayList<String>(ordered.size()); for (int i = 0; i < ordered.size(); i++) { orderedScreens.add(headers.get(ordered.get(i))); } } else { error(); } } private File extract(String fileName, int position) { File file = null; FileOutputStream os = null; try { FileHeader fh = fileHeaders.get(fileName); final String tempFileName = getDefaultFileName(position); file = createTempFile(tempFileName); os = new FileOutputStream(file); arc.extractFile(fh, os); } catch (Exception e) { Log.e("RarComic.extract", e.getLocalizedMessage()); // Try with small window size in we're using the big one Compress.adjustWindowSize(false); } finally { if (os != null) { try { os.close(); } catch (IOException e1) { e1.printStackTrace(); } } } return file; } public synchronized void prepareScreen(int position) { if (position >= 0 && position < this.getLength()) { ImageState status = imageState.get(String.valueOf(position)); if (status == null || status.equals(ImageState.UNKNOWN)) { String entryName = orderedScreens.get(position); try { getBitmapFromFileHeaderIfNeeded(position, entryName, true); } catch (Exception e) { e.printStackTrace(); TrackingManager.trackError("RarComic.prepareScreen", e); } } } } private synchronized Bitmap getBitmapFromFileHeaderIfNeeded(int position, String fileName, boolean recycle) { Bitmap bitmap = null; ImageState status = imageState.get(String.valueOf(position)); if (status == null || status.equals(ImageState.UNKNOWN)) { try { File file = extract(fileName, position); BitmapFactory.decodeFile(file.getPath(), bounds); if (bounds.outWidth == -1) { // TODO: Error } int width = bounds.outWidth; int height = bounds.outHeight; boolean landscape = height > width; int maxHeight = getMaxHeight(landscape); int maxWidth = getMaxWidth(landscape); boolean withinBounds = width <= maxWidth && height <= maxHeight; if (withinBounds) { imageState.put(String.valueOf(position), ImageState.ORIGINAL); } else { bitmap = resampleAndSave(position, width, height); } } catch (Exception e) { e.printStackTrace(); TrackingManager.trackError("RarComic.getBitmapFromFileHeaderIfNeeded", e); } } if (bitmap != null && recycle) { bitmap.recycle(); return null; } else { return bitmap; } } public int getLength() { return orderedScreens != null ? orderedScreens.size() : 0; } @Override public Drawable getScreen(final int position) { ImageState status = imageState.get(String.valueOf(position)); if (status == null) status = ImageState.UNKNOWN; try { String entryName = orderedScreens.get(position); switch (status) { case ORIGINAL: case MODIFIED: String filePath = getTempFilePath(position); if (filePath != null) { return Drawable.createFromPath(filePath); } default: Bitmap bitmap = getBitmapFromFileHeaderIfNeeded(position, entryName, false); if (bitmap == null) { status = imageState.get(String.valueOf(position)); if (status == null) status = ImageState.UNKNOWN; switch (status) { case ORIGINAL: case MODIFIED: filePath = getTempFilePath(position); if (filePath != null) { return Drawable.createFromPath(filePath); } return Drawable.createFromPath(filePath); default: error(); return null; } } else { return new BitmapDrawable(bitmap); } } } catch(IndexOutOfBoundsException e) { return null; } } public Drawable getThumbnail(int position) { return null; } private Bitmap resample(String filePath, int sampleSize, int position) { BitmapFactory.Options resample = new BitmapFactory.Options(); resample.inPreferredConfig = Config.RGB_565; resample.inSampleSize = sampleSize; return BitmapFactory.decodeFile(filePath, resample); } private Bitmap resampleAndSave(int position, int width, int height) { String filePath = getTempFilePath(position); Bitmap bitmap = null; int sampleSize = calculateSampleSize(width, height); if (filePath != null) { bitmap = resample(filePath, sampleSize, position); } if (bitmap != null) { final String tempFileName = getDefaultFileName(position); String resampledFilePath = saveBitmap(tempFileName, bitmap); if (resampledFilePath != null) { imageState.put(String.valueOf(position), ImageState.MODIFIED); } } return bitmap; } public void destroy() { try { if (this.arc != null) { this.arc.close(); } } catch (IOException e) {} } private String getTempFilePath(int position) { final String tempFileName = getDefaultFileName(position); return getTempFilePath(tempFileName); } @Override public Uri getUri(int position) { String filePath = getTempFilePath(position); return filePath != null ? Uri.fromFile(new File(filePath)) : null; } }