Compare commits

..
16 Commits
Author SHA1 Message Date
tarsin d13cd1e07f 1.8.0.2
CI / Build (push) Has been cancelled
Releases / Build (push) Has been cancelled
2022-07-28 10:37:07 +08:00
tarsin 7365fd0448 Fix a memleak 2022-07-28 10:33:47 +08:00
txyyh f1febca312 Let renovate bot detect two branch 2022-07-28 04:12:33 +08:00
renovate[bot] dbf67404c0 Update fragment_version to v1.5.1 (#138)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-28 03:39:42 +08:00
renovate[bot] 8cfe8c4b80 Update collection_version to v1.3.0-alpha02 (#137)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-28 03:39:25 +08:00
tarsin 674f53315f Code clean 2022-07-27 19:46:39 +08:00
tarsin e51cd6b90d Drop taptargetview
* Not MD3
2022-07-25 20:44:59 +08:00
tarsin a44f12b2e0 Reformat Code 2022-07-25 20:07:16 +08:00
tarsin a2552ed5b9 Reformat 2022-07-25 20:05:38 +08:00
tarsin 763c007950 Log tweaks 2022-07-25 20:02:47 +08:00
tarsin b221bf8e52 Release 1.8.0.1
CI / Build (push) Has been cancelled
Releases / Build (push) Has been cancelled
2022-07-25 19:16:07 +08:00
tarsin ab9a89685c Code clean 2022-07-25 19:02:10 +08:00
tarsin 41ccb16227 Code clean 2022-07-25 18:42:18 +08:00
tarsin f6bf7b1ba6 No need to thanks image decs anymore 2022-07-25 13:06:24 +08:00
tarsin 09e7113df1 Fix a dirty dealloc 2022-07-25 12:23:52 +08:00
tarsin 62a7e283a4 Should be able to support all format now 2022-07-25 10:51:57 +08:00
41 changed files with 370 additions and 1182 deletions

No files matched your search

-4
View File
@@ -54,12 +54,8 @@ Here is the libraries
- [material-components-android](https://github.com/material-components/material-components-android)
- [material-design-icons](https://github.com/google/material-design-icons)
- [Apache Commons Lang](https://commons.apache.org/proper/commons-lang/)
- [apng](http://apng.sourceforge.net/)
- [giflib](http://giflib.sourceforge.net)
- [greenDAO](https://github.com/greenrobot/greenDAO)
- [jsoup](https://github.com/jhy/jsoup)
- [libjpeg-turbo](https://libjpeg-turbo.org/)
- [libpng](http://www.libpng.org/pub/png/libpng.html)
- [okhttp](https://github.com/square/okhttp)
- [roaster](https://github.com/forge/roaster)
- [TapTargetView](https://github.com/KeepSafe/TapTargetView)
+4 -5
View File
@@ -34,8 +34,8 @@ android {
applicationId "moe.tarsin.ehviewer"
minSdkVersion 31
targetSdkVersion 33
versionCode 180000
versionName "1.8.0.0"
versionCode 180002
versionName "1.8.0.2"
resConfigs 'zh', 'zh-rCN', 'zh-rHK', 'zh-rTW', 'es', 'ja', 'ko', 'fr', 'de', 'th'
}
@@ -107,7 +107,7 @@ dependencies {
implementation "androidx.biometric:biometric-ktx:1.2.0-alpha04"
implementation "androidx.browser:browser:1.4.0"
def collection_version = "1.3.0-alpha01"
def collection_version = "1.3.0-alpha02"
implementation "androidx.collection:collection:$collection_version"
implementation "androidx.collection:collection-ktx:$collection_version"
@@ -122,7 +122,7 @@ dependencies {
implementation "androidx.documentfile:documentfile:1.1.0-alpha01"
implementation "androidx.dynamicanimation:dynamicanimation:1.1.0-alpha03"
def fragment_version = "1.5.0"
def fragment_version = "1.5.1"
implementation "androidx.fragment:fragment:$fragment_version"
implementation "androidx.fragment:fragment-ktx:$fragment_version"
@@ -148,7 +148,6 @@ dependencies {
implementation 'com.drakeet.drawer:drawer:1.0.3'
implementation 'com.google.android.material:material:1.7.0-alpha03'
implementation 'com.getkeepsafe.taptargetview:taptargetview:1.13.3'
implementation 'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:1.0.0'
implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.10'
implementation 'dev.rikka.rikkax.core:core-ktx:1.4.1'
+5 -4
View File
@@ -26,11 +26,12 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<!-- Required to maintain app compatibility. -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<uses-feature
android:glEsVersion="0x00020000"
android:required="true" />
@@ -167,6 +167,7 @@ public final class DiskLruCache implements Closeable {
* its sequence number is not equal to its entry's sequence number.
*/
private long nextSequenceNumber = 0;
private DiskLruCache(File directory, int appVersion, int valueCount, long maxSize) {
this.directory = directory;
this.appVersion = appVersion;
@@ -175,21 +176,7 @@ public final class DiskLruCache implements Closeable {
this.journalFileBackup = new File(directory, JOURNAL_FILE_BACKUP);
this.valueCount = valueCount;
this.maxSize = maxSize;
} private final Callable<Void> cleanupCallable = new Callable<>() {
public Void call() throws Exception {
synchronized (DiskLruCache.this) {
if (journalWriter == null) {
return null; // Closed.
}
trimToSize();
if (journalRebuildRequired()) {
rebuildJournal();
redundantOpCount = 0;
}
}
return null;
}
};
}
/**
* Opens the cache in {@code directory}, creating a cache if none exists
@@ -244,7 +231,21 @@ public final class DiskLruCache implements Closeable {
cache = new DiskLruCache(directory, appVersion, valueCount, maxSize);
cache.rebuildJournal();
return cache;
}
} private final Callable<Void> cleanupCallable = new Callable<>() {
public Void call() throws Exception {
synchronized (DiskLruCache.this) {
if (journalWriter == null) {
return null; // Closed.
}
trimToSize();
if (journalRebuildRequired()) {
rebuildJournal();
redundantOpCount = 0;
}
}
return null;
}
};
private static void deleteIfExists(File file) throws IOException {
if (file.exists() && !file.delete()) {
@@ -16,8 +16,6 @@
package com.hippo.ehviewer;
import android.os.ParcelFileDescriptor;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -27,7 +25,6 @@ import com.hippo.streampipe.InputStreamPipe;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class ImageBitmapHelper implements ValueHelper<ImageBitmap> {
@@ -34,10 +34,6 @@ import com.hippo.unifile.UniFile;
import com.hippo.yorozuya.thread.PVLock;
import com.hippo.yorozuya.thread.PriorityThread;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -259,7 +259,7 @@ public class DirGalleryProvider extends GalleryProvider2 implements Runnable {
InputStream is = null;
try {
is = files[index].openInputStream();
Image image = Image.decode(((FileInputStream)is).getFD(), true);
Image image = Image.decode(((FileInputStream) is).getFD(), true);
mDecodingIndex.lazySet(GalleryPageView.INVALID_INDEX);
if (image != null) {
notifyPageSucceed(index, image);
@@ -50,7 +50,7 @@ class VersionPreference @JvmOverloads constructor(
inner class NativeLibInfo {
private var message: String = ""
fun addLib(libname:String, libversion:String): NativeLibInfo {
fun addLib(libname: String, libversion: String): NativeLibInfo {
message = "$message$libname $libversion\n"
return this
}
@@ -1678,10 +1678,9 @@ public final class SpiderQueen implements Runnable {
if (is != null) {
try {
image = Image.decode(((FileInputStream)is).getFD(), true);
image = Image.decode(((FileInputStream) is).getFD(), true);
} catch (IOException e) {
e.printStackTrace();
image = null;
} finally {
try {
is.close();
@@ -226,6 +226,9 @@ public class GalleryActivity extends EhActivity implements SeekBar.OnSeekBarChan
private int mSize;
private int mCurrentIndex;
private int mSavingPage = -1;
private EditTextDialogBuilder builder;
private boolean dialogShown = false;
private AlertDialog dialog;
private void buildProvider() {
if (mGalleryProvider != null) {
@@ -287,7 +290,16 @@ public class GalleryActivity extends EhActivity implements SeekBar.OnSeekBarChan
}
outState.putInt(KEY_PAGE, mPage);
outState.putInt(KEY_CURRENT_INDEX, mCurrentIndex);
}
} ActivityResultLauncher<String> requestStoragePermissionLauncher = registerForActivityResult(
new ActivityResultContracts.RequestPermission(),
result -> {
if (result && mSavingPage != -1) {
saveImage(mSavingPage);
} else {
Toast.makeText(this, R.string.error_cant_save_image, Toast.LENGTH_SHORT).show();
}
mSavingPage = -1;
});
@Override
protected void attachBaseContext(@NonNull Context newBase) {
@@ -477,16 +489,7 @@ public class GalleryActivity extends EhActivity implements SeekBar.OnSeekBarChan
FrameLayout mainLayout = (FrameLayout) ViewUtils.$$(this, R.id.main);
mainLayout.addView(new GalleryGuideView(this));
}
} ActivityResultLauncher<String> requestStoragePermissionLauncher = registerForActivityResult(
new ActivityResultContracts.RequestPermission(),
result -> {
if (result && mSavingPage != -1) {
saveImage(mSavingPage);
} else {
Toast.makeText(this, R.string.error_cant_save_image, Toast.LENGTH_SHORT).show();
}
mSavingPage = -1;
});
}
@Override
protected void onDestroy() {
@@ -1046,6 +1049,66 @@ public class GalleryActivity extends EhActivity implements SeekBar.OnSeekBarChan
}
}
private void showPasswdDialog() {
if (!dialogShown) {
dialogShown = true;
dialog.show();
if (dialog.getButton(AlertDialog.BUTTON_POSITIVE) != null) {
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(v -> {
GalleryActivity.this.onProvidePasswd();
});
}
dialog.setOnCancelListener(v -> finish());
}
}
private void onProvidePasswd() {
String passwd = builder.getText();
if (passwd.isEmpty())
builder.setError(getString(R.string.passwd_cannot_be_empty));
else {
ArchiveGalleryProvider.passwd = passwd;
ArchiveGalleryProvider.pv.v();
}
}
private void onPasswdWrong() {
builder.setError(getString(R.string.passwd_wrong));
}
private void onPasswdCorrect() {
dialog.dismiss();
}
private static class ShowPasswdDialogHandler extends Handler {
//弱引用持有HandlerActivity , GC 回收时会被回收掉
private final WeakReference<GalleryActivity> weakReference;
public ShowPasswdDialogHandler(GalleryActivity activity) {
this.weakReference = new WeakReference(activity);
}
@Override
public void handleMessage(Message msg) {
GalleryActivity activity = weakReference.get();
super.handleMessage(msg);
if (null != activity) {
switch (msg.what) {
case 0:
activity.showPasswdDialog();
break;
case 1:
activity.onPasswdWrong();
break;
case 2:
activity.onPasswdCorrect();
break;
}
}
}
}
private class GalleryMenuHelper implements DialogInterface.OnClickListener {
private final View mView;
@@ -1306,69 +1369,5 @@ public class GalleryActivity extends EhActivity implements SeekBar.OnSeekBarChan
}
}
private EditTextDialogBuilder builder;
private boolean dialogShown = false;
private AlertDialog dialog;
private void showPasswdDialog() {
if (!dialogShown) {
dialogShown = true;
dialog.show();
if (dialog.getButton(AlertDialog.BUTTON_POSITIVE) != null) {
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(v -> {
GalleryActivity.this.onProvidePasswd();
});
}
dialog.setOnCancelListener(v -> finish());
}
}
private void onProvidePasswd() {
String passwd = builder.getText();
if (passwd.isEmpty())
builder.setError(getString(R.string.passwd_cannot_be_empty));
else {
ArchiveGalleryProvider.passwd = passwd;
ArchiveGalleryProvider.pv.v();
}
}
private void onPasswdWrong() {
builder.setError(getString(R.string.passwd_wrong));
}
private void onPasswdCorrect() {
dialog.dismiss();
}
private static class ShowPasswdDialogHandler extends Handler {
//弱引用持有HandlerActivity , GC 回收时会被回收掉
private final WeakReference<GalleryActivity> weakReference;
public ShowPasswdDialogHandler(GalleryActivity activity) {
this.weakReference = new WeakReference(activity);
}
@Override
public void handleMessage(Message msg) {
GalleryActivity activity = weakReference.get();
super.handleMessage(msg);
if (null != activity) {
switch (msg.what) {
case 0:
activity.showPasswdDialog();
break;
case 1:
activity.onPasswdWrong();
break;
case 2:
activity.onPasswdCorrect();
break;
}
}
}
}
}
@@ -22,7 +22,6 @@ import android.content.res.Resources;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
@@ -55,8 +55,6 @@ import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.SimpleItemAnimator;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
import com.getkeepsafe.taptargetview.TapTarget;
import com.getkeepsafe.taptargetview.TapTargetView;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.h6ah4i.android.widget.advrecyclerview.animator.DraggableItemAnimator;
@@ -390,90 +388,9 @@ public class DownloadsScene extends ToolbarScene
updateView();
guide();
return view;
}
private void guide() {
if (Settings.getGuideDownloadThumb() && null != mRecyclerView) {
mRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (Settings.getGuideDownloadThumb()) {
guideDownloadThumb();
}
if (null != mRecyclerView) {
ViewUtils.removeOnGlobalLayoutListener(mRecyclerView.getViewTreeObserver(), this);
}
}
});
} else {
guideDownloadLabels();
}
}
private void guideDownloadThumb() {
MainActivity activity = getMainActivity();
if (null == activity || !Settings.getGuideDownloadThumb() || null == mLayoutManager || null == mRecyclerView) {
guideDownloadLabels();
return;
}
int position = mLayoutManager.findFirstCompletelyVisibleItemPositions(null)[0];
if (position < 0) {
guideDownloadLabels();
return;
}
RecyclerView.ViewHolder holder = mRecyclerView.findViewHolderForAdapterPosition(position);
if (null == holder) {
guideDownloadLabels();
return;
}
TapTargetView.showFor(requireActivity(),
TapTarget.forView(((DownloadHolder) holder).thumb,
getString(R.string.guide_download_thumb_title),
getString(R.string.guide_download_thumb_text))
.transparentTarget(true),
new TapTargetView.Listener() {
@Override
public void onTargetDismissed(TapTargetView view, boolean userInitiated) {
super.onTargetDismissed(view, userInitiated);
Settings.putGuideDownloadThumb(false);
guideDownloadLabels();
}
});
}
private void guideDownloadLabels() {
MainActivity activity = getMainActivity();
if (null == activity || !Settings.getGuideDownloadLabels()) {
return;
}
Display display = activity.getWindowManager().getDefaultDisplay();
Point point = new Point();
display.getSize(point);
Rect bounds = new Rect(point.x + LayoutUtils.dp2pix(requireContext(), 20),
point.y / 3 + LayoutUtils.dp2pix(requireContext(), 20),
point.x - LayoutUtils.dp2pix(requireContext(), 20),
point.y / 3 - LayoutUtils.dp2pix(requireContext(), 20));
TapTargetView.showFor(requireActivity(),
TapTarget.forBounds(bounds,
getString(R.string.guide_download_labels_title),
getString(R.string.guide_download_labels_text))
.transparentTarget(true),
new TapTargetView.Listener() {
@Override
public void onTargetDismissed(TapTargetView view, boolean userInitiated) {
super.onTargetClick(view);
Settings.puttGuideDownloadLabels(false);
openDrawer(Gravity.RIGHT);
}
});
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
@@ -45,8 +45,6 @@ import androidx.drawerlayout.widget.DrawerLayout;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.getkeepsafe.taptargetview.TapTarget;
import com.getkeepsafe.taptargetview.TapTargetView;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.hippo.annotation.Implemented;
@@ -311,40 +309,9 @@ public class FavoritesScene extends BaseScene implements
mHelper.firstRefresh();
}
guideCollections();
return view;
}
private void guideCollections() {
Activity activity = getMainActivity();
if (null == activity || !Settings.getGuideCollections()) {
return;
}
Display display = activity.getWindowManager().getDefaultDisplay();
Point point = new Point();
display.getSize(point);
Rect bounds = new Rect(point.x + LayoutUtils.dp2pix(requireContext(), 20),
point.y / 3 + LayoutUtils.dp2pix(requireContext(), 20),
point.x - LayoutUtils.dp2pix(requireContext(), 20),
point.y / 3 - LayoutUtils.dp2pix(requireContext(), 20));
TapTargetView.showFor(requireActivity(),
TapTarget.forBounds(bounds,
getString(R.string.guide_collections_title),
getString(R.string.guide_collections_text))
.transparentTarget(true),
new TapTargetView.Listener() {
@Override
public void onTargetDismissed(TapTargetView view, boolean userInitiated) {
super.onTargetClick(view);
Settings.putGuideCollections(false);
openDrawer(Gravity.RIGHT);
}
});
}
// keyword of mUrlBuilder, fav cat of mUrlBuilder, mFavCatArray.
// They changed, call it
private void updateSearchBar() {
@@ -59,8 +59,6 @@ import androidx.drawerlayout.widget.DrawerLayout;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.getkeepsafe.taptargetview.TapTarget;
import com.getkeepsafe.taptargetview.TapTargetView;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.h6ah4i.android.widget.advrecyclerview.animator.DraggableItemAnimator;
@@ -634,40 +632,9 @@ public final class GalleryListScene extends BaseScene
mHelper.firstRefresh();
}
guideQuickSearch();
return view;
}
private void guideQuickSearch() {
Activity activity = getMainActivity();
if (null == activity || !Settings.getGuideQuickSearch()) {
return;
}
Display display = activity.getWindowManager().getDefaultDisplay();
Point point = new Point();
display.getSize(point);
Rect bounds = new Rect(point.x + LayoutUtils.dp2pix(requireContext(), 20),
point.y / 3 + LayoutUtils.dp2pix(requireContext(), 20),
point.x - LayoutUtils.dp2pix(requireContext(), 20),
point.y / 3 - LayoutUtils.dp2pix(requireContext(), 20));
TapTargetView.showFor(requireActivity(),
TapTarget.forBounds(bounds,
getString(R.string.guide_quick_search_title),
getString(R.string.guide_quick_search_text))
.transparentTarget(true),
new TapTargetView.Listener() {
@Override
public void onTargetDismissed(TapTargetView view, boolean userInitiated) {
super.onTargetClick(view);
Settings.putGuideQuickSearch(false);
openDrawer(Gravity.RIGHT);
}
});
}
@Override
public void onDestroyView() {
super.onDestroyView();
@@ -57,6 +57,7 @@ public abstract class GalleryProvider {
public void stop() {
OSUtils.checkMainLoop();
mImageCache.evictAll();
Image.lazyEvictAll();
}
public void setGLRoot(GLRoot glRoot) {
@@ -245,18 +246,14 @@ public abstract class GalleryProvider {
}
public void add(Integer key, ImageWrapper value) {
if (value.getFormat() != Image.FORMAT_ANIMATED && value.obtain()) {
put(key, value);
}
if (value.getFormat() != Image.FORMAT_ANIMATED)
if (value.obtain())
put(key, value);
}
@Override
protected int sizeOf(Integer key, ImageWrapper value) {
int size = value.getWidth() * value.getHeight() * 4;
if (value.getFormat() == Image.FORMAT_ANIMATED) {
size *= 5;
}
return size;
return value.getWidth() * value.getHeight() * 4;
}
@Override
@@ -33,6 +33,7 @@ final class DocumentsContractApi21 {
private static final String TAG = DocumentsContractApi21.class.getSimpleName();
private static final String PATH_DOCUMENT = "document";
private static final String PATH_TREE = "tree";
private DocumentsContractApi21() {
}
@@ -41,6 +41,7 @@ class FileDescriptorRandomAccessFile implements UniRandomAccessFile {
private final int flushAfterWrite;
private final Object closeLock = new Object();
private volatile boolean closed = false;
private FileDescriptorRandomAccessFile(ParcelFileDescriptor pfd, FileDescriptor fd, String mode) {
this.pfd = pfd;
this.fd = fd;
@@ -82,6 +82,13 @@ public class BatteryView extends AppCompatTextView {
}
mCurrentColor = color;
super.setTextColor(color);
}
private void startCharger() {
if (!mIsChargerWorking) {
getHandler().post(mCharger);
mIsChargerWorking = true;
}
} private final Runnable mCharger = new Runnable() {
private int level = 0;
@@ -97,13 +104,6 @@ public class BatteryView extends AppCompatTextView {
}
};
private void startCharger() {
if (!mIsChargerWorking) {
getHandler().post(mCharger);
mIsChargerWorking = true;
}
}
private void stopCharger() {
if (mIsChargerWorking) {
getHandler().removeCallbacks(mCharger);
@@ -145,6 +145,7 @@ public class BatteryView extends AppCompatTextView {
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
@@ -97,6 +97,10 @@ public class TextClock extends AppCompatTextView {
} else {
mTime = Calendar.getInstance();
}
}
public CharSequence getFormat12Hour() {
return mFormat12;
} private final Runnable mTicker = new Runnable() {
@Override
public void run() {
@@ -109,10 +113,6 @@ public class TextClock extends AppCompatTextView {
}
};
public CharSequence getFormat12Hour() {
return mFormat12;
}
public void setFormat12Hour(CharSequence format) {
mFormat12 = format;
@@ -144,19 +144,7 @@ public class TextClock extends AppCompatTextView {
createTime(timeZone);
onTimeChanged();
} private final ContentObserver mFormatChangeObserver = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
chooseFormat();
onTimeChanged();
}
@Override
public void onChange(boolean selfChange, Uri uri) {
chooseFormat();
onTimeChanged();
}
};
}
/**
* Selects either one of {@link #getFormat12Hour()} or {@link #getFormat24Hour()}
@@ -170,7 +158,19 @@ public class TextClock extends AppCompatTextView {
public CharSequence getFormat() {
return mFormat;
}
} private final ContentObserver mFormatChangeObserver = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
chooseFormat();
onTimeChanged();
}
@Override
public void onChange(boolean selfChange, Uri uri) {
chooseFormat();
onTimeChanged();
}
};
/**
* Selects either one of {@link #getFormat12Hour()} or {@link #getFormat24Hour()}
@@ -84,10 +84,10 @@
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:divider="@drawable/spacer_keyline"
android:orientation="horizontal"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:showDividers="middle">
<FrameLayout
@@ -230,8 +230,8 @@
android:clickable="true"
android:focusable="true"
android:insetLeft="40dp"
android:insetRight="40dp"
android:insetTop="16dp"
android:insetRight="40dp"
android:text="@string/read">
<requestFocus />
@@ -244,11 +244,11 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:clickable="true"
android:nextFocusDown="@+id/torrent"
android:focusable="true"
android:insetLeft="40dp"
android:insetTop="16dp"
android:insetRight="40dp" />
android:insetRight="40dp"
android:nextFocusDown="@+id/torrent" />
<android.widget.Space
@@ -188,11 +188,11 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/keyline_margin"
app:chipSpacingHorizontal="8dp"
android:ellipsize="end"
android:singleLine="true"
android:textAllCaps="true"
app:chipIcon="@drawable/ic_baseline_label_24"
app:chipSpacingHorizontal="8dp"
app:ensureMinTouchTargetSize="true"
app:layout_constraintBottom_toTopOf="@id/uploader"
app:layout_constraintEnd_toEndOf="parent" />
+42 -58
View File
@@ -17,13 +17,12 @@
package com.hippo.image;
import android.graphics.Bitmap;
import android.util.Log;
import androidx.annotation.Nullable;
import java.io.BufferedInputStream;
import java.io.FileDescriptor;
import java.io.InputStream;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.ArrayList;
/**
* The {@code Image} is a image which stored pixel data in native heap
@@ -33,7 +32,9 @@ public final class Image {
public static final int FORMAT_ANIMATED = 1;
private static final AtomicInteger sImageCount = new AtomicInteger();
private static final ArrayList<Image> imageList = new ArrayList<>();
private static boolean needEvictAll = false;
private final int mFormat;
private final int mWidth;
private final int mHeight;
@@ -41,12 +42,27 @@ public final class Image {
private Throwable mRecycleTracker;
private Image(long nativePtr, int format, int width, int height) {
if (needEvictAll)
evictAll();
mNativePtr = nativePtr;
mFormat = format;
mWidth = width;
mHeight = height;
sImageCount.getAndIncrement();
imageList.add(this);
}
public static void lazyEvictAll() {
needEvictAll = true;
}
private static void evictAll() {
for (Image image : imageList) {
nativeRecycle(image.mNativePtr);
image.mNativePtr = 0;
}
imageList.clear();
needEvictAll = false;
}
/**
@@ -54,7 +70,7 @@ public final class Image {
*/
@Nullable
public static Image decode(FileDescriptor fd, boolean partially) {
return nativeDecode(fd, partially);
return nativeDecode(fd);
}
/**
@@ -62,7 +78,7 @@ public final class Image {
*/
@Nullable
public static Image decode(Integer fd, boolean partially) {
return nativeDecodeFdInt(fd, partially);
return nativeDecodeFdInt(fd);
}
/**
@@ -70,7 +86,7 @@ public final class Image {
*/
@Nullable
public static Image decodeAddr(Long addr, boolean partially) {
return nativeDecodeAddr(addr, partially);
return nativeDecodeAddr(addr);
}
/**
@@ -86,37 +102,30 @@ public final class Image {
* It is useful for debug.
*/
public static int getImageCount() {
return sImageCount.get();
return imageList.size();
}
private static native Image nativeDecode(FileDescriptor fd, boolean partially);
private static native Image nativeDecode(FileDescriptor fd);
private static native Image nativeDecodeFdInt(int fd, boolean partially);
private static native Image nativeDecodeFdInt(int fd);
private static native Image nativeDecodeAddr(long addr, boolean partially);
private static native Image nativeDecodeAddr(long addr);
private static native Image nativeCreate(Bitmap bitmap);
private static native int nativeGetByteCount(long nativePtr, int format);
private static native void nativeRender(long nativePtr, int format,
private static native void nativeRender(long nativePtr,
int srcX, int srcY, Bitmap dst, int dstX, int dstY,
int width, int height, boolean fillBlank, int defaultColor);
int width, int height);
private static native void nativeTexImage(long nativePtr, int format,
boolean init, int offsetX, int offsetY, int width, int height);
private static native void nativeTexImage(long nativePtr, boolean init, int offsetX, int offsetY, int width, int height);
private static native void nativeAdvance(long nativePtr, int format);
private static native void nativeAdvance(long nativePtr);
private static native int nativeGetDelay(long nativePtr, int format);
private static native int nativeGetDelay(long nativePtr);
private static native boolean nativeIsOpaque(long nativePtr, int format);
private static native boolean nativeIsOpaque(long nativePtr);
private static native boolean nativeIsGray(long nativePtr, int format, int error);
private static native void nativeClahe(long nativePtr, int format, boolean toGray);
private static native void nativeRecycle(long nativePtr, int format);
private static native void nativeRecycle(long nativePtr);
/**
* Return the format of the image
@@ -139,14 +148,6 @@ public final class Image {
return mHeight;
}
/**
* Return the minimum number of bytes that can be used to store this image's pixels.
*/
public int getByteCount() {
checkRecycled();
return nativeGetByteCount(mNativePtr, mFormat);
}
private void checkRecycled() {
if (mNativePtr == 0) {
if (mRecycleTracker != null) {
@@ -163,8 +164,7 @@ public final class Image {
public void render(int srcX, int srcY, Bitmap dst, int dstX, int dstY,
int width, int height, boolean fillBlank, int defaultColor) {
checkRecycled();
nativeRender(mNativePtr, mFormat, srcX, srcY, dst, dstX, dstY,
width, height, fillBlank, defaultColor);
nativeRender(mNativePtr, srcX, srcY, dst, dstX, dstY, width, height);
}
/**
@@ -174,7 +174,7 @@ public final class Image {
*/
public void texImage(boolean init, int offsetX, int offsetY, int width, int height) {
checkRecycled();
nativeTexImage(mNativePtr, mFormat, init, offsetX, offsetY, width, height);
nativeTexImage(mNativePtr, init, offsetX, offsetY, width, height);
}
/**
@@ -182,7 +182,7 @@ public final class Image {
*/
public void advance() {
checkRecycled();
nativeAdvance(mNativePtr, mFormat);
nativeAdvance(mNativePtr);
}
/**
@@ -190,7 +190,7 @@ public final class Image {
*/
public int getDelay() {
checkRecycled();
int delay = nativeGetDelay(mNativePtr, mFormat);
int delay = nativeGetDelay(mNativePtr);
return delay <= 10 ? 100 : delay;
}
@@ -199,23 +199,7 @@ public final class Image {
*/
public boolean isOpaque() {
checkRecycled();
return nativeIsOpaque(mNativePtr, mFormat);
}
/**
* Return {@code true} if the image is gray.
*/
public boolean isGray(int error) {
checkRecycled();
return nativeIsGray(mNativePtr, mFormat, error);
}
/**
* Improves contrast in this image with CLAHE.
*/
public void clahe(boolean toGray) {
checkRecycled();
nativeClahe(mNativePtr, mFormat, toGray);
return nativeIsOpaque(mNativePtr);
}
/**
@@ -225,10 +209,10 @@ public final class Image {
*/
public void recycle() {
if (mNativePtr != 0) {
nativeRecycle(mNativePtr, mFormat);
nativeRecycle(mNativePtr);
mNativePtr = 0;
sImageCount.getAndDecrement();
imageList.remove(this);
mRecycleTracker = new Throwable("It's a ImageRecycleTracker");
}
@@ -45,7 +45,6 @@ public final class ImageBitmap implements Animatable, Runnable {
private final Bitmap mBitmap;
private final int mFormat;
private final boolean mIsOpaque;
private final int mByteCount;
private final Set<WeakReference<Callback>> mCallbackSet = new LinkedHashSet<>();
@Nullable
private Image mImage;
@@ -60,7 +59,6 @@ public final class ImageBitmap implements Animatable, Runnable {
image.render(0, 0, mBitmap, 0, 0, width, height, false, 0);
mFormat = image.getFormat();
mIsOpaque = image.isOpaque();
mByteCount = image.getByteCount();
if (mFormat == 1) {
// For animated image, save image object
@@ -75,7 +73,6 @@ public final class ImageBitmap implements Animatable, Runnable {
mFormat = Image.FORMAT_NORMAL;
mBitmap = bitmap;
mIsOpaque = !bitmap.hasAlpha();
mByteCount = bitmap.getRowBytes() * bitmap.getHeight();
}
/**
@@ -221,13 +218,6 @@ public final class ImageBitmap implements Animatable, Runnable {
return mIsOpaque;
}
/**
* Return byte count of image
*/
public int getByteCount() {
return mByteCount;
}
/**
* Return image is animated
*/
+26 -24
View File
@@ -43,21 +43,27 @@ static char *passwd = NULL;
static void *archiveAddr = NULL;
static jlong archiveSize = 0;
const char supportExt[9][6] = {
"jpeg",
"jpg",
"png",
"gif",
"webp",
"bmp",
"ico",
"wbmp",
"heif"
};
static int filename_is_playable_file(const char *name) {
const char *dotptr = strrchr(name, '.');
if (dotptr++) {
switch (*dotptr) {
case 'j':
return (strcmp(dotptr, "jpg") == 0) || (strcmp(dotptr, "jpeg") == 0);
case 'p':
return strcmp(dotptr, "png") == 0;
case 'g':
return strcmp(dotptr, "gif") == 0;
default:
return 0;
}
}
return 0;
if (!dotptr++)
return false;
int i;
for (i = 0; i < 9; i++)
if (strcmp(dotptr, supportExt[i]) == 0)
return true;
return false;
}
static long archive_list_all_entries() {
@@ -111,7 +117,6 @@ Java_com_hippo_UriArchiveAccessor_openArchive(JNIEnv *_, jobject thiz, jlong add
need_encrypt = true;
break;
case 0: // format supports but no encrypted entry found
case ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW: // Sometimes we might not read through whole file|vm, but it means so far we haven't meet any encrypted entry yet
default:
need_encrypt = false;
}
@@ -122,7 +127,7 @@ Java_com_hippo_UriArchiveAccessor_openArchive(JNIEnv *_, jobject thiz, jlong add
}
typedef struct Memarea {
void* buffer;
void *buffer;
long size;
} Memarea;
@@ -134,20 +139,18 @@ Java_com_hippo_UriArchiveAccessor_extracttoOutputStream(JNIEnv *_, jobject thiz,
archive_alloc();
cur_index = 0;
}
Memarea* memarea = malloc(sizeof(Memarea));
Memarea *memarea = malloc(sizeof(Memarea));
while (archive_read_next_header(arc, &entry) == ARCHIVE_OK) {
if (!filename_is_playable_file(archive_entry_pathname(entry)))
continue;
if (cur_index++ == index) {
memarea->size = archive_entry_size(entry);
memarea->buffer = malloc(memarea->size);
for (;;) {
ret = archive_read_data(arc, memarea->buffer, memarea->size);
if (ret < 0) {
LOGE("%s%s", "Archive read failed:", archive_error_string(arc));
}
break;
}
ret = archive_read_data(arc, memarea->buffer, memarea->size);
if (ret != memarea->size)
LOGE("%s", "No enough data read, WTF?");
if (ret < 0)
LOGE("%s%s", "Archive read failed:", archive_error_string(arc));
break;
}
}
@@ -174,7 +177,6 @@ Java_com_hippo_UriArchiveAccessor_providePassword(JNIEnv *_, jobject thiz, jstri
free(passwd);
passwd = calloc(len, sizeof(char));
strcpy(passwd, (*env)->GetStringUTFChars(env, str, NULL));
LOGI("%s%s", "Passwd is ", passwd);
archive_alloc();
while (archive_read_next_header(arc, &entry) == ARCHIVE_OK) {
if (!filename_is_playable_file(archive_entry_pathname(entry)))
-2
View File
@@ -18,8 +18,6 @@ project(image C)
set(IMAGE_SOURCES
image.c
image_utils.c
filter/clahe.c
filter/gray.c
java_wrapper.c
)
set(IMAGE_INCLUDES
-186
View File
@@ -1,186 +0,0 @@
/*
* Copyright 2018 Hippo Seven
*
* 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 "clahe.h"
#include "pixel.h"
#include "../utils.h"
#include "../log.h"
#define TILE_BLOCK 8
#define LIMIT_MULTIPLE 4
#define CL_MAX_LOOP_NUMBER 4
static BYTE clamp(int t) {
t = t > 255 ? 255 : t;
t = t < 0 ? 0 : t;
return (BYTE) t;
}
void IMAGE_clahe(void *data, int width, int height, bool to_gray) {
if (width < TILE_BLOCK || height < TILE_BLOCK) {
return;
}
PIXEL *pixels = data;
if (to_gray) {
for (int i = 0; i < width * height; ++i) {
PIXEL *p = pixels + i;
int t1 = (int) (p->c1 * 0.299f + p->c2 * 0.587f + p->c3 * 0.114f);
p->c1 = clamp(t1);
}
} else {
// RGBA to YUVA
for (int i = 0; i < width * height; ++i) {
PIXEL *p = pixels + i;
int t1 = (int) (p->c1 * 0.299f + p->c2 * 0.587f + p->c3 * 0.114f);
int t2 = (int) (p->c1 * -0.169f + p->c2 * -0.331f + p->c3 * 0.5f + 128);
int t3 = (int) (p->c1 * 0.5f + p->c2 * -0.419f + p->c3 * -0.081f + 128);
p->c1 = clamp(t1);
p->c2 = clamp(t2);
p->c3 = clamp(t3);
}
}
int tile_width = width / TILE_BLOCK;
int tile_height = height / TILE_BLOCK;
int histogram[TILE_BLOCK * TILE_BLOCK][256] = {0};
float accumulation[TILE_BLOCK * TILE_BLOCK][256] = {0.0f};
// Build histogram and accumulation
for (int i = 0; i < TILE_BLOCK; i++) {
for (int j = 0; j < TILE_BLOCK; j++) {
int x_start = tile_width * i;
int x_end = i == TILE_BLOCK - 1 ? width : x_start + tile_width;
int y_start = tile_height * j;
int y_end = j == TILE_BLOCK - 1 ? height : y_start + tile_height;
int tile_size = (x_end - x_start) * (y_end - y_start);
int tile_index = i + TILE_BLOCK * j;
// Count
for (int x = x_start; x < x_end; x++) {
for (int y = y_start; y < y_end; y++) {
PIXEL *p = pixels + x + y * width;
histogram[tile_index][p->c1] += 1;
}
}
// CL
int limit = tile_size * LIMIT_MULTIPLE / 256;
for (int m = 0; m < CL_MAX_LOOP_NUMBER; m++) {
int steal = 0;
for (int n = 0; n < 256; n++) {
if (histogram[tile_index][n] > limit) {
steal += histogram[tile_index][n] - limit;
histogram[tile_index][n] = limit;
}
}
int bonus = steal / 256;
if (bonus == 0 && steal != 0 && m == 0) {
bonus = 1;
}
if (bonus == 0) {
break;
}
for (int n = 0; n < 256; n++) {
histogram[tile_index][n] += bonus;
}
}
// accumulation
for (int n = 0; n < 256; n++) {
accumulation[tile_index][n] = (float) histogram[tile_index][n] / tile_size;
if (n != 0) {
accumulation[tile_index][n] += accumulation[tile_index][n - 1];
}
}
}
}
// Interpolation
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
PIXEL *p = pixels + x + y * width;
// top-left corner
if (x <= tile_width / 2 && y <= tile_height / 2) {
p->c1 = clamp((int) (accumulation[0][p->c1] * 255));
continue;
}
// top-right corner
if (x > width - tile_width / 2 && y <= tile_height / 2) {
p->c1 = clamp((int) (accumulation[TILE_BLOCK - 1][p->c1] * 255));
continue;
}
// bottom-left corner
if (x <= tile_width / 2 && y > height - tile_height / 2) {
p->c1 = clamp((int) (accumulation[TILE_BLOCK * (TILE_BLOCK - 1)][p->c1] * 255));
continue;
}
// bottom-right corner
if (x > width - tile_width / 2 && y > height - tile_height / 2) {
p->c1 = clamp((int) (accumulation[TILE_BLOCK * TILE_BLOCK - 1][p->c1] * 255));
continue;
}
int tile_x_index = (x - tile_width / 2) / tile_width;
int tile_y_index = (y - tile_height / 2) / tile_height;
int tile_index1 = tile_x_index + TILE_BLOCK * tile_y_index;
int tile_index2 = tile_index1 + 1;
float u = (float) (x - (tile_x_index * tile_width + tile_width / 2)) / tile_width;
// top side and bottom side
if (y <= tile_height / 2 || y > height - tile_height / 2) {
p->c1 = clamp((int) (255 * (accumulation[tile_index1][p->c1] * (1 - u) +
accumulation[tile_index2][p->c1] * u)));
continue;
}
int tile_index3 = tile_index1 + TILE_BLOCK;
float v = (float) (y - (tile_y_index * tile_height + tile_height / 2)) / tile_height;
// left side and right side
if (x <= tile_width / 2 || x > width - tile_width / 2) {
p->c1 = clamp((int) (255 * (accumulation[tile_index1][p->c1] * (1 - v) +
accumulation[tile_index3][p->c1] * v)));
continue;
}
int tile_index4 = tile_index2 + TILE_BLOCK;
p->c1 = clamp((int) (255 * (
accumulation[tile_index1][p->c1] * (1 - u) * (1 - v)
+ accumulation[tile_index2][p->c1] * u * (1 - v)
+ accumulation[tile_index3][p->c1] * (1 - u) * v
+ accumulation[tile_index4][p->c1] * u * v)));
}
}
if (to_gray) {
for (int i = 0; i < width * height; ++i) {
PIXEL *p = pixels + i;
p->c2 = p->c1;
p->c3 = p->c1;
}
} else {
// YUVA to RGBA
for (int i = 0; i < width * height; ++i) {
PIXEL *p = pixels + i;
int t1 = (int) (p->c1 + (p->c2 - 128) * -0.00093f + (p->c3 - 128) * 1.401687f);
int t2 = (int) (p->c1 + (p->c2 - 128) * -0.3437f + (p->c3 - 128) * -0.71417f);
int t3 = (int) (p->c1 + (p->c2 - 128) * 1.77216f + (p->c3 - 128) * 0.00099f);
p->c1 = clamp(t1);
p->c2 = clamp(t2);
p->c3 = clamp(t3);
}
}
}
-24
View File
@@ -1,24 +0,0 @@
/*
* Copyright 2018 Hippo Seven
*
* 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 IMAGE_CLAHE_H
#define IMAGE_CLAHE_H
#include <stdbool.h>
void IMAGE_clahe(void *data, int width, int height, bool to_gray);
#endif //IMAGE_CLAHE_H
-36
View File
@@ -1,36 +0,0 @@
/*
* Copyright 2019 Hippo Seven
*
* 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 "gray.h"
#include "pixel.h"
bool IMAGE_is_gray(void *data, int width, int height, int error) {
PIXEL *p = data;
for (int i = 0, n = width * height; i < n; i++, p++) {
int e1 = p->c1 - p->c2;
int e2 = p->c1 - p->c3;
int e3 = p->c2 - p->c3;
if (e1 > error || e1 < -error
|| e2 > error || e2 < -error
|| e3 > error || e3 < -error) {
return false;
}
}
return true;
}
-24
View File
@@ -1,24 +0,0 @@
/*
* Copyright 2019 Hippo Seven
*
* 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 IMAGE_GRAY_H
#define IMAGE_GRAY_H
#include <stdbool.h>
bool IMAGE_is_gray(void *data, int width, int height, int error);
#endif //IMAGE_GRAY_H
-29
View File
@@ -1,29 +0,0 @@
/*
* Copyright 2019 Hippo Seven
*
* 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 IMAGE_PIXEL_H
#define IMAGE_PIXEL_H
typedef unsigned char BYTE;
typedef struct {
BYTE c1;
BYTE c2;
BYTE c3;
BYTE c4;
} PIXEL;
#endif //IMAGE_PIXEL_H
+53 -135
View File
@@ -1,36 +1,33 @@
/*
* Copyright 2015 Hippo Seven
* Copyright 2022 Tarsin Norbin
*
* 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
* This file is part of EhViewer
*
* http://www.apache.org/licenses/LICENSE-2.0
* EhViewer is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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.
* EhViewer is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* EhViewer. If not, see <https://www.gnu.org/licenses/>.
*/
//
// Created by Hippo on 12/27/2015.
//
#include <android/data_space.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "image.h"
#include "image_utils.h"
#include "filter/clahe.h"
#include "filter/gray.h"
#include "log.h"
void decodeCommon(IMAGE *image) {
AImageDecoder *decoder = image->decoder;
void decodeCommon(IMAGE *image, SOURCE *src) {
image->src = src;
AImageDecoder *decoder = src->decoder;
image->isAnimated = AImageDecoder_isAnimated(decoder);
AImageDecoder_setDataSpace(decoder, ADATASPACE_SRGB);
AImageDecoder_setAndroidBitmapFormat(decoder, ANDROID_BITMAP_FORMAT_RGBA_8888);
const AImageDecoderHeaderInfo *headerInfo = AImageDecoder_getHeaderInfo(decoder);
@@ -38,155 +35,76 @@ void decodeCommon(IMAGE *image) {
image->width = AImageDecoderHeaderInfo_getWidth(headerInfo);
image->alpha =
AImageDecoderHeaderInfo_getAlphaFlags(headerInfo) == ANDROID_BITMAP_FLAGS_ALPHA_PREMUL;
image->stride = AImageDecoder_getMinimumStride(decoder);
image->bufferLen = image->height * image->stride;
src->stride = AImageDecoder_getMinimumStride(decoder);
image->bufferLen = (int) (image->height * src->stride);
image->buffer = malloc(image->bufferLen);
if (image->isAnimated) {
AImageDecoder_setInternallyHandleDisposePrevious(decoder, false);
image->frameInfo = AImageDecoderFrameInfo_create();
AImageDecoder_getFrameInfo(decoder, image->frameInfo);
AImageDecoderFrameInfo *frameInfo = AImageDecoderFrameInfo_create();
AImageDecoder_getFrameInfo(decoder, frameInfo);
image->delay = (int) AImageDecoderFrameInfo_getDuration(frameInfo) / 1000000;
AImageDecoderFrameInfo_delete(frameInfo);
}
AImageDecoder_decodeImage(decoder, image->buffer, src->stride, image->bufferLen);
if (!image->isAnimated) {
recycleSource(image->src);
image->src = NULL;
}
AImageDecoder_decodeImage(decoder, image->buffer, image->stride, image->bufferLen);
}
IMAGE *createFromFd(JNIEnv *env, int fd, bool partially, int *format) {
IMAGE *createFromFd(int fd) {
AImageDecoder *decoder;
int r = AImageDecoder_createFromFd(fd, &decoder);
LOGD("%s%d", "Create ImageDecoder with ret ", r);
if (r)
return NULL;
AImageDecoder_createFromFd(fd, &decoder);
IMAGE *image = calloc(1, sizeof(IMAGE));
image->isAnimated = *format = AImageDecoder_isAnimated(decoder);
image->decoder = decoder;
decodeCommon(image);
SOURCE *src = calloc(1, sizeof(SOURCE));
src->decoder = decoder;
src->fd = fd;
decodeCommon(image, src);
return image;
}
IMAGE *createFromAddr(JNIEnv *env, void *addr, long size, bool partially, int *format) {
IMAGE *createFromAddr(void *addr, long size) {
AImageDecoder *decoder;
int r = AImageDecoder_createFromBuffer((const void *) addr, size, &decoder);
LOGD("%s%d", "Create ImageDecoder with ret ", r);
if (r)
return NULL;
AImageDecoder_createFromBuffer((const void *) addr, size, &decoder);
IMAGE *image = calloc(1, sizeof(IMAGE));
image->isAnimated = *format = AImageDecoder_isAnimated(decoder);
image->decoder = decoder;
image->srcBuffer = addr;
decodeCommon(image);
SOURCE *src = calloc(1, sizeof(SOURCE));
src->decoder = decoder;
src->srcBuffer = addr;
decodeCommon(image, src);
return image;
}
void *create(int32_t width, int32_t height, const void *data) {
IMAGE *plain = NULL;
IMAGE *create(int32_t width, int32_t height, const void *data) {
IMAGE *plain = calloc(1, sizeof(IMAGE));
void *buffer = NULL;
size_t length;
plain = malloc(sizeof(IMAGE));
if (plain == NULL) {
WTF_OM;
return NULL;
}
length = (size_t) (width * height * 4);
size_t length = width * height * 4;
buffer = malloc(length);
if (buffer == NULL) {
WTF_OM;
free(plain);
return NULL;
}
memcpy(buffer, data, length);
plain->width = width;
plain->height = height;
plain->buffer = buffer;
plain->bufferLen = length;
plain->decoder = NULL;
plain->bufferLen = (int) length;
return plain;
}
int get_width(IMAGE *image, int format) {
return image->width;
}
int get_height(IMAGE *image, int format) {
return image->height;
}
int get_byte_count(IMAGE *image, int format) {
return image->bufferLen;
}
void render(IMAGE *image, int format, int src_x, int src_y,
void render(IMAGE *image, int src_x, int src_y,
void *dst, int dst_w, int dst_h, int dst_x, int dst_y,
int width, int height, bool fill_blank, int default_color) {
int width, int height) {
copy_pixels(image->buffer, image->width, image->height, src_x, src_y, dst, dst_w, dst_h, dst_x,
dst_y, width, height, fill_blank, default_color);
dst_y, width, height);
}
void advance(IMAGE *image, int format) {
if (format) {
AImageDecoder_advanceFrame(image->decoder);
if (AImageDecoder_decodeImage(image->decoder, image->buffer, image->stride,
void advance(IMAGE *image) {
if (image->isAnimated) {
AImageDecoder_advanceFrame(image->src->decoder);
if (AImageDecoder_decodeImage(image->src->decoder, image->buffer, image->src->stride,
image->bufferLen) == ANDROID_IMAGE_DECODER_FINISHED) {
AImageDecoder_rewind(image->decoder);
AImageDecoder_decodeImage(image->decoder, image->buffer, image->stride,
AImageDecoder_rewind(image->src->decoder);
AImageDecoder_decodeImage(image->src->decoder, image->buffer, image->src->stride,
image->bufferLen);
}
}
}
int get_delay(IMAGE *image, int format) {
if (format)
return AImageDecoderFrameInfo_getDuration(image->frameInfo) / 1000000;
return 0;
}
bool is_opaque(IMAGE *image, int format) {
return image->alpha;
}
static void get_image_data(IMAGE *image, int format, void **pixel, int *width, int *height) {
*pixel = image->buffer;
*width = image->width;
*height = image->height;
}
bool is_gray(IMAGE *image, int format, int error) {
void *pixel = NULL;
int width = 0;
int height = 0;
get_image_data(image, format, &pixel, &width, &height);
if (pixel == NULL || width == 0 || height == 0) {
return false;
}
return IMAGE_is_gray(pixel, width, height, error);
}
void clahe(IMAGE *image, int format, bool to_gray) {
void *pixel = NULL;
int width = 0;
int height = 0;
get_image_data(image, format, &pixel, &width, &height);
if (pixel == NULL || width == 0 || height == 0) {
return;
}
IMAGE_clahe(pixel, width, height, to_gray);
}
void recycle(JNIEnv *env, IMAGE *image, int format) {
free(image->buffer);
image->buffer = NULL;
AImageDecoderFrameInfo_delete(image->frameInfo);
AImageDecoder_delete(image->decoder);
free(image->srcBuffer);
free(image);
}
+43 -40
View File
@@ -1,69 +1,72 @@
/*
* Copyright 2015 Hippo Seven
* Copyright 2022 Tarsin Norbin
*
* 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
* This file is part of EhViewer
*
* http://www.apache.org/licenses/LICENSE-2.0
* EhViewer is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* 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.
* EhViewer is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* EhViewer. If not, see <https://www.gnu.org/licenses/>.
*/
//
// Created by Hippo on 12/27/2015.
//
#ifndef IMAGE_IMAGE_H
#define IMAGE_IMAGE_H
#include <android/imagedecoder.h>
#include <stdbool.h>
#include <jni.h>
typedef struct {
AImageDecoder *decoder;
void *srcBuffer;
size_t stride;
int fd;
} SOURCE;
typedef struct {
int32_t width;
int32_t height;
void *buffer;
int bufferLen;
AImageDecoder *decoder;
void *srcBuffer;
size_t stride;
bool isAnimated;
AImageDecoderFrameInfo *frameInfo;
bool alpha;
int delay;
SOURCE *src;
} IMAGE;
IMAGE *createFromFd(JNIEnv *env, int fd, bool partially, int *format);
static void recycleSource(SOURCE *src) {
if (!src)
return;
AImageDecoder_delete(src->decoder);
free(src->srcBuffer);
free(src);
}
IMAGE *createFromAddr(JNIEnv *env, void *addr, long size, bool partially, int *format);
static void recycle(IMAGE *image) {
if (!image)
return;
recycleSource(image->src);
free(image->buffer);
free(image);
}
void *create(int32_t width, int32_t height, const void *data);
IMAGE *createFromFd(int fd);
int get_width(IMAGE *image, int format);
IMAGE *createFromAddr(void *addr, long size);
int get_height(IMAGE *image, int format);
IMAGE *create(int32_t width, int32_t height, const void *data);
int get_byte_count(IMAGE *image, int format);
void render(IMAGE *image, int format, int src_x, int src_y,
void render(IMAGE *image, int src_x, int src_y,
void *dst, int dst_w, int dst_h, int dst_x, int dst_y,
int width, int height, bool fill_blank, int default_color);
int width, int height);
void advance(IMAGE *image, int format);
void advance(IMAGE *image);
int get_delay(IMAGE *image, int format);
bool is_opaque(IMAGE *image, int format);
bool is_gray(IMAGE *image, int format, int error);
void clahe(IMAGE *image, int format, bool to_gray);
void recycle(JNIEnv *env, IMAGE *image, int format);
#endif //IMAGE_IMAGE_H
#endif /* IMAGE_IMAGE_H */
+3 -79
View File
@@ -14,64 +14,14 @@
* limitations under the License.
*/
//
// Created by Hippo on 12/27/2015.
//
#include "image_utils.h"
#include <stdlib.h>
#include <string.h>
#define LITTLE_ENDIAN 0x00
#define BIG_ENDIAN 0x01
static unsigned int endian = ~0U;
static unsigned int get_endian() {
unsigned int x = 1;
if (endian == ~0U) {
if (1 == ((char *) &x)[0]) {
endian = LITTLE_ENDIAN;
} else {
endian = BIG_ENDIAN;
}
}
return endian;
}
static int convert_color(int origin) {
int result;
unsigned char *orPtr = (unsigned char *) &origin;
unsigned char *rePtr = (unsigned char *) &result;
if (get_endian() == BIG_ENDIAN) {
rePtr[0] = orPtr[1];
rePtr[1] = orPtr[2];
rePtr[2] = orPtr[3];
rePtr[3] = orPtr[0];
} else {
rePtr[0] = orPtr[2];
rePtr[1] = orPtr[1];
rePtr[2] = orPtr[0];
rePtr[3] = orPtr[3];
}
return result;
}
static void memset_int(int *dst, int val, size_t size) {
int *maxPtr = dst + size;
int *ptr = dst;
while (ptr < maxPtr)
*ptr++ = val;
}
bool copy_pixels_internal(const void *src, int src_w, int src_h, int src_x, int src_y,
void *dst, int dst_w, int dst_h, int dst_x, int dst_y,
int width, int height, bool fill_blank, int color) {
bool copy_pixels(const void *src, int src_w, int src_h, int src_x, int src_y,
void *dst, int dst_w, int dst_h, int dst_x, int dst_y,
int width, int height) {
int left;
int line;
size_t line_stride;
@@ -137,10 +87,6 @@ bool copy_pixels_internal(const void *src, int src_w, int src_h, int src_x, int
dst_pos = 0;
dst_blank_length = (size_t) (dst_y * dst_w + dst_x) * 4;
// Fill start blank if necessary
if (fill_blank) {
memset_int((int *) (dst + dst_pos), color, dst_blank_length / 4);
}
// First line
dst_pos += dst_blank_length;
@@ -151,33 +97,11 @@ bool copy_pixels_internal(const void *src, int src_w, int src_h, int src_x, int
// Other lines
dst_blank_length = (size_t) ((dst_w - width) * 4);
for (line = 1; line < height; line++) {
if (fill_blank) {
memset_int((int *) (dst + dst_pos), color, dst_blank_length / 4);
}
dst_pos += dst_blank_length;
memcpy(dst + dst_pos, src + src_pos, line_stride);
dst_pos += line_stride;
src_pos += src_stride;
}
// Fill left blank if necessary
if (fill_blank) {
memset_int((int *) (dst + dst_pos), color, (size_t) (dst_w * dst_h * 4 - dst_pos) / 4);
}
return true;
}
void copy_pixels(const void *src, int src_w, int src_h, int src_x, int src_y,
void *dst, int dst_w, int dst_h, int dst_x, int dst_y,
int width, int height, bool fill_blank, int default_color) {
int color = 0;
if (fill_blank) {
color = convert_color(default_color);
}
if (!copy_pixels_internal(src, src_w, src_h, src_x, src_y, dst, dst_w, dst_h, dst_x,
dst_y, width, height, fill_blank, color) && fill_blank) {
memset_int(dst, color, (size_t) (dst_w * dst_h));
}
}
+3 -7
View File
@@ -17,17 +17,13 @@
* EhViewer. If not, see <https://www.gnu.org/licenses/>.
*/
//
// Created by Hippo on 12/27/2015.
//
#ifndef IMAGE_IMAGE_UTILS_H
#define IMAGE_IMAGE_UTILS_H
#include <stdbool.h>
void copy_pixels(const void *src, int src_w, int src_h, int src_x, int src_y,
bool copy_pixels(const void *src, int src_w, int src_h, int src_x, int src_y,
void *dst, int dst_w, int dst_h, int dst_x, int dst_y,
int width, int height, bool fill_blank, int default_color);
int width, int height);
#endif //IMAGE_IMAGE_UTILS_H
#endif /* IMAGE_IMAGE_UTILS_H */
+39 -170
View File
@@ -17,14 +17,13 @@
#include <stdlib.h>
#include <android/bitmap.h>
#include <GLES2/gl2.h>
#include <jni.h>
#include "java_wrapper.h"
#include "image.h"
#include "log.h"
static JavaVM *jvm;
static void *tile_buffer;
static void *tile_buffer = NULL;
static int jniGetFDFromFileDescriptor(JNIEnv *env, jobject fileDescriptor) {
jint fd = -1;
@@ -40,240 +39,110 @@ static int jniGetFDFromFileDescriptor(JNIEnv *env, jobject fileDescriptor) {
return fd;
}
JNIEnv *obtain_env(bool *attach) {
JNIEnv *env;
switch ((*jvm)->GetEnv(jvm, (void **) &env, JNI_VERSION_1_6)) {
case JNI_EDETACHED:
if ((*jvm)->AttachCurrentThread(jvm, &env, NULL) == JNI_OK) {
*attach = true;
return env;
} else {
return NULL;
}
case JNI_OK:
*attach = false;
return env;
default:
case JNI_EVERSION:
return NULL;
}
}
void release_env() {
(*jvm)->DetachCurrentThread(jvm);
}
jobject create_image_object(JNIEnv *env, void *ptr, int format, int width, int height) {
jclass image_clazz;
jmethodID constructor;
image_clazz = (*env)->FindClass(env, "com/hippo/image/Image");
constructor = (*env)->GetMethodID(env, image_clazz, "<init>", "(JIII)V");
if (constructor == 0) {
LOGE(MSG("Can't find Image object constructor"));
return NULL;
} else {
return (*env)->NewObject(env, image_clazz, constructor,
(jlong) (uintptr_t) ptr, (jint) format, (jint) width,
(jint) height);
}
return (*env)->NewObject(env, image_clazz, constructor,
(jlong) (uintptr_t) ptr, (jint) format, (jint) width,
(jint) height);
}
JNIEXPORT jobject JNICALL
Java_com_hippo_image_Image_nativeDecodeFdInt(JNIEnv *env,
jclass clazz, jint fd, jboolean partially) {
int format;
void *image;
jobject image_object;
image = createFromFd(env, fd, partially, &format);
if (image == NULL) {
return NULL;
}
image_object = create_image_object(env, image, format,
get_width(image, format), get_height(image, format));
if (image_object == NULL) {
recycle(env, image, format);
return NULL;
} else {
return image_object;
}
Java_com_hippo_image_Image_nativeDecodeFdInt(JNIEnv *env, jclass clazz, jint fd) {
IMAGE *image = createFromFd(fd);
return create_image_object(env, image, image->isAnimated, image->width, image->height);
}
JNIEXPORT jobject JNICALL
Java_com_hippo_image_Image_nativeDecode(JNIEnv *env,
jclass clazz, jobject fd, jboolean partially) {
Java_com_hippo_image_Image_nativeDecode(JNIEnv *env, jclass clazz, jobject fd) {
return Java_com_hippo_image_Image_nativeDecodeFdInt(env, clazz,
jniGetFDFromFileDescriptor(env, fd),
partially);
jniGetFDFromFileDescriptor(env, fd));
}
JNIEXPORT jobject JNICALL
Java_com_hippo_image_Image_nativeCreate(JNIEnv *env,
jclass clazz, jobject bitmap) {
Java_com_hippo_image_Image_nativeCreate(JNIEnv *env, jclass clazz, jobject bitmap) {
AndroidBitmapInfo info;
void *pixels = NULL;
void *image = NULL;
jobject image_object;
AndroidBitmap_getInfo(env, bitmap, &info);
AndroidBitmap_lockPixels(env, bitmap, &pixels);
if (pixels == NULL) {
LOGE(MSG("Can't lock bitmap pixels"));
return NULL;
}
image = create(info.width, info.height, pixels);
AndroidBitmap_unlockPixels(env, bitmap);
if (image == NULL) {
return NULL;
}
image_object = create_image_object(env, image, 0,
info.width, info.height);
if (image_object == NULL) {
recycle(env, image, 0);
return NULL;
} else {
return image_object;
}
}
JNIEXPORT jint JNICALL
Java_com_hippo_image_Image_nativeGetByteCount(JNIEnv *env,
jclass clazz, jlong ptr, jint format) {
return (jint) get_byte_count((void *) (intptr_t) ptr, format);
return create_image_object(env, image, 0, info.width, info.height);
}
JNIEXPORT void JNICALL
Java_com_hippo_image_Image_nativeRender(JNIEnv *env,
jclass clazz, jlong ptr, jint format,
jint src_x, jint src_y, jobject dst, jint dst_x, jint dst_y,
jint width, jint height, jboolean fill_blank,
jint default_color) {
Java_com_hippo_image_Image_nativeRender(JNIEnv *env, jclass clazz, jlong ptr, jint src_x,
jint src_y, jobject dst, jint dst_x, jint dst_y, jint width,
jint height) {
AndroidBitmapInfo info;
void *pixels = NULL;
AndroidBitmap_getInfo(env, dst, &info);
AndroidBitmap_lockPixels(env, dst, &pixels);
if (pixels == NULL) {
LOGE(MSG("Can't lock bitmap pixels"));
return;
}
render((void *) (intptr_t) ptr, format, src_x, src_y,
pixels, info.width, info.height, dst_x, dst_y,
width, height, fill_blank, default_color);
render((IMAGE *) ptr, src_x, src_y, pixels, info.width, info.height, dst_x, dst_y, width,
height);
AndroidBitmap_unlockPixels(env, dst);
return;
}
JNIEXPORT void JNICALL
Java_com_hippo_image_Image_nativeTexImage(JNIEnv *env,
jclass clazz, jlong ptr, jint format, jboolean init,
Java_com_hippo_image_Image_nativeTexImage(JNIEnv *env, jclass clazz, jlong ptr, jboolean init,
jint src_x, jint src_y, jint width, jint height) {
// Check tile_buffer NULL
if (NULL == tile_buffer) {
if (width * height > IMAGE_TILE_MAX_SIZE)
return;
}
// Check render size
if (width * height > IMAGE_TILE_MAX_SIZE) {
return;
}
render((void *) (intptr_t) ptr, format, src_x, src_y,
tile_buffer, width, height, 0, 0,
width, height, false, 0);
render((IMAGE *) ptr, src_x, src_y, tile_buffer, width, height, 0, 0, width, height);
if (init) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height,
0, GL_RGBA, GL_UNSIGNED_BYTE, tile_buffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
tile_buffer);
} else {
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height,
GL_RGBA, GL_UNSIGNED_BYTE, tile_buffer);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE,
tile_buffer);
}
}
JNIEXPORT void JNICALL
Java_com_hippo_image_Image_nativeAdvance(JNIEnv *env,
jclass clazz, jlong ptr, jint format) {
advance((void *) (intptr_t) ptr, format);
Java_com_hippo_image_Image_nativeAdvance(JNIEnv *env, jclass clazz, jlong ptr) {
advance((IMAGE *) ptr);
}
JNIEXPORT jint JNICALL
Java_com_hippo_image_Image_nativeGetDelay(JNIEnv *env,
jclass clazz, jlong ptr, jint format) {
return (jint) get_delay((void *) (intptr_t) ptr, format);
Java_com_hippo_image_Image_nativeGetDelay(JNIEnv *env, jclass clazz, jlong ptr) {
return ((IMAGE *) ptr)->delay;
}
JNIEXPORT jboolean JNICALL
Java_com_hippo_image_Image_nativeIsOpaque(JNIEnv *env,
jclass clazz, jlong ptr, jint format) {
return (jboolean) is_opaque((void *) (intptr_t) ptr, format);
}
JNIEXPORT jboolean JNICALL
Java_com_hippo_image_Image_nativeIsGray(JNIEnv *env,
jclass clazz, jlong ptr, jint format, jint error) {
return (jboolean) is_gray((void *) (intptr_t) ptr, format, error);
Java_com_hippo_image_Image_nativeIsOpaque(JNIEnv *env, jclass clazz, jlong ptr) {
return ((IMAGE *) ptr)->alpha;
}
JNIEXPORT void JNICALL
Java_com_hippo_image_Image_nativeClahe(JNIEnv *env,
jclass clazz, jlong ptr, jint format, jboolean to_gray) {
clahe((void *) (intptr_t) ptr, format, to_gray);
Java_com_hippo_image_Image_nativeRecycle(JNIEnv *env, jclass clazz, jlong ptr) {
recycle((IMAGE *) ptr);
}
JNIEXPORT void JNICALL
Java_com_hippo_image_Image_nativeRecycle(JNIEnv *env,
jclass clazz, jlong ptr, jint format) {
recycle(env, (void *) (intptr_t) ptr, format);
}
bool image_onLoad(JavaVM *vm) {
jvm = vm;
bool image_onLoad() {
tile_buffer = malloc(IMAGE_TILE_MAX_SIZE * 4);
return true;
return tile_buffer != NULL;
}
JNIEXPORT void JNICALL
JNI_OnUnload(JavaVM *vm, void *reserved) {
void image_onUnload() {
free(tile_buffer);
tile_buffer = NULL;
}
typedef struct Memarea {
void *buffer;
long size;
} Memarea;
JNIEXPORT jobject JNICALL
Java_com_hippo_image_Image_nativeDecodeAddr(JNIEnv *env, jclass clazz, jlong addr,
jboolean partially) {
int format;
void *image;
jobject image_object;
Java_com_hippo_image_Image_nativeDecodeAddr(JNIEnv *env, jclass clazz, jlong addr) {
Memarea *memarea = (Memarea *) addr;
image = createFromAddr(env, memarea->buffer, memarea->size, partially, &format);
IMAGE *image = createFromAddr(memarea->buffer, memarea->size);
free(memarea);
if (image == NULL) {
return NULL;
}
image_object = create_image_object(env, image, format,
get_width(image, format), get_height(image, format));
if (image_object == NULL) {
recycle(env, image, format);
return NULL;
} else {
return image_object;
}
}
return create_image_object(env, image, image->isAnimated, image->width, image->height);
}
+7 -9
View File
@@ -17,22 +17,20 @@
* EhViewer. If not, see <https://www.gnu.org/licenses/>.
*/
//
// Created by Hippo on 12/28/2015.
//
#ifndef IMAGE_JAVA_WRAPPER_H
#define IMAGE_JAVA_WRAPPER_H
#include <jni.h>
#include <stdbool.h>
#define IMAGE_TILE_MAX_SIZE (512 * 512)
bool image_onLoad(JavaVM *vm);
typedef struct Memarea {
void *buffer;
long size;
} Memarea;
JNIEnv *obtain_env(bool *attach);
bool image_onLoad();
void release_env();
void image_onUnload();
#endif // IMAGE_JAVA_WRAPPER_H
#endif /* IMAGE_JAVA_WRAPPER_H */
+2 -15
View File
@@ -14,18 +14,12 @@
* limitations under the License.
*/
//
// Created by Hippo on 10/19/2015.
//
#ifndef LOG_H
#define LOG_H
#include <android/log.h>
#include "utils.h"
#define TAG "Image"
#define TAG "ImageDecoder_wrapper"
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG ,__VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG ,__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG ,__VA_ARGS__)
@@ -33,11 +27,4 @@
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG ,__VA_ARGS__)
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL, TAG ,__VA_ARGS__)
#define FILE_LINE MAKESTRING(STRINGIZE, __LINE__ )
#define MSG(msg) __FILE__ "(" FILE_LINE "): "msg
#define OUT_OF_MEMORY "Out of memory"
#define WTF_OM LOGE(MSG(OUT_OF_MEMORY))
#endif //LOG_H
#endif /* LOG_H */
-30
View File
@@ -1,30 +0,0 @@
/*
* Copyright 2015 Hippo Seven
*
* 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.
*/
//
// Created by Hippo on 12/29/2015.
//
#ifndef UTILS_H
#define UTILS_H
#define STRINGIZE(L) #L
#define MAKESTRING(M, L) M(L)
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif // UTILS_H
+5
View File
@@ -39,6 +39,11 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
return JNI_VERSION_1_6;
}
JNIEXPORT void JNICALL
JNI_OnUnload(JavaVM *vm, void *reserved) {
image_onUnload();
}
JNIEXPORT jstring JNICALL
Java_com_hippo_Native_getlibarchiveVersion(JNIEnv *env, jclass clazz) {
return (*env)->NewStringUTF(env, ARCHIVE_VERSION_STRING);
+5
View File
@@ -1,4 +1,9 @@
{
"baseBranches": [
"1.8.x.x",
"1.7.x.x"
],
"extends": [
"config:base"
]