Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
162b88915e | ||
|
|
d014b6947c | ||
|
|
a6188964c9 | ||
|
|
722fbec72c | ||
|
|
22190fb686 | ||
|
|
49ea70c839 | ||
|
|
c655e7e1c9 | ||
|
|
d13cd1e07f | ||
|
|
7365fd0448 | ||
|
|
f1febca312 | ||
|
|
dbf67404c0 | ||
|
|
8cfe8c4b80 | ||
|
|
674f53315f | ||
|
|
e51cd6b90d | ||
|
|
a44f12b2e0 | ||
|
|
a2552ed5b9 | ||
|
|
763c007950 | ||
|
|
b221bf8e52 | ||
|
|
ab9a89685c | ||
|
|
41ccb16227 | ||
|
|
f6bf7b1ba6 | ||
|
|
09e7113df1 | ||
|
|
62a7e283a4 |
No files matched your search
@@ -34,9 +34,11 @@ with Material Design 3 and Dynamic Color Support
|
||||
|
||||
# Download
|
||||
|
||||
[Github 下载](https://github.com/Ehviewer-Overhauled/Ehviewer/releases)
|
||||
<a href="https://github.com/Ehviewer-Overhauled/Ehviewer/releases"><img alt="Get it on Google Play" src="art/get-it-on-github.svg" width="200px"/></a>
|
||||
|
||||
[CI 版本下载(需登录)](https://github.com/Ehviewer-Overhauled/Ehviewer/actions/workflows/ci.yml)
|
||||
App 分为 1.8 与 1.7 两个版本。1.8 版本适配 Android 12 及以上系统,为开发主线;1.7 版本适配 Android 11 及以下版本,削减了 Android 12 及以上系统的独有功能,使其能在低版本 Android 上正常工作
|
||||
|
||||
App is divided into two versions: 1.7 and 1.8 . Version 1.8 support Android 12 and above, also the develop mainline. Version 1.7 support Android 11 and below, drop down some spicetify functions for Android 12 to make app useable on lower Android System
|
||||
|
||||
# Screenshot
|
||||
|
||||
@@ -54,12 +56,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
@@ -34,8 +34,8 @@ android {
|
||||
applicationId "moe.tarsin.ehviewer"
|
||||
minSdkVersion 31
|
||||
targetSdkVersion 33
|
||||
versionCode 180000
|
||||
versionName "1.8.0.0"
|
||||
versionCode 180004
|
||||
versionName "1.8.0.4"
|
||||
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'
|
||||
|
||||
@@ -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()}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright 2022 Tarsin Norbin
|
||||
~
|
||||
~ This file is part of EhViewer
|
||||
~
|
||||
~ EhViewer is free software: you can redistribute it and/or modify it
|
||||
~ under the terms of the GNU GeneralPublic License as published
|
||||
~ by the Free Software Foundation,either version 3 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ 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/>.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="44dp"
|
||||
android:height="44dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<group
|
||||
android:scaleX="0.37947997"
|
||||
android:scaleY="0.37947997"
|
||||
android:translateX="35.1"
|
||||
android:translateY="39.584126">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M39.893,68.066L39.893,75.977L0,75.977L0,4.59L39.893,4.59L39.893,12.5L8.984,12.5L8.984,34.766L38.086,34.766L38.086,42.578L8.984,42.578L8.984,68.066L39.893,68.066Z" />
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M99.609,75.977L90.918,75.977L90.918,41.699A23.436,23.436 0,0 0,90.662 38.109Q90.055,34.207 88.013,31.958Q85.629,29.334 81.028,28.863A20.84,20.84 0,0 0,78.906 28.76A23.134,23.134 0,0 0,74.45 29.16Q71.926,29.656 69.994,30.767A11.122,11.122 0,0 0,66.968 33.301A13.32,13.32 0,0 0,64.756 37.276Q63.399,40.971 63.213,46.495A53.517,53.517 0,0 0,63.184 48.291L63.184,75.977L54.395,75.977L54.395,0L63.184,0L63.184,22.266A66.935,66.935 0,0 1,63.115 25.383Q63.043,26.914 62.897,28.251A33.547,33.547 0,0 1,62.695 29.785L63.281,29.785A16.11,16.11 0,0 1,69.394 24.035A19.448,19.448 0,0 1,70.068 23.682A20.88,20.88 0,0 1,77.292 21.622A25.763,25.763 0,0 1,79.98 21.484A32.643,32.643 0,0 1,85.483 21.917Q91.249,22.905 94.678,26.147Q98.472,29.735 99.347,36.631A35.274,35.274 0,0 1,99.609 41.064L99.609,75.977Z" />
|
||||
</group>
|
||||
</vector>
|
||||
@@ -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" />
|
||||
|
||||
@@ -18,4 +18,5 @@
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_monochrome" />
|
||||
</adaptive-icon>
|
||||
@@ -18,4 +18,5 @@
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_monochrome" />
|
||||
</adaptive-icon>
|
||||
@@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright 2016 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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
<!-- Custom preference -->
|
||||
|
||||
</resources>
|
||||
@@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright 2016 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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
<!-- Custom preference -->
|
||||
|
||||
</resources>
|
||||
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright 2016 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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
</resources>
|
||||
@@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright 2016 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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
<!-- Custom preference -->
|
||||
|
||||
</resources>
|
||||
@@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright 2016 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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
|
||||
</resources>
|
||||
File renamed without changes.
@@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="646" height="250" id="svg8502" version="1.1" inkscape:version="0.91 r13725" sodipodi:docname="get-it-on-github.svg" inkscape:export-filename="/home/nixdorf/Lokaler Speicher/Build/andOTP/assets/badges/get-it-on-github.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90">
|
||||
<defs id="defs8504" />
|
||||
<sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="0.50000001" inkscape:cx="-223.13537" inkscape:cy="546.37524" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" fit-margin-top="0" fit-margin-left="0" fit-margin-right="0" fit-margin-bottom="0" inkscape:window-width="1920" inkscape:window-height="1021" inkscape:window-x="0" inkscape:window-y="31" inkscape:window-maximized="1" />
|
||||
<metadata id="metadata8507">
|
||||
<rdf:RDF>
|
||||
<cc:Work rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Andrew Nayenko</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>https://f-droid.org</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/3.0/" />
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title />
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
<cc:License rdf:about="http://creativecommons.org/licenses/by-sa/3.0/">
|
||||
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction" />
|
||||
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution" />
|
||||
<cc:requires rdf:resource="http://creativecommons.org/ns#Notice" />
|
||||
<cc:requires rdf:resource="http://creativecommons.org/ns#Attribution" />
|
||||
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||
<cc:requires rdf:resource="http://creativecommons.org/ns#ShareAlike" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1" transform="translate(-289,-312.36218)">
|
||||
<rect style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#a6a6a6;stroke-width:4;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker:none;enable-background:accumulate" id="rect3007" width="560" height="164" x="332" y="355.36218" rx="20" ry="20" />
|
||||
<text sodipodi:linespacing="100%" id="text3013" y="402.36697" x="508.95129" style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.39519119px;line-height:100%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans';letter-spacing:0px;word-spacing:0px;display:inline;overflow:visible;visibility:visible;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;enable-background:accumulate" xml:space="preserve"><tspan y="402.36697" x="508.95129" id="tspan3015" sodipodi:role="line" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:34.125px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans'">GET IT ON</tspan></text>
|
||||
<text xml:space="preserve" style="color:black;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:29.70882034px;line-height:100%;font-family:Rokkitt;-inkscape-font-specification:'Rokkitt Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;display:inline;overflow:visible;visibility:visible;fill:white;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;marker:none;enable-background:accumulate" x="508.21259" y="489.36108" id="text5902" sodipodi:linespacing="100%"><tspan sodipodi:role="line" id="tspan5904" x="508.21259" y="489.36108" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:87.5px;line-height:100%;font-family:'Roboto Slab';-inkscape-font-specification:'Roboto Slab Bold';text-align:start;writing-mode:lr-tb;text-anchor:start;fill:white;fill-opacity:1">GitHub</tspan></text>
|
||||
<g transform="matrix(1.0017681,0,0,1.0017681,68.770756,92.660249)" id="g5136">
|
||||
<path style="fill:white;fill-opacity:1;fill-rule:evenodd;stroke:none" d="m 350.60937,282.4375 c -33.34765,0 -60.38671,27.03516 -60.38671,60.38672 0,26.67969 17.30078,49.3164 41.29687,57.30078 3.01563,0.55859 4.125,-1.30859 4.125,-2.90625 0,-1.4375 -0.0547,-6.19531 -0.082,-11.24219 -16.80078,3.65235 -20.34375,-7.125 -20.34375,-7.125 -2.75,-6.98047 -6.70703,-8.83594 -6.70703,-8.83594 -5.48047,-3.74609 0.41406,-3.67187 0.41406,-3.67187 6.0625,0.42578 9.25781,6.22266 9.25781,6.22266 5.38282,9.23437 14.125,6.5664 17.57032,5.02343 0.54296,-3.90234 2.10937,-6.57031 3.83593,-8.07812 -13.41406,-1.52735 -27.51562,-6.70313 -27.51562,-29.84375 0,-6.59375 2.35937,-11.98047 6.22265,-16.20703 -0.625,-1.52344 -2.6914,-7.66407 0.58594,-15.98047 0,0 5.07031,-1.625 16.60938,6.1875 4.82031,-1.33594 9.98437,-2.00781 15.11718,-2.03125 5.13282,0.0234 10.30079,0.69531 15.12891,2.03125 11.52344,-7.8125 16.58984,-6.1875 16.58984,-6.1875 3.28516,8.3164 1.21875,14.45703 0.58985,15.98047 3.87109,4.22656 6.21484,9.61328 6.21484,16.20703 0,23.19531 -14.125,28.30078 -27.57422,29.79687 2.16797,1.875 4.09766,5.55078 4.09766,11.1836 0,8.07812 -0.0703,14.58203 -0.0703,16.57031 0,1.60937 1.08593,3.49219 4.14843,2.89844 23.98047,-7.9961 41.26172,-30.6211 41.26172,-57.29297 0,-33.35156 -27.03515,-60.38672 -60.38672,-60.38672" id="path4937" inkscape:connector-curvature="0" />
|
||||
<path style="fill:white;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 313.09375,369.14062 c -0.13281,0.30079 -0.60547,0.38672 -1.03516,0.1836 -0.4375,-0.19922 -0.68359,-0.60547 -0.54297,-0.91016 0.12891,-0.30859 0.60157,-0.39062 1.03907,-0.1875 0.4414,0.19922 0.6914,0.61328 0.53906,0.91406" id="path4939" inkscape:connector-curvature="0" />
|
||||
<path style="fill:white;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 315.53906,371.86719 c -0.28906,0.26562 -0.85156,0.14453 -1.23437,-0.27735 -0.39453,-0.42187 -0.46875,-0.98437 -0.17578,-1.25781 0.29687,-0.26562 0.84375,-0.14062 1.23828,0.28125 0.39453,0.42578 0.47265,0.98438 0.17187,1.25391" id="path4941" inkscape:connector-curvature="0" />
|
||||
<path style="fill:white;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 317.92187,375.34375 c -0.37109,0.25781 -0.97656,0.0156 -1.35156,-0.51953 -0.37109,-0.53906 -0.37109,-1.17969 0.008,-1.4375 0.375,-0.25781 0.97266,-0.0274 1.35157,0.5039 0.36718,0.54688 0.36718,1.19141 -0.008,1.45313" id="path4943" inkscape:connector-curvature="0" />
|
||||
<path style="fill:white;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 321.18359,378.70312 c -0.33203,0.36719 -1.03906,0.26954 -1.55468,-0.23046 -0.52735,-0.48438 -0.67579,-1.17579 -0.34375,-1.54297 0.33593,-0.36328 1.04687,-0.26172 1.5664,0.23047 0.52344,0.48828 0.6836,1.18359 0.33203,1.54296" id="path4945-3" inkscape:connector-curvature="0" />
|
||||
<path style="fill:white;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 325.68359,380.65625 c -0.14843,0.47266 -0.82812,0.6875 -1.51172,0.48828 -0.68359,-0.20703 -1.1289,-0.76172 -0.99218,-1.24219 0.14453,-0.47265 0.82422,-0.69922 1.51562,-0.48437 0.67969,0.20703 1.12891,0.75781 0.98828,1.23828" id="path4947-6" inkscape:connector-curvature="0" />
|
||||
<path style="fill:white;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 330.625,381.01953 c 0.0156,0.49609 -0.5625,0.91016 -1.28125,0.91797 -0.72266,0.0156 -1.30859,-0.38672 -1.31641,-0.875 0,-0.50391 0.57032,-0.91406 1.28907,-0.92578 0.71875,-0.0156 1.30859,0.38672 1.30859,0.88281" id="path4949" inkscape:connector-curvature="0" />
|
||||
<path style="fill:white;fill-opacity:1;fill-rule:nonzero;stroke:none" d="m 335.22266,380.23437 c 0.0859,0.48829 -0.41407,0.98438 -1.125,1.11719 -0.70313,0.12891 -1.35157,-0.17187 -1.44141,-0.65234 -0.0859,-0.5 0.42187,-0.9961 1.12109,-1.125 0.71485,-0.125 1.35547,0.16797 1.44532,0.66015" id="path4951-7" inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.5 KiB |
@@ -20,10 +20,8 @@ import android.graphics.Bitmap;
|
||||
|
||||
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,20 +31,33 @@ 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;
|
||||
private long mNativePtr;
|
||||
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() {
|
||||
(new ArrayList<>(imageList)).forEach(Image::recycle);
|
||||
needEvictAll = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,7 +65,7 @@ public final class Image {
|
||||
*/
|
||||
@Nullable
|
||||
public static Image decode(FileDescriptor fd, boolean partially) {
|
||||
return nativeDecode(fd, partially);
|
||||
return nativeDecode(fd);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,7 +73,7 @@ public final class Image {
|
||||
*/
|
||||
@Nullable
|
||||
public static Image decode(Integer fd, boolean partially) {
|
||||
return nativeDecodeFdInt(fd, partially);
|
||||
return nativeDecodeFdInt(fd);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -70,7 +81,7 @@ public final class Image {
|
||||
*/
|
||||
@Nullable
|
||||
public static Image decodeAddr(Long addr, boolean partially) {
|
||||
return nativeDecodeAddr(addr, partially);
|
||||
return nativeDecodeAddr(addr);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,37 +97,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,21 +143,9 @@ 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) {
|
||||
throw new IllegalStateException("The image is recycled.", mRecycleTracker);
|
||||
} else {
|
||||
throw new IllegalStateException("The image is recycled.");
|
||||
}
|
||||
throw new IllegalStateException("The image is recycled.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,8 +155,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 +165,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 +173,7 @@ public final class Image {
|
||||
*/
|
||||
public void advance() {
|
||||
checkRecycled();
|
||||
nativeAdvance(mNativePtr, mFormat);
|
||||
nativeAdvance(mNativePtr);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -190,7 +181,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 +190,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -223,14 +198,11 @@ public final class Image {
|
||||
* It must be called when the image will not be used.
|
||||
* The image can't be used after this method is called.
|
||||
*/
|
||||
public void recycle() {
|
||||
public synchronized void recycle() {
|
||||
if (mNativePtr != 0) {
|
||||
nativeRecycle(mNativePtr, mFormat);
|
||||
nativeRecycle(mNativePtr);
|
||||
mNativePtr = 0;
|
||||
|
||||
sImageCount.getAndDecrement();
|
||||
|
||||
mRecycleTracker = new Throwable("It's a ImageRecycleTracker");
|
||||
imageList.remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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,77 @@ 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) {
|
||||
AImageDecoder *decoder;
|
||||
int r = AImageDecoder_createFromFd(fd, &decoder);
|
||||
LOGD("%s%d", "Create ImageDecoder with ret ", r);
|
||||
if (r)
|
||||
IMAGE *createFromFd(int fd) {
|
||||
AImageDecoder *decoder = NULL;
|
||||
if (AImageDecoder_createFromFd(fd, &decoder) != ANDROID_IMAGE_DECODER_SUCCESS)
|
||||
return NULL;
|
||||
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);
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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,112 @@ 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) {
|
||||
Java_com_hippo_image_Image_nativeDecodeFdInt(JNIEnv *env, jclass clazz, jint fd) {
|
||||
IMAGE *image = createFromFd(fd);
|
||||
if (!image)
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
{
|
||||
"baseBranches": [
|
||||
"1.8.x.x",
|
||||
"1.7.x.x"
|
||||
],
|
||||
|
||||
"extends": [
|
||||
"config:base"
|
||||
]
|
||||
|
||||
Reference in new issue
Block a user