Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
41a54b76bf | ||
|
|
a09940eb86 | ||
|
|
159b8c13b0 | ||
|
|
498d51ec22 | ||
|
|
24e50da7c9 | ||
|
|
fcc595d9a3 | ||
|
|
d2aecb5eb5 | ||
|
|
e2cfa30052 |
No files matched your search
@@ -1,3 +1,12 @@
|
||||
[submodule "native/src/main/jni/image/libjpeg-turbo/libjpeg-turbo"]
|
||||
path = native/src/main/jni/image/libjpeg-turbo/libjpeg-turbo
|
||||
url = https://github.com/Ehviewer-Overhauled/libjpeg-turbo
|
||||
[submodule "native/src/main/jni/image/giflib/giflib"]
|
||||
path = native/src/main/jni/image/giflib/giflib
|
||||
url = https://github.com/Ehviewer-Overhauled/giflib
|
||||
[submodule "native/src/main/jni/image/libpng/libpng"]
|
||||
path = native/src/main/jni/image/libpng/libpng
|
||||
url = https://github.com/Ehviewer-Overhauled/libpng
|
||||
[submodule "native/src/main/jni/libarchive"]
|
||||
path = native/src/main/jni/libarchive
|
||||
url = https://github.com/Ehviewer-Overhauled/libarchive
|
||||
|
||||
+5
-6
@@ -32,10 +32,10 @@ android {
|
||||
|
||||
defaultConfig {
|
||||
applicationId "moe.tarsin.ehviewer"
|
||||
minSdkVersion 31
|
||||
minSdkVersion 26
|
||||
targetSdkVersion 33
|
||||
versionCode 180000
|
||||
versionName "1.8.0.0"
|
||||
versionCode 114535
|
||||
versionName "1.7.29.3"
|
||||
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'
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package com.hippo.ehviewer;
|
||||
|
||||
import android.os.ParcelFileDescriptor;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
@@ -25,9 +23,7 @@ import com.hippo.conaco.ValueHelper;
|
||||
import com.hippo.image.ImageBitmap;
|
||||
import com.hippo.streampipe.InputStreamPipe;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class ImageBitmapHelper implements ValueHelper<ImageBitmap> {
|
||||
|
||||
@@ -38,8 +34,7 @@ public class ImageBitmapHelper implements ValueHelper<ImageBitmap> {
|
||||
public ImageBitmap decode(@NonNull InputStreamPipe isPipe) {
|
||||
try {
|
||||
isPipe.obtain();
|
||||
FileInputStream is = (FileInputStream) isPipe.open();
|
||||
return ImageBitmap.decode(is.getFD());
|
||||
return ImageBitmap.decode(isPipe.open());
|
||||
} catch (OutOfMemoryError | IOException e) {
|
||||
return null;
|
||||
} finally {
|
||||
|
||||
@@ -34,9 +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;
|
||||
@@ -53,7 +50,7 @@ public class ArchiveGalleryProvider extends GalleryProvider2 {
|
||||
private final UriArchiveAccessor archiveAccessor;
|
||||
private final Stack<Integer> requests = new Stack<>();
|
||||
private final AtomicInteger extractingIndex = new AtomicInteger(GalleryPageView.INVALID_INDEX);
|
||||
private final LinkedHashMap<Integer, Long> streams = new LinkedHashMap<>();
|
||||
private final LinkedHashMap<Integer, InputStream> streams = new LinkedHashMap<>();
|
||||
private final AtomicInteger decodingIndex = new AtomicInteger(GalleryPageView.INVALID_INDEX);
|
||||
private Thread archiveThread;
|
||||
private Thread decodeThread;
|
||||
@@ -253,18 +250,18 @@ public class ArchiveGalleryProvider extends GalleryProvider2 {
|
||||
continue;
|
||||
}
|
||||
|
||||
Pipe pipe = new Pipe();
|
||||
|
||||
synchronized (streams) {
|
||||
if (streams.get(index) != null) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
long addr = archiveAccessor.extracttoOutputStream(index);
|
||||
|
||||
synchronized (streams) {
|
||||
streams.put(index, addr);
|
||||
streams.put(index, pipe.getInputStream());
|
||||
streams.notify();
|
||||
}
|
||||
|
||||
archiveAccessor.extracttoOutputStream(index, pipe.getOutputFd());
|
||||
pipe.closeOutputFd();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -274,7 +271,7 @@ public class ArchiveGalleryProvider extends GalleryProvider2 {
|
||||
public void run() {
|
||||
while (!Thread.currentThread().isInterrupted()) {
|
||||
int index;
|
||||
Long addr;
|
||||
InputStream stream;
|
||||
synchronized (streams) {
|
||||
if (streams.isEmpty()) {
|
||||
try {
|
||||
@@ -286,16 +283,16 @@ public class ArchiveGalleryProvider extends GalleryProvider2 {
|
||||
continue;
|
||||
}
|
||||
|
||||
Iterator<Map.Entry<Integer, Long>> iterator = streams.entrySet().iterator();
|
||||
Map.Entry<Integer, Long> entry = iterator.next();
|
||||
Iterator<Map.Entry<Integer, InputStream>> iterator = streams.entrySet().iterator();
|
||||
Map.Entry<Integer, InputStream> entry = iterator.next();
|
||||
iterator.remove();
|
||||
index = entry.getKey();
|
||||
addr = entry.getValue();
|
||||
stream = entry.getValue();
|
||||
decodingIndex.lazySet(index);
|
||||
}
|
||||
|
||||
try {
|
||||
Image image = Image.decodeAddr(addr, true);
|
||||
Image image = Image.decode(stream, true);
|
||||
if (image != null) {
|
||||
notifyPageSucceed(index, image);
|
||||
} else {
|
||||
|
||||
@@ -34,7 +34,6 @@ import com.hippo.yorozuya.IOUtils;
|
||||
import com.hippo.yorozuya.StringUtils;
|
||||
import com.hippo.yorozuya.thread.PriorityThread;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@@ -259,7 +258,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(is, true);
|
||||
mDecodingIndex.lazySet(GalleryPageView.INVALID_INDEX);
|
||||
if (image != null) {
|
||||
notifyPageSucceed(index, image);
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.gallery;
|
||||
|
||||
import android.os.ParcelFileDescriptor;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
class Pipe {
|
||||
private ParcelFileDescriptor[] fd;
|
||||
{
|
||||
try {
|
||||
fd = ParcelFileDescriptor.createPipe();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private final InputStream inputStream = new FileInputStream(fd[0].getFileDescriptor());
|
||||
|
||||
InputStream getInputStream() {
|
||||
return inputStream;
|
||||
}
|
||||
|
||||
int getOutputFd() {
|
||||
return fd[1].getFd();
|
||||
}
|
||||
|
||||
void closeOutputFd() {
|
||||
try {
|
||||
fd[1].close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,7 @@ class VersionPreference @JvmOverloads constructor(
|
||||
val info = NativeLibInfo().addLib(Native.getlibarchiveVersion())
|
||||
.addLib("lzma(xz-utils)", Native.getliblzmaVersion())
|
||||
.addLib("zlib", Native.getzlibVersion())
|
||||
.addLib("libjpeg-turbo", Native.getlibjpeg_turboVersion())
|
||||
.addLib(Native.getnettleVersion())
|
||||
builder.setMessage(info.getMessage())
|
||||
}
|
||||
|
||||
@@ -66,7 +66,6 @@ import com.hippo.yorozuya.thread.PriorityThread;
|
||||
import com.hippo.yorozuya.thread.PriorityThreadFactory;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@@ -1097,6 +1096,33 @@ public final class SpiderQueen implements Runnable {
|
||||
void onGetImageFailure(int index, String error);
|
||||
}
|
||||
|
||||
private static class AutoCloseInputStream extends InputStream {
|
||||
|
||||
private final InputStreamPipe mPipe;
|
||||
private final InputStream mIs;
|
||||
|
||||
public AutoCloseInputStream(InputStreamPipe pipe, InputStream is) {
|
||||
mPipe = pipe;
|
||||
mIs = is;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return mIs.read();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(@NonNull byte[] buffer, int byteOffset, int byteCount) throws IOException {
|
||||
return mIs.read(buffer, byteOffset, byteCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
mPipe.close();
|
||||
mPipe.release();
|
||||
}
|
||||
}
|
||||
|
||||
private class SpiderWorker implements Runnable {
|
||||
|
||||
private final long mGid;
|
||||
@@ -1667,7 +1693,7 @@ public final class SpiderQueen implements Runnable {
|
||||
|
||||
pipe.obtain();
|
||||
try {
|
||||
is = pipe.open();
|
||||
is = new AutoCloseInputStream(pipe, pipe.open());
|
||||
} catch (IOException e) {
|
||||
// Can't open pipe
|
||||
error = GetText.getString(R.string.error_reading_failed);
|
||||
@@ -1677,18 +1703,7 @@ public final class SpiderQueen implements Runnable {
|
||||
}
|
||||
|
||||
if (is != null) {
|
||||
try {
|
||||
image = Image.decode(((FileInputStream)is).getFD(), true);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
image = null;
|
||||
} finally {
|
||||
try {
|
||||
is.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
image = Image.decode(is, true);
|
||||
if (image == null) {
|
||||
error = GetText.getString(R.string.error_decoding_failed);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -245,7 +245,7 @@ public abstract class GalleryProvider {
|
||||
}
|
||||
|
||||
public void add(Integer key, ImageWrapper value) {
|
||||
if (value.getFormat() != Image.FORMAT_ANIMATED && value.obtain()) {
|
||||
if (value.getFormat() != Image.FORMAT_GIF && value.obtain()) {
|
||||
put(key, value);
|
||||
}
|
||||
}
|
||||
@@ -253,7 +253,7 @@ public abstract class GalleryProvider {
|
||||
@Override
|
||||
protected int sizeOf(Integer key, ImageWrapper value) {
|
||||
int size = value.getWidth() * value.getHeight() * 4;
|
||||
if (value.getFormat() == Image.FORMAT_ANIMATED) {
|
||||
if (value.getFormat() == Image.FORMAT_GIF) {
|
||||
size *= 5;
|
||||
}
|
||||
return size;
|
||||
|
||||
@@ -153,6 +153,12 @@ public class ImageTexture implements Texture, Animatable {
|
||||
}
|
||||
|
||||
mTiles = list.toArray(new Tile[list.size()]);
|
||||
|
||||
if (!mImage.isCompleted()) {
|
||||
Runnable runnable = new AnimateRunnable();
|
||||
mAnimateRunnable = runnable;
|
||||
sThreadExecutor.execute(runnable);
|
||||
}
|
||||
}
|
||||
|
||||
private static Tile obtainSmallTile() {
|
||||
@@ -233,7 +239,7 @@ public class ImageTexture implements Texture, Animatable {
|
||||
}
|
||||
|
||||
boolean end = mReleased.get() || mImage.isImageRecycled() || mNeedRelease.get() ||
|
||||
(mImage.getFormat() == 0) || mRunning.get();
|
||||
(mImage.isCompleted() && mImage.getFrameCount() <= 1) || mRunning.get();
|
||||
|
||||
synchronized (mImage) {
|
||||
mImageBusy = false;
|
||||
@@ -591,11 +597,25 @@ public class ImageTexture implements Texture, Animatable {
|
||||
mImageBusy = true;
|
||||
}
|
||||
|
||||
if (!mImage.isCompleted()) {
|
||||
try {
|
||||
sPVLock.p();
|
||||
} catch (InterruptedException e) {
|
||||
// Ignore
|
||||
}
|
||||
if (!mNeedRelease.get()) {
|
||||
mImage.complete();
|
||||
}
|
||||
sPVLock.v();
|
||||
}
|
||||
|
||||
int frameCount = mImage.getFrameCount();
|
||||
|
||||
synchronized (mImage) {
|
||||
// Release image
|
||||
mImageBusy = false;
|
||||
// Check need release, frameCount <= 1
|
||||
if (mNeedRelease.get() || mImage.getFormat() == 0) {
|
||||
if (mNeedRelease.get() || frameCount <= 1) {
|
||||
mAnimateRunnable = null;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -122,6 +122,22 @@ public class ImageWrapper {
|
||||
return mCut.height();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Image#complete()
|
||||
*/
|
||||
public boolean complete() {
|
||||
synchronized (mImage) {
|
||||
return mImage.complete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Image#isCompleted()
|
||||
*/
|
||||
public boolean isCompleted() {
|
||||
return mImage.isCompleted();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Image#render(int, int, Bitmap, int, int, int, int, boolean, int)
|
||||
*/
|
||||
@@ -152,6 +168,13 @@ public class ImageWrapper {
|
||||
return mImage.getDelay();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Image#getFrameCount()
|
||||
*/
|
||||
public int getFrameCount() {
|
||||
return mImage.getFrameCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Image#isOpaque()
|
||||
*/
|
||||
|
||||
@@ -756,8 +756,8 @@
|
||||
<string name="pick_new_download_location">选择新路径</string>
|
||||
<string name="dont_show_again">不再显示</string>
|
||||
<string name="open_settings">打开设置</string>
|
||||
<string name="app_link_not_verified_message">对于 Android 12 及更新的版本,您需要手动添加链接到已验证链接才能在 EhViewer 中打开 E-Hentai 链接。</string>
|
||||
<string name="app_link_not_verified_title">应用链接未验证</string>
|
||||
<string name="app_link_not_verified_message">对于您的设备,我们强烈建议您使用 1.8 版本。1.7 版本仅为 Android 11 及以下版本设计</string>
|
||||
<string name="app_link_not_verified_title">升级 App 版本</string>
|
||||
<string name="open_by_default">默认打开</string>
|
||||
|
||||
<string name="show_library_version">依赖库之版本</string>
|
||||
|
||||
@@ -820,8 +820,8 @@
|
||||
<string name="pick_new_download_location">Pick a new location</string>
|
||||
<string name="dont_show_again">Don\'t show again</string>
|
||||
<string name="open_settings">Open settings</string>
|
||||
<string name="app_link_not_verified_message">For Android 12 and newer, you need to manually add link to verified links in order to open E-Hentai links in EhViewer.</string>
|
||||
<string name="app_link_not_verified_title">App links not verified</string>
|
||||
<string name="app_link_not_verified_message">For you device, We strongly recommend you to use version 1.8. version 1.7 is only made for Android 11 and below .</string>
|
||||
<string name="app_link_not_verified_title">Update App Version</string>
|
||||
<string name="open_by_default">Open by default</string>
|
||||
|
||||
<string name="show_library_version">Library Version</string>
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ android {
|
||||
ndkVersion "25.0.8775105"
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 31
|
||||
minSdkVersion 26
|
||||
targetSdkVersion 33
|
||||
consumerProguardFiles 'proguard-rules.pro'
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@ public class Native {
|
||||
|
||||
public static native String getliblzmaVersion();
|
||||
|
||||
public static native String getlibjpeg_turboVersion();
|
||||
|
||||
public static native String getzlibVersion();
|
||||
|
||||
public static native String getnettleVersion();
|
||||
|
||||
@@ -47,7 +47,7 @@ public class UriArchiveAccessor {
|
||||
|
||||
private native int openArchive(long addr, long size);
|
||||
|
||||
public native long extracttoOutputStream(int index);
|
||||
public native void extracttoOutputStream(int index, int fd);
|
||||
|
||||
public native boolean needPassword();
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ 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;
|
||||
|
||||
@@ -29,9 +28,31 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
* The {@code Image} is a image which stored pixel data in native heap
|
||||
*/
|
||||
public final class Image {
|
||||
public static final int FORMAT_NORMAL = 0;
|
||||
|
||||
public static final int FORMAT_ANIMATED = 1;
|
||||
/**
|
||||
* Unknown image format
|
||||
*/
|
||||
public static final int FORMAT_UNKNOWN = -1;
|
||||
|
||||
/**
|
||||
* Plain image format, for {@code Image} from {@link #create(Bitmap)}
|
||||
*/
|
||||
public static final int FORMAT_PLAIN = 0;
|
||||
|
||||
/**
|
||||
* JPEG image format
|
||||
*/
|
||||
public static final int FORMAT_JPEG = 1;
|
||||
|
||||
/**
|
||||
* PNG image format
|
||||
*/
|
||||
public static final int FORMAT_PNG = 2;
|
||||
|
||||
/**
|
||||
* GIF image format
|
||||
*/
|
||||
public static final int FORMAT_GIF = 3;
|
||||
|
||||
private static final AtomicInteger sImageCount = new AtomicInteger();
|
||||
private final int mFormat;
|
||||
@@ -53,24 +74,11 @@ public final class Image {
|
||||
* Decode image from {@code InputStream}
|
||||
*/
|
||||
@Nullable
|
||||
public static Image decode(FileDescriptor fd, boolean partially) {
|
||||
return nativeDecode(fd, partially);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode image from {@code InputStream}
|
||||
*/
|
||||
@Nullable
|
||||
public static Image decode(Integer fd, boolean partially) {
|
||||
return nativeDecodeFdInt(fd, partially);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode image from {@code InputStream}
|
||||
*/
|
||||
@Nullable
|
||||
public static Image decodeAddr(Long addr, boolean partially) {
|
||||
return nativeDecodeAddr(addr, partially);
|
||||
public static Image decode(InputStream is, boolean partially) {
|
||||
if (!(is instanceof BufferedInputStream)) {
|
||||
is = new BufferedInputStream(is);
|
||||
}
|
||||
return nativeDecode(is, partially);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,16 +97,31 @@ public final class Image {
|
||||
return sImageCount.get();
|
||||
}
|
||||
|
||||
private static native Image nativeDecode(FileDescriptor fd, boolean partially);
|
||||
/**
|
||||
* Return all supported image formats, exclude {@link #FORMAT_PLAIN}
|
||||
*/
|
||||
public static int[] getSupportedImageFormats() {
|
||||
return nativeGetSupportedImageFormats();
|
||||
}
|
||||
|
||||
private static native Image nativeDecodeFdInt(int fd, boolean partially);
|
||||
/**
|
||||
* Return decoder description of the image format,
|
||||
* {@code null} for invalid image format.
|
||||
*/
|
||||
public static String getDecoderDescription(int format) {
|
||||
return nativeGetDecoderDescription(format);
|
||||
}
|
||||
|
||||
private static native Image nativeDecodeAddr(long addr, boolean partially);
|
||||
private static native Image nativeDecode(InputStream is, boolean partially);
|
||||
|
||||
private static native Image nativeCreate(Bitmap bitmap);
|
||||
|
||||
private static native int nativeGetByteCount(long nativePtr, int format);
|
||||
|
||||
private static native boolean nativeComplete(long nativePtr, int format);
|
||||
|
||||
private static native boolean nativeIsCompleted(long nativePtr, int format);
|
||||
|
||||
private static native void nativeRender(long nativePtr, int format,
|
||||
int srcX, int srcY, Bitmap dst, int dstX, int dstY,
|
||||
int width, int height, boolean fillBlank, int defaultColor);
|
||||
@@ -110,6 +133,8 @@ public final class Image {
|
||||
|
||||
private static native int nativeGetDelay(long nativePtr, int format);
|
||||
|
||||
private static native int nativeFrameCount(long nativePtr, int format);
|
||||
|
||||
private static native boolean nativeIsOpaque(long nativePtr, int format);
|
||||
|
||||
private static native boolean nativeIsGray(long nativePtr, int format, int error);
|
||||
@@ -118,6 +143,10 @@ public final class Image {
|
||||
|
||||
private static native void nativeRecycle(long nativePtr, int format);
|
||||
|
||||
private static native int[] nativeGetSupportedImageFormats();
|
||||
|
||||
private static native String nativeGetDecoderDescription(int format);
|
||||
|
||||
/**
|
||||
* Return the format of the image
|
||||
*/
|
||||
@@ -157,6 +186,22 @@ public final class Image {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete the image decoding
|
||||
*/
|
||||
public boolean complete() {
|
||||
checkRecycled();
|
||||
return nativeComplete(mNativePtr, mFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the image decoding completed
|
||||
*/
|
||||
public boolean isCompleted() {
|
||||
checkRecycled();
|
||||
return nativeIsCompleted(mNativePtr, mFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the image to {@code Bitmap}
|
||||
*/
|
||||
@@ -194,6 +239,14 @@ public final class Image {
|
||||
return delay <= 10 ? 100 : delay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return frame count. 1 for non-animation image
|
||||
*/
|
||||
public int getFrameCount() {
|
||||
checkRecycled();
|
||||
return nativeFrameCount(mNativePtr, mFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return is the image opaque
|
||||
*/
|
||||
|
||||
@@ -28,7 +28,6 @@ import android.os.Looper;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.InputStream;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Iterator;
|
||||
@@ -46,6 +45,7 @@ public final class ImageBitmap implements Animatable, Runnable {
|
||||
private final int mFormat;
|
||||
private final boolean mIsOpaque;
|
||||
private final int mByteCount;
|
||||
private final int mFrameCount;
|
||||
private final Set<WeakReference<Callback>> mCallbackSet = new LinkedHashSet<>();
|
||||
@Nullable
|
||||
private Image mImage;
|
||||
@@ -61,8 +61,9 @@ public final class ImageBitmap implements Animatable, Runnable {
|
||||
mFormat = image.getFormat();
|
||||
mIsOpaque = image.isOpaque();
|
||||
mByteCount = image.getByteCount();
|
||||
mFrameCount = image.getFrameCount();
|
||||
|
||||
if (mFormat == 1) {
|
||||
if (mFrameCount > 1) {
|
||||
// For animated image, save image object
|
||||
mImage = image;
|
||||
} else {
|
||||
@@ -72,18 +73,19 @@ public final class ImageBitmap implements Animatable, Runnable {
|
||||
}
|
||||
|
||||
private ImageBitmap(@NonNull Bitmap bitmap) {
|
||||
mFormat = Image.FORMAT_NORMAL;
|
||||
mFormat = Image.FORMAT_PLAIN;
|
||||
mBitmap = bitmap;
|
||||
mIsOpaque = !bitmap.hasAlpha();
|
||||
mByteCount = bitmap.getRowBytes() * bitmap.getHeight();
|
||||
mFrameCount = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode {@code InputStream}, then create image.
|
||||
*/
|
||||
@Nullable
|
||||
public static ImageBitmap decode(@NonNull FileDescriptor fd) {
|
||||
Image image = Image.decode(fd, false);
|
||||
public static ImageBitmap decode(@NonNull InputStream is) {
|
||||
Image image = Image.decode(is, false);
|
||||
if (image != null) {
|
||||
return create(image);
|
||||
} else {
|
||||
@@ -235,6 +237,13 @@ public final class ImageBitmap implements Animatable, Runnable {
|
||||
return mImage != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return image frame count
|
||||
*/
|
||||
public int getFrameCount() {
|
||||
return mFrameCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw image to canvas
|
||||
*/
|
||||
|
||||
@@ -121,37 +121,35 @@ Java_com_hippo_UriArchiveAccessor_openArchive(JNIEnv *_, jobject thiz, jlong add
|
||||
return r;
|
||||
}
|
||||
|
||||
typedef struct Memarea {
|
||||
void* buffer;
|
||||
long size;
|
||||
} Memarea;
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_com_hippo_UriArchiveAccessor_extracttoOutputStream(JNIEnv *_, jobject thiz, jint index) {
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_hippo_UriArchiveAccessor_extracttoOutputStream(JNIEnv *_, jobject thiz, jint index,
|
||||
jint fd) {
|
||||
struct archive_entry *entry;
|
||||
size_t size;
|
||||
int ret;
|
||||
la_int64_t offset;
|
||||
const void *buff;
|
||||
if (!arc || index < cur_index) {
|
||||
archive_alloc();
|
||||
cur_index = 0;
|
||||
}
|
||||
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) {
|
||||
ret = archive_read_data_block(arc, &buff, &size, &offset);
|
||||
if (ret == ARCHIVE_EOF)
|
||||
break;
|
||||
if (ret != ARCHIVE_OK) {
|
||||
LOGE("%s%s", "Archive read failed:", archive_error_string(arc));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
write(fd, buff, size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (jlong) memarea;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
@@ -174,7 +172,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)))
|
||||
|
||||
@@ -13,24 +13,9 @@
|
||||
# limitations under the License.
|
||||
|
||||
cmake_minimum_required(VERSION 3.4.1)
|
||||
project(image C)
|
||||
|
||||
set(IMAGE_SOURCES
|
||||
image.c
|
||||
image_utils.c
|
||||
filter/clahe.c
|
||||
filter/gray.c
|
||||
java_wrapper.c
|
||||
)
|
||||
set(IMAGE_INCLUDES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
set(IMAGE_LIBRARIES
|
||||
log
|
||||
jnigraphics
|
||||
GLESv2
|
||||
)
|
||||
|
||||
add_library(image STATIC ${IMAGE_SOURCES})
|
||||
target_include_directories(image PRIVATE ${IMAGE_INCLUDES})
|
||||
target_link_libraries(image PRIVATE ${IMAGE_LIBRARIES})
|
||||
add_subdirectory(image)
|
||||
add_subdirectory(stream)
|
||||
add_subdirectory(libjpeg-turbo)
|
||||
add_subdirectory(libpng)
|
||||
add_subdirectory(giflib)
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
# 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.
|
||||
|
||||
cmake_minimum_required(VERSION 3.4.1)
|
||||
project(gif C)
|
||||
|
||||
set(GIFLIB_SOURCES
|
||||
giflib/dgif_lib.c
|
||||
giflib/gif_hash.c
|
||||
giflib/gifalloc.c
|
||||
giflib/openbsd-reallocarray.c
|
||||
)
|
||||
set(GIFLIB_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/giflib)
|
||||
|
||||
add_library(gif STATIC ${GIFLIB_SOURCES})
|
||||
target_include_directories(gif PUBLIC ${GIFLIB_INCLUDES})
|
||||
Submodule
+1
Submodule native/src/main/jni/image/giflib/giflib added at df82ff4380.
@@ -1,192 +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/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;
|
||||
AImageDecoder_setDataSpace(decoder, ADATASPACE_SRGB);
|
||||
AImageDecoder_setAndroidBitmapFormat(decoder, ANDROID_BITMAP_FORMAT_RGBA_8888);
|
||||
const AImageDecoderHeaderInfo *headerInfo = AImageDecoder_getHeaderInfo(decoder);
|
||||
image->height = AImageDecoderHeaderInfo_getHeight(headerInfo);
|
||||
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;
|
||||
image->buffer = malloc(image->bufferLen);
|
||||
if (image->isAnimated) {
|
||||
AImageDecoder_setInternallyHandleDisposePrevious(decoder, false);
|
||||
image->frameInfo = AImageDecoderFrameInfo_create();
|
||||
AImageDecoder_getFrameInfo(decoder, image->frameInfo);
|
||||
}
|
||||
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)
|
||||
return NULL;
|
||||
IMAGE *image = calloc(1, sizeof(IMAGE));
|
||||
image->isAnimated = *format = AImageDecoder_isAnimated(decoder);
|
||||
image->decoder = decoder;
|
||||
decodeCommon(image);
|
||||
return image;
|
||||
}
|
||||
|
||||
IMAGE *createFromAddr(JNIEnv *env, void *addr, long size, bool partially, int *format) {
|
||||
AImageDecoder *decoder;
|
||||
int r = AImageDecoder_createFromBuffer((const void *) addr, size, &decoder);
|
||||
LOGD("%s%d", "Create ImageDecoder with ret ", r);
|
||||
if (r)
|
||||
return NULL;
|
||||
IMAGE *image = calloc(1, sizeof(IMAGE));
|
||||
image->isAnimated = *format = AImageDecoder_isAnimated(decoder);
|
||||
image->decoder = decoder;
|
||||
image->srcBuffer = addr;
|
||||
decodeCommon(image);
|
||||
return image;
|
||||
}
|
||||
|
||||
void *create(int32_t width, int32_t height, const void *data) {
|
||||
IMAGE *plain = NULL;
|
||||
void *buffer = NULL;
|
||||
size_t length;
|
||||
|
||||
plain = malloc(sizeof(IMAGE));
|
||||
if (plain == NULL) {
|
||||
WTF_OM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
length = (size_t) (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;
|
||||
|
||||
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 *dst, int dst_w, int dst_h, int dst_x, int dst_y,
|
||||
int width, int height, bool fill_blank, int default_color) {
|
||||
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);
|
||||
}
|
||||
|
||||
void advance(IMAGE *image, int format) {
|
||||
if (format) {
|
||||
AImageDecoder_advanceFrame(image->decoder);
|
||||
if (AImageDecoder_decodeImage(image->decoder, image->buffer, image->stride,
|
||||
image->bufferLen) == ANDROID_IMAGE_DECODER_FINISHED) {
|
||||
AImageDecoder_rewind(image->decoder);
|
||||
AImageDecoder_decodeImage(image->decoder, image->buffer, image->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 +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/27/2015.
|
||||
//
|
||||
|
||||
#ifndef IMAGE_IMAGE_H
|
||||
#define IMAGE_IMAGE_H
|
||||
|
||||
#include <android/imagedecoder.h>
|
||||
#include <stdbool.h>
|
||||
#include <jni.h>
|
||||
|
||||
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;
|
||||
} IMAGE;
|
||||
|
||||
IMAGE *createFromFd(JNIEnv *env, int fd, bool partially, int *format);
|
||||
|
||||
IMAGE *createFromAddr(JNIEnv *env, void *addr, long size, bool partially, int *format);
|
||||
|
||||
void *create(int32_t width, int32_t height, const void *data);
|
||||
|
||||
int get_width(IMAGE *image, int format);
|
||||
|
||||
int get_height(IMAGE *image, int format);
|
||||
|
||||
int get_byte_count(IMAGE *image, int format);
|
||||
|
||||
void render(IMAGE *image, int format, 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);
|
||||
|
||||
void advance(IMAGE *image, int format);
|
||||
|
||||
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
|
||||
@@ -0,0 +1,60 @@
|
||||
# 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.
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
SUPPORT_FORMAT := plain jpeg png gif
|
||||
|
||||
LOCAL_MODULE := image
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../stream
|
||||
LOCAL_SRC_FILES := \
|
||||
image.c \
|
||||
image_utils.c \
|
||||
java_wrapper.c
|
||||
LOCAL_LDLIBS := -llog -ljnigraphics -lGLESv2
|
||||
LOCAL_STATIC_LIBRARIES := stream
|
||||
|
||||
ifeq ($(filter plain, $(SUPPORT_FORMAT)), plain)
|
||||
LOCAL_SRC_FILES += image_plain.c
|
||||
else
|
||||
LOCAL_CFLAGS += -DIMAGE_NOT_SUPPORT_PLAIN
|
||||
endif
|
||||
|
||||
ifeq ($(filter jpeg, $(SUPPORT_FORMAT)), jpeg)
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../libjpeg-turbo
|
||||
LOCAL_SRC_FILES += image_jpeg.c
|
||||
LOCAL_STATIC_LIBRARIES += jpeg-turbo
|
||||
else
|
||||
LOCAL_CFLAGS += -DIMAGE_NOT_SUPPORT_JPEG
|
||||
endif
|
||||
|
||||
ifeq ($(filter png, $(SUPPORT_FORMAT)), png)
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../libpng
|
||||
LOCAL_SRC_FILES += image_png.c
|
||||
LOCAL_STATIC_LIBRARIES += png
|
||||
else
|
||||
LOCAL_CFLAGS += -DIMAGE_NOT_SUPPORT_PNG
|
||||
endif
|
||||
|
||||
ifeq ($(filter gif, $(SUPPORT_FORMAT)), gif)
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../giflib
|
||||
LOCAL_SRC_FILES += image_gif.c
|
||||
LOCAL_STATIC_LIBRARIES += gif
|
||||
else
|
||||
LOCAL_CFLAGS += -DIMAGE_NOT_SUPPORT_GIF
|
||||
endif
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
@@ -0,0 +1,44 @@
|
||||
# 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.
|
||||
|
||||
cmake_minimum_required(VERSION 3.4.1)
|
||||
project(image C)
|
||||
|
||||
set(IMAGE_SOURCES
|
||||
image.c
|
||||
image_utils.c
|
||||
image_plain.c
|
||||
image_jpeg.c
|
||||
image_png.c
|
||||
image_gif.c
|
||||
filter/clahe.c
|
||||
filter/gray.c
|
||||
java_wrapper.c
|
||||
)
|
||||
set(IMAGE_INCLUDES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
set(IMAGE_LIBRARIES
|
||||
log
|
||||
jnigraphics
|
||||
GLESv2
|
||||
stream
|
||||
jpeg
|
||||
png
|
||||
gif
|
||||
)
|
||||
|
||||
add_library(image STATIC ${IMAGE_SOURCES})
|
||||
target_include_directories(image PRIVATE ${IMAGE_INCLUDES})
|
||||
target_link_libraries(image PRIVATE ${IMAGE_LIBRARIES})
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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/27/2015.
|
||||
//
|
||||
|
||||
#ifndef IMAGE_CONFIG_H
|
||||
#define IMAGE_CONFIG_H
|
||||
|
||||
#ifndef IMAGE_NOT_SUPPORT_PLAIN
|
||||
#define IMAGE_SUPPORT_PLAIN
|
||||
#endif
|
||||
#ifndef IMAGE_NOT_SUPPORT_JPEG
|
||||
#define IMAGE_SUPPORT_JPEG
|
||||
#endif
|
||||
#ifndef IMAGE_NOT_SUPPORT_PNG
|
||||
#define IMAGE_SUPPORT_PNG
|
||||
#endif
|
||||
#ifndef IMAGE_NOT_SUPPORT_GIF
|
||||
#define IMAGE_SUPPORT_GIF
|
||||
#endif
|
||||
|
||||
#endif //IMAGE_CONFIG_H
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* 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
-1
@@ -19,6 +19,6 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
void IMAGE_clahe(void *data, int width, int height, bool to_gray);
|
||||
void IMAGE_clahe(void* data, int width, int height, bool to_gray);
|
||||
|
||||
#endif //IMAGE_CLAHE_H
|
||||
+12
-12
@@ -17,20 +17,20 @@
|
||||
#include "gray.h"
|
||||
#include "pixel.h"
|
||||
|
||||
bool IMAGE_is_gray(void *data, int width, int height, int error) {
|
||||
PIXEL *p = data;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
if (e1 > error || e1 < -error
|
||||
|| e2 > error || e2 < -error
|
||||
|| e3 > error || e3 < -error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
+1
-1
@@ -19,6 +19,6 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
bool IMAGE_is_gray(void *data, int width, int height, int error);
|
||||
bool IMAGE_is_gray(void* data, int width, int height, int error);
|
||||
|
||||
#endif //IMAGE_GRAY_H
|
||||
+6
-5
@@ -19,11 +19,12 @@
|
||||
|
||||
typedef unsigned char BYTE;
|
||||
|
||||
typedef struct {
|
||||
BYTE c1;
|
||||
BYTE c2;
|
||||
BYTE c3;
|
||||
BYTE c4;
|
||||
typedef struct
|
||||
{
|
||||
BYTE c1;
|
||||
BYTE c2;
|
||||
BYTE c3;
|
||||
BYTE c4;
|
||||
} PIXEL;
|
||||
|
||||
#endif //IMAGE_PIXEL_H
|
||||
@@ -0,0 +1,532 @@
|
||||
/*
|
||||
* 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/27/2015.
|
||||
//
|
||||
|
||||
#include "image.h"
|
||||
#include "image_plain.h"
|
||||
#include "image_jpeg.h"
|
||||
#include "image_png.h"
|
||||
#include "image_gif.h"
|
||||
#include "filter/clahe.h"
|
||||
#include "filter/gray.h"
|
||||
#include "../log.h"
|
||||
|
||||
static int get_format(JNIEnv* env, InputStream* stream)
|
||||
{
|
||||
unsigned char temp[2];
|
||||
int read = read_input_stream(env, stream, temp, 0, 2);
|
||||
|
||||
if (read == 2) {
|
||||
#ifdef IMAGE_SUPPORT_JPEG
|
||||
if (temp[0] == IMAGE_JPEG_MAGIC_NUMBER_0 && temp[1] == IMAGE_JPEG_MAGIC_NUMBER_1) {
|
||||
return IMAGE_FORMAT_JPEG;
|
||||
}
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_PNG
|
||||
if (temp[0] == IMAGE_PNG_MAGIC_NUMBER_0 && temp[1] == IMAGE_PNG_MAGIC_NUMBER_1) {
|
||||
return IMAGE_FORMAT_PNG;
|
||||
}
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_GIF
|
||||
if (temp[0] == IMAGE_GIF_MAGIC_NUMBER_0 && temp[1] == IMAGE_GIF_MAGIC_NUMBER_1) {
|
||||
return IMAGE_FORMAT_GIF;
|
||||
}
|
||||
#endif
|
||||
LOGE(MSG("Can't recognize the two magic number: %d, %d"), temp[0], temp[1]);
|
||||
} else {
|
||||
LOGE(MSG("Can't read two magic number from stream"));
|
||||
}
|
||||
|
||||
return IMAGE_FORMAT_UNKNOWN;
|
||||
}
|
||||
|
||||
void* decode(JNIEnv* env, InputStream* stream, bool partially, int* format)
|
||||
{
|
||||
unsigned char magic_numbers[2];
|
||||
PatchHeadInputStream* patch_head_input_stream;
|
||||
|
||||
*format = get_format(env, stream);
|
||||
|
||||
switch (*format) {
|
||||
#ifdef IMAGE_SUPPORT_JPEG
|
||||
case IMAGE_FORMAT_JPEG:
|
||||
magic_numbers[0] = IMAGE_JPEG_MAGIC_NUMBER_0;
|
||||
magic_numbers[1] = IMAGE_JPEG_MAGIC_NUMBER_1;
|
||||
break;
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_PNG
|
||||
case IMAGE_FORMAT_PNG:
|
||||
magic_numbers[0] = IMAGE_PNG_MAGIC_NUMBER_0;
|
||||
magic_numbers[1] = IMAGE_PNG_MAGIC_NUMBER_1;
|
||||
break;
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_GIF
|
||||
case IMAGE_FORMAT_GIF:
|
||||
magic_numbers[0] = IMAGE_GIF_MAGIC_NUMBER_0;
|
||||
magic_numbers[1] = IMAGE_GIF_MAGIC_NUMBER_1;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
LOGE(MSG("Can't detect format %d"), *format);
|
||||
destroy_input_stream(env, &stream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
patch_head_input_stream = create_patch_head_input_stream(stream, magic_numbers, 2);
|
||||
if (patch_head_input_stream == NULL){
|
||||
WTF_OM;
|
||||
destroy_input_stream(env, &stream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (*format) {
|
||||
#ifdef IMAGE_SUPPORT_JPEG
|
||||
case IMAGE_FORMAT_JPEG:
|
||||
return JPEG_decode(env, patch_head_input_stream, partially);
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_PNG
|
||||
case IMAGE_FORMAT_PNG:
|
||||
return PNG_decode(env, patch_head_input_stream, partially);
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_GIF
|
||||
case IMAGE_FORMAT_GIF:
|
||||
return GIF_decode(env, patch_head_input_stream, partially);
|
||||
#endif
|
||||
default:
|
||||
LOGE(MSG("Can't detect format %d"), *format);
|
||||
close_patch_head_input_stream(env, patch_head_input_stream);
|
||||
destroy_patch_head_input_stream(env, &patch_head_input_stream);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void* create(unsigned int width, unsigned int height, const void* data)
|
||||
{
|
||||
#ifdef IMAGE_SUPPORT_PLAIN
|
||||
return PLAIN_create(width, height, data);
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool complete(JNIEnv* env, void* image, int format)
|
||||
{
|
||||
switch (format) {
|
||||
#ifdef IMAGE_SUPPORT_PLAIN
|
||||
case IMAGE_FORMAT_PLAIN:
|
||||
return PLAIN_complete((PLAIN*) image);
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_JPEG
|
||||
case IMAGE_FORMAT_JPEG:
|
||||
return JPEG_complete((JPEG*) image);
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_PNG
|
||||
case IMAGE_FORMAT_PNG:
|
||||
return PNG_complete(env, (PNG*) image);
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_GIF
|
||||
case IMAGE_FORMAT_GIF:
|
||||
return GIF_complete(env, (GIF*) image);
|
||||
#endif
|
||||
default:
|
||||
LOGE(MSG("Can't detect format %d"), format);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_completed(void* image, int format)
|
||||
{
|
||||
switch (format) {
|
||||
#ifdef IMAGE_SUPPORT_PLAIN
|
||||
case IMAGE_FORMAT_PLAIN:
|
||||
return PLAIN_is_completed((PLAIN*) image);
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_JPEG
|
||||
case IMAGE_FORMAT_JPEG:
|
||||
return JPEG_is_completed((JPEG*) image);
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_PNG
|
||||
case IMAGE_FORMAT_PNG:
|
||||
return PNG_is_completed((PNG*) image);
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_GIF
|
||||
case IMAGE_FORMAT_GIF:
|
||||
return GIF_is_completed((GIF*) image);
|
||||
#endif
|
||||
default:
|
||||
LOGE(MSG("Can't detect format %d"), format);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int get_width(void* image, int format)
|
||||
{
|
||||
switch (format) {
|
||||
#ifdef IMAGE_SUPPORT_PLAIN
|
||||
case IMAGE_FORMAT_PLAIN:
|
||||
return PLAIN_get_width((PLAIN*) image);
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_JPEG
|
||||
case IMAGE_FORMAT_JPEG:
|
||||
return JPEG_get_width((JPEG*) image);
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_PNG
|
||||
case IMAGE_FORMAT_PNG:
|
||||
return PNG_get_width((PNG*) image);
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_GIF
|
||||
case IMAGE_FORMAT_GIF:
|
||||
return GIF_get_width((GIF*) image);
|
||||
#endif
|
||||
default:
|
||||
LOGE(MSG("Can't detect format %d"), format);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int get_height(void* image, int format)
|
||||
{
|
||||
switch (format) {
|
||||
#ifdef IMAGE_SUPPORT_PLAIN
|
||||
case IMAGE_FORMAT_PLAIN:
|
||||
return PLAIN_get_height((PLAIN*) image);
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_JPEG
|
||||
case IMAGE_FORMAT_JPEG:
|
||||
return JPEG_get_height((JPEG*) image);
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_PNG
|
||||
case IMAGE_FORMAT_PNG:
|
||||
return PNG_get_height((PNG*) image);
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_GIF
|
||||
case IMAGE_FORMAT_GIF:
|
||||
return GIF_get_height((GIF*) image);
|
||||
#endif
|
||||
default:
|
||||
LOGE(MSG("Can't detect format %d"), format);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int get_byte_count(void* image, int format)
|
||||
{
|
||||
switch (format) {
|
||||
#ifdef IMAGE_SUPPORT_PLAIN
|
||||
case IMAGE_FORMAT_PLAIN:
|
||||
return PLAIN_get_byte_count((PLAIN*) image);
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_JPEG
|
||||
case IMAGE_FORMAT_JPEG:
|
||||
return JPEG_get_byte_count((JPEG*) image);
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_PNG
|
||||
case IMAGE_FORMAT_PNG:
|
||||
return PNG_get_byte_count((PNG*) image);
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_GIF
|
||||
case IMAGE_FORMAT_GIF:
|
||||
return GIF_get_byte_count((GIF*) image);
|
||||
#endif
|
||||
default:
|
||||
LOGE(MSG("Can't detect format %d"), format);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void render(void* image, int format, 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)
|
||||
{
|
||||
switch (format) {
|
||||
#ifdef IMAGE_SUPPORT_PLAIN
|
||||
case IMAGE_FORMAT_PLAIN:
|
||||
PLAIN_render((PLAIN*) image, src_x, src_y,
|
||||
dst, dst_w, dst_h, dst_x, dst_y,
|
||||
width, height, fill_blank, default_color);
|
||||
break;
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_JPEG
|
||||
case IMAGE_FORMAT_JPEG:
|
||||
JPEG_render((JPEG*) image, src_x, src_y,
|
||||
dst, dst_w, dst_h, dst_x, dst_y,
|
||||
width, height, fill_blank, default_color);
|
||||
break;
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_PNG
|
||||
case IMAGE_FORMAT_PNG:
|
||||
PNG_render((PNG*) image, src_x, src_y,
|
||||
dst, dst_w, dst_h, dst_x, dst_y,
|
||||
width, height, fill_blank, default_color);
|
||||
break;
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_GIF
|
||||
case IMAGE_FORMAT_GIF:
|
||||
GIF_render((GIF*) image, src_x, src_y,
|
||||
dst, dst_w, dst_h, dst_x, dst_y,
|
||||
width, height, fill_blank, default_color);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
LOGE(MSG("Can't detect format %d"), format);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void advance(void* image, int format)
|
||||
{
|
||||
switch (format) {
|
||||
#ifdef IMAGE_SUPPORT_PLAIN
|
||||
case IMAGE_FORMAT_PLAIN:
|
||||
PLAIN_advance((PLAIN*) image);
|
||||
break;
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_JPEG
|
||||
case IMAGE_FORMAT_JPEG:
|
||||
JPEG_advance((JPEG*) image);
|
||||
break;
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_PNG
|
||||
case IMAGE_FORMAT_PNG:
|
||||
PNG_advance((PNG*) image);
|
||||
break;
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_GIF
|
||||
case IMAGE_FORMAT_GIF:
|
||||
GIF_advance((GIF*) image);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
LOGE(MSG("Can't detect format %d"), format);
|
||||
}
|
||||
}
|
||||
|
||||
int get_delay(void* image, int format)
|
||||
{
|
||||
switch (format) {
|
||||
#ifdef IMAGE_SUPPORT_PLAIN
|
||||
case IMAGE_FORMAT_PLAIN:
|
||||
return PLAIN_get_delay((PLAIN*) image);
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_JPEG
|
||||
case IMAGE_FORMAT_JPEG:
|
||||
return JPEG_get_delay((JPEG*) image);
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_PNG
|
||||
case IMAGE_FORMAT_PNG:
|
||||
return PNG_get_delay((PNG*) image);
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_GIF
|
||||
case IMAGE_FORMAT_GIF:
|
||||
return GIF_get_delay((GIF*) image);
|
||||
#endif
|
||||
default:
|
||||
LOGE(MSG("Can't detect format %d"), format);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int get_frame_count(void* image, int format)
|
||||
{
|
||||
switch (format) {
|
||||
#ifdef IMAGE_SUPPORT_PLAIN
|
||||
case IMAGE_FORMAT_PLAIN:
|
||||
return PLAIN_get_frame_count((PLAIN*) image);
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_JPEG
|
||||
case IMAGE_FORMAT_JPEG:
|
||||
return JPEG_get_frame_count((JPEG*) image);
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_PNG
|
||||
case IMAGE_FORMAT_PNG:
|
||||
return PNG_get_frame_count((PNG*) image);
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_GIF
|
||||
case IMAGE_FORMAT_GIF:
|
||||
return GIF_get_frame_count((GIF*) image);
|
||||
#endif
|
||||
default:
|
||||
LOGE(MSG("Can't detect format %d"), format);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_opaque(void* image, int format)
|
||||
{
|
||||
switch (format) {
|
||||
#ifdef IMAGE_SUPPORT_PLAIN
|
||||
case IMAGE_FORMAT_PLAIN:
|
||||
return PLAIN_is_opaque((PLAIN*) image);
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_JPEG
|
||||
case IMAGE_FORMAT_JPEG:
|
||||
return JPEG_is_opaque((JPEG*) image);
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_PNG
|
||||
case IMAGE_FORMAT_PNG:
|
||||
return PNG_is_opaque((PNG*) image);
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_GIF
|
||||
case IMAGE_FORMAT_GIF:
|
||||
return GIF_is_opaque((GIF*) image);
|
||||
#endif
|
||||
default:
|
||||
LOGE(MSG("Can't detect format %d"), format);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void get_image_data(void* image, int format, void** pixel, int* width, int* height) {
|
||||
switch (format) {
|
||||
#ifdef IMAGE_SUPPORT_PLAIN
|
||||
case IMAGE_FORMAT_PLAIN: {
|
||||
PLAIN* plain = (PLAIN*) image;
|
||||
*pixel = PLAIN_get_pixels(plain);
|
||||
*width = PLAIN_get_width(plain);
|
||||
*height = PLAIN_get_height(plain);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_JPEG
|
||||
case IMAGE_FORMAT_JPEG: {
|
||||
JPEG* jpeg = (JPEG*) image;
|
||||
*pixel = JPEG_get_pixels(jpeg);
|
||||
*width = JPEG_get_width(jpeg);
|
||||
*height = JPEG_get_height(jpeg);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_PNG
|
||||
case IMAGE_FORMAT_PNG: {
|
||||
PNG* png = (PNG*) image;
|
||||
*pixel = PNG_get_pixels(png);
|
||||
*width = PNG_get_width(png);
|
||||
*height = PNG_get_height(png);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_GIF
|
||||
case IMAGE_FORMAT_GIF: {
|
||||
GIF* gif = (GIF*) image;
|
||||
*pixel = GIF_get_pixels(gif);
|
||||
*width = GIF_get_width(gif);
|
||||
*height = GIF_get_height(gif);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
*pixel = NULL;
|
||||
*width = 0;
|
||||
*height = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_gray(void* 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(void* 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, void* image, int format)
|
||||
{
|
||||
switch (format) {
|
||||
#ifdef IMAGE_SUPPORT_PLAIN
|
||||
case IMAGE_FORMAT_PLAIN:
|
||||
PLAIN_recycle((PLAIN*) image);
|
||||
break;
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_JPEG
|
||||
case IMAGE_FORMAT_JPEG:
|
||||
JPEG_recycle((JPEG*) image);
|
||||
break;
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_PNG
|
||||
case IMAGE_FORMAT_PNG:
|
||||
PNG_recycle(env, (PNG*) image);
|
||||
break;
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_GIF
|
||||
case IMAGE_FORMAT_GIF:
|
||||
GIF_recycle(env, (GIF*) image);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
LOGE(MSG("Can't detect format %d"), format);
|
||||
}
|
||||
}
|
||||
|
||||
int get_supported_formats(int *formats)
|
||||
{
|
||||
int i = 0;
|
||||
#ifdef IMAGE_SUPPORT_JPEG
|
||||
formats[i++] = IMAGE_FORMAT_JPEG;
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_PNG
|
||||
formats[i++] = IMAGE_FORMAT_PNG;
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_GIF
|
||||
formats[i++] = IMAGE_FORMAT_GIF;
|
||||
#endif
|
||||
return i;
|
||||
}
|
||||
|
||||
const char *get_decoder_description(int format)
|
||||
{
|
||||
switch (format) {
|
||||
#ifdef IMAGE_SUPPORT_JPEG
|
||||
case IMAGE_FORMAT_JPEG:
|
||||
return IMAGE_JPEG_DECODER_DESCRIPTION;
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_PNG
|
||||
case IMAGE_FORMAT_PNG:
|
||||
return IMAGE_PNG_DECODER_DESCRIPTION;
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_GIF
|
||||
case IMAGE_FORMAT_GIF:
|
||||
return IMAGE_GIF_DECODER_DESCRIPTION;
|
||||
#endif
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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/27/2015.
|
||||
//
|
||||
|
||||
#ifndef IMAGE_IMAGE_H
|
||||
#define IMAGE_IMAGE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "input_stream.h"
|
||||
|
||||
#define IMAGE_FORMAT_UNKNOWN -1
|
||||
#ifdef IMAGE_SUPPORT_PLAIN
|
||||
#define IMAGE_FORMAT_PLAIN 0
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_JPEG
|
||||
#define IMAGE_FORMAT_JPEG 1
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_PNG
|
||||
#define IMAGE_FORMAT_PNG 2
|
||||
#endif
|
||||
#ifdef IMAGE_SUPPORT_GIF
|
||||
#define IMAGE_FORMAT_GIF 3
|
||||
#endif
|
||||
|
||||
#define IMAGE_MAX_SUPPORTED_FORMAT_COUNT 3
|
||||
|
||||
void* decode(JNIEnv* env, InputStream* stream, bool partially, int* format);
|
||||
void* create(unsigned int width, unsigned int height, const void* data);
|
||||
bool complete(JNIEnv* env, void* image, int format);
|
||||
bool is_completed(void* image, int format);
|
||||
int get_width(void* image, int format);
|
||||
int get_height(void* image, int format);
|
||||
int get_byte_count(void* image, int format);
|
||||
void render(void* image, int format, 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);
|
||||
void advance(void* image, int format);
|
||||
int get_delay(void* image, int format);
|
||||
int get_frame_count(void* image, int format);
|
||||
bool is_opaque(void* image, int format);
|
||||
bool is_gray(void* image, int format, int error);
|
||||
void clahe(void* image, int format, bool to_gray);
|
||||
void recycle(JNIEnv *env, void* image, int format);
|
||||
int get_supported_formats(int *);
|
||||
const char *get_decoder_description(int);
|
||||
|
||||
#endif //IMAGE_IMAGE_H
|
||||
@@ -0,0 +1,558 @@
|
||||
/*
|
||||
* 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/27/2015.
|
||||
//
|
||||
|
||||
#include "config.h"
|
||||
#ifdef IMAGE_SUPPORT_GIF
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "image_gif.h"
|
||||
#include "image_utils.h"
|
||||
#include "java_wrapper.h"
|
||||
#include "../log.h"
|
||||
#include "../utils.h"
|
||||
|
||||
static int error_code = 0;
|
||||
|
||||
typedef struct {
|
||||
unsigned char red;
|
||||
unsigned char green;
|
||||
unsigned char blue;
|
||||
unsigned char alpha;
|
||||
} RGBA;
|
||||
|
||||
static int custom_read_fun(GifFileType* gif, GifByteType* bytes, int size) {
|
||||
bool attach;
|
||||
int read;
|
||||
PatchHeadInputStream* patch_head_input_stream = gif->UserData;
|
||||
JNIEnv *env = obtain_env(&attach);
|
||||
|
||||
if (env == NULL) {
|
||||
LOGE(MSG("Can't get JNIEnv"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
read = read_patch_head_input_stream(env, patch_head_input_stream, bytes, 0, (size_t) size);
|
||||
|
||||
if (attach) {
|
||||
release_env();
|
||||
}
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
static void generate_prepare(GIF_FRAME_INFO* frame_info_array, int count)
|
||||
{
|
||||
int disposal = 0xff;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++){
|
||||
GIF_FRAME_INFO* frame_info = frame_info_array + i;
|
||||
|
||||
switch (disposal) {
|
||||
case DISPOSAL_UNSPECIFIED:
|
||||
case DISPOSE_DO_NOT:
|
||||
frame_info->prepare = IMAGE_GIF_PREPARE_NONE;
|
||||
break;
|
||||
case DISPOSE_BACKGROUND:
|
||||
frame_info->prepare = IMAGE_GIF_PREPARE_BACKGROUND;
|
||||
break;
|
||||
case DISPOSE_PREVIOUS:
|
||||
frame_info->prepare = IMAGE_GIF_PREPARE_USE_BACKUP;
|
||||
break;
|
||||
default:
|
||||
frame_info->prepare = IMAGE_GIF_PREPARE_BACKGROUND;
|
||||
break;
|
||||
}
|
||||
|
||||
disposal = frame_info->disposal;
|
||||
}
|
||||
}
|
||||
|
||||
static void read_gcb(GifFileType* gif_file, int index, GIF_FRAME_INFO* frame_info)
|
||||
{
|
||||
GraphicsControlBlock gcb;
|
||||
if (DGifSavedExtensionToGCB(gif_file, index, &gcb) == GIF_OK) {
|
||||
frame_info->tran = gcb.TransparentColor;
|
||||
frame_info->delay = gcb.DelayTime * 10;
|
||||
frame_info->disposal = gcb.DisposalMode;
|
||||
frame_info->prepare = IMAGE_GIF_PREPARE_UNKNOWN;
|
||||
} else {
|
||||
frame_info->tran = -1;
|
||||
frame_info->delay = 0;
|
||||
frame_info->disposal = DISPOSE_DO_NOT;
|
||||
frame_info->prepare = IMAGE_GIF_PREPARE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static void fix_gif_file(GifFileType* gif_file) {
|
||||
if (gif_file->ImageCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
SavedImage last_image = gif_file->SavedImages[gif_file->ImageCount - 1];
|
||||
// If RasterBits is NULL, discard this frame
|
||||
if (last_image.RasterBits == NULL) {
|
||||
gif_file->ImageCount--;
|
||||
// Free last image
|
||||
if (last_image.ImageDesc.ColorMap != NULL) {
|
||||
GifFreeMapObject(last_image.ImageDesc.ColorMap);
|
||||
last_image.ImageDesc.ColorMap = NULL;
|
||||
}
|
||||
GifFreeExtensions(&last_image.ExtensionBlockCount, &last_image.ExtensionBlocks);
|
||||
}
|
||||
}
|
||||
|
||||
void* GIF_decode(JNIEnv* env, PatchHeadInputStream* patch_head_input_stream, bool partially)
|
||||
{
|
||||
GIF* gif = NULL;
|
||||
GifFileType* gif_file = NULL;
|
||||
void* buffer = NULL;
|
||||
void*shown_buffer = NULL;
|
||||
GIF_FRAME_INFO* frame_info_array = NULL;
|
||||
int i;
|
||||
|
||||
gif = (GIF*) malloc(sizeof(GIF));
|
||||
if (gif == NULL) {
|
||||
WTF_OM;
|
||||
close_patch_head_input_stream(env, patch_head_input_stream);
|
||||
destroy_patch_head_input_stream(env, &patch_head_input_stream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Open
|
||||
gif_file = DGifOpen(patch_head_input_stream, &custom_read_fun, &error_code);
|
||||
if (gif_file == NULL) {
|
||||
WTF_OM;
|
||||
free(gif);
|
||||
close_patch_head_input_stream(env, patch_head_input_stream);
|
||||
destroy_patch_head_input_stream(env, &patch_head_input_stream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Buffer
|
||||
buffer = malloc(gif_file->SWidth * gif_file->SHeight * sizeof(RGBA));
|
||||
shown_buffer = malloc(gif_file->SWidth * gif_file->SHeight * sizeof(RGBA));
|
||||
if (buffer == NULL || shown_buffer == NULL) {
|
||||
WTF_OM;
|
||||
free(buffer);
|
||||
free(shown_buffer);
|
||||
DGifCloseFile(gif_file, &error_code);
|
||||
free(gif);
|
||||
close_patch_head_input_stream(env, patch_head_input_stream);
|
||||
destroy_patch_head_input_stream(env, &patch_head_input_stream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (partially) {
|
||||
// Glance
|
||||
if (DGifGlance(gif_file) != GIF_OK) {
|
||||
LOGE(MSG("GIF error code %d"), error_code);
|
||||
DGifCloseFile(gif_file, &error_code);
|
||||
free(buffer);
|
||||
free(gif);
|
||||
close_patch_head_input_stream(env, patch_head_input_stream);
|
||||
destroy_patch_head_input_stream(env, &patch_head_input_stream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Frame info
|
||||
frame_info_array = (GIF_FRAME_INFO*) malloc(sizeof(GIF_FRAME_INFO));
|
||||
if (frame_info_array == NULL) {
|
||||
WTF_OM;
|
||||
DGifCloseFile(gif_file, &error_code);
|
||||
free(buffer);
|
||||
free(gif);
|
||||
close_patch_head_input_stream(env, patch_head_input_stream);
|
||||
destroy_patch_head_input_stream(env, &patch_head_input_stream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Read gcb
|
||||
read_gcb(gif_file, 0, frame_info_array);
|
||||
|
||||
gif->partially = true;
|
||||
gif->patch_head_input_stream = patch_head_input_stream;
|
||||
} else {
|
||||
// Slurp
|
||||
if (DGifSlurp(gif_file) == GIF_ERROR) {
|
||||
fix_gif_file(gif_file);
|
||||
}
|
||||
if (gif_file->ImageCount <= 0) {
|
||||
LOGE(MSG("No frame"));
|
||||
DGifCloseFile(gif_file, &error_code);
|
||||
free(buffer);
|
||||
free(gif);
|
||||
close_patch_head_input_stream(env, patch_head_input_stream);
|
||||
destroy_patch_head_input_stream(env, &patch_head_input_stream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Frame info
|
||||
frame_info_array = (GIF_FRAME_INFO*) malloc(gif_file->ImageCount * sizeof(GIF_FRAME_INFO));
|
||||
if (frame_info_array == NULL) {
|
||||
WTF_OM;
|
||||
DGifCloseFile(gif_file, &error_code);
|
||||
free(buffer);
|
||||
free(gif);
|
||||
close_patch_head_input_stream(env, patch_head_input_stream);
|
||||
destroy_patch_head_input_stream(env, &patch_head_input_stream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Read gcb
|
||||
for (i = 0; i < gif_file->ImageCount; i++) {
|
||||
read_gcb(gif_file, i, frame_info_array + i);
|
||||
}
|
||||
|
||||
// Generate prepare
|
||||
generate_prepare(frame_info_array, gif_file->ImageCount);
|
||||
|
||||
// Close input stream
|
||||
close_patch_head_input_stream(env, patch_head_input_stream);
|
||||
destroy_patch_head_input_stream(env, &patch_head_input_stream);
|
||||
|
||||
gif->partially = false;
|
||||
gif->patch_head_input_stream = NULL;
|
||||
}
|
||||
|
||||
gif->gif_file = gif_file;
|
||||
gif->frame_info_array = frame_info_array;
|
||||
gif->buffer = buffer;
|
||||
gif->buffer_index = -1;
|
||||
gif->backup = NULL;
|
||||
gif->shown_buffer = shown_buffer;
|
||||
|
||||
GIF_advance(gif);
|
||||
|
||||
return gif;
|
||||
}
|
||||
|
||||
bool GIF_complete(JNIEnv* env, GIF* gif)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!gif->partially) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (gif->gif_file == NULL || gif->patch_head_input_stream == NULL) {
|
||||
LOGE(MSG("Some stuff is NULL"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DGifSlurp(gif->gif_file) == GIF_ERROR) {
|
||||
fix_gif_file(gif->gif_file);
|
||||
}
|
||||
|
||||
// Close input stream
|
||||
close_patch_head_input_stream(env, gif->patch_head_input_stream);
|
||||
destroy_patch_head_input_stream(env, &gif->patch_head_input_stream);
|
||||
gif->patch_head_input_stream = NULL;
|
||||
|
||||
gif->partially = false;
|
||||
|
||||
gif->frame_info_array = (GIF_FRAME_INFO*) realloc(gif->frame_info_array,
|
||||
gif->gif_file->ImageCount * sizeof(GIF_FRAME_INFO));
|
||||
if (gif->frame_info_array == NULL) {
|
||||
WTF_OM;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read gcb
|
||||
for (i = 0; i < gif->gif_file->ImageCount; i++) {
|
||||
read_gcb(gif->gif_file, i, gif->frame_info_array + i);
|
||||
}
|
||||
|
||||
// Generate prepare
|
||||
generate_prepare(gif->frame_info_array, gif->gif_file->ImageCount);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GIF_is_completed(GIF* gif)
|
||||
{
|
||||
return !gif->partially;
|
||||
}
|
||||
|
||||
void* GIF_get_pixels(GIF* gif)
|
||||
{
|
||||
if (!gif->partially && GIF_get_frame_count(gif) == 1) {
|
||||
return gif->buffer;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int GIF_get_width(GIF* gif)
|
||||
{
|
||||
return gif->gif_file->SWidth;
|
||||
}
|
||||
|
||||
int GIF_get_height(GIF* gif)
|
||||
{
|
||||
return gif->gif_file->SHeight;
|
||||
}
|
||||
|
||||
int GIF_get_byte_count(GIF* gif)
|
||||
{
|
||||
int i;
|
||||
SavedImage saved_image;
|
||||
int size = 0;
|
||||
// Add buffer size
|
||||
if (gif->buffer != NULL) {
|
||||
size += gif->gif_file->SWidth * gif->gif_file->SHeight * 4;
|
||||
}
|
||||
// Add backup size
|
||||
if (gif->backup != NULL) {
|
||||
size += gif->gif_file->SWidth * gif->gif_file->SHeight * 4;
|
||||
}
|
||||
// Add shown buffer size
|
||||
if (gif->shown_buffer != NULL) {
|
||||
size += gif->gif_file->SWidth * gif->gif_file->SHeight * 4;
|
||||
}
|
||||
// Add frames size
|
||||
if (gif->gif_file->SavedImages != NULL) {
|
||||
for (i = 0; i < gif->gif_file->ImageCount; i++) {
|
||||
saved_image = gif->gif_file->SavedImages[i];
|
||||
if (saved_image.RasterBits != NULL) {
|
||||
size += saved_image.ImageDesc.Width * saved_image.ImageDesc.Height * 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void GIF_render(GIF* gif, 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)
|
||||
{
|
||||
copy_pixels(gif->shown_buffer, gif->gif_file->SWidth, gif->gif_file->SHeight, src_x, src_y,
|
||||
dst, dst_w, dst_h, dst_x, dst_y,
|
||||
width, height, fill_blank, default_color);
|
||||
}
|
||||
|
||||
static void backup(GIF* gif)
|
||||
{
|
||||
if (gif->backup == NULL) {
|
||||
gif->backup = (unsigned char*) malloc((size_t) (gif->gif_file->SWidth * gif->gif_file->SHeight * 4));
|
||||
if (gif->backup == NULL) {
|
||||
WTF_OM;
|
||||
return;
|
||||
}
|
||||
}
|
||||
memcpy(gif->backup, gif->buffer, (size_t) (gif->gif_file->SWidth * gif->gif_file->SHeight * 4));
|
||||
}
|
||||
|
||||
static void restore(GIF* gif)
|
||||
{
|
||||
if (gif->backup == NULL) {
|
||||
LOGE(MSG("Backup is NULL"));
|
||||
} else {
|
||||
memcpy(gif->buffer, gif->backup, (size_t) (gif->gif_file->SWidth * gif->gif_file->SHeight * 4));
|
||||
}
|
||||
}
|
||||
|
||||
static void switch_buffer_backup(GIF* gif)
|
||||
{
|
||||
unsigned char* temp;
|
||||
|
||||
if (gif->backup == NULL) {
|
||||
backup(gif);
|
||||
} else {
|
||||
temp = gif->buffer;
|
||||
gif->buffer = gif->backup;
|
||||
gif->backup = temp;
|
||||
}
|
||||
}
|
||||
|
||||
static void clear(RGBA* pixels, int num, RGBA color) {
|
||||
RGBA* ptr = pixels;
|
||||
int i;
|
||||
for (i = 0; i < num; i++) {
|
||||
*(ptr++) = color;
|
||||
}
|
||||
}
|
||||
|
||||
static bool get_color_from_table(const ColorMapObject* cmap, int index,
|
||||
RGBA* color) {
|
||||
if (cmap == NULL || index < 0 || index >= cmap->ColorCount) {
|
||||
return false;
|
||||
} else {
|
||||
GifColorType gct = cmap->Colors[index];
|
||||
color->red = gct.Red;
|
||||
color->green = gct.Green;
|
||||
color->blue = gct.Blue;
|
||||
color->alpha = 0xff;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static void clear_bg(GifFileType* gif_file, void* pixels)
|
||||
{
|
||||
RGBA color;
|
||||
if (!get_color_from_table(gif_file->SColorMap, gif_file->SBackGroundColor, &color)) {
|
||||
color.red = 0x00;
|
||||
color.green = 0x00;
|
||||
color.blue = 0x00;
|
||||
color.alpha = 0x00;
|
||||
}
|
||||
clear(pixels, gif_file->SWidth * gif_file->SHeight, color);
|
||||
}
|
||||
|
||||
static void copy_line(GifByteType* src, RGBA* dst,
|
||||
const ColorMapObject* cmap, int tran, int len)
|
||||
{
|
||||
for (; len > 0; len--, src++, dst++) {
|
||||
int index = *src;
|
||||
if (tran == -1 || index != tran) {
|
||||
get_color_from_table(cmap, index, dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void blend(GifFileType* gif_file, int index, void* pixels, int tran)
|
||||
{
|
||||
int width = gif_file->SWidth;
|
||||
int height = gif_file->SHeight;
|
||||
SavedImage cur = gif_file->SavedImages[index];
|
||||
GifImageDesc desc = cur.ImageDesc;
|
||||
int copy_width = MIN(width - desc.Left, desc.Width);
|
||||
int copy_height = MIN(height - desc.Top, desc.Height);
|
||||
ColorMapObject *cmap = desc.ColorMap;
|
||||
GifByteType* src = cur.RasterBits;
|
||||
RGBA* dst = pixels;
|
||||
GifByteType* src_ptr;
|
||||
RGBA* dst_ptr;
|
||||
size_t len;
|
||||
int i;
|
||||
|
||||
if (cmap == NULL) {
|
||||
cmap = gif_file->SColorMap;
|
||||
}
|
||||
if (cmap != NULL) {
|
||||
for (i = 0; i < copy_height; i++) {
|
||||
src_ptr = src + (i * desc.Width);
|
||||
dst_ptr = dst + ((desc.Top + i) * width + desc.Left);
|
||||
len = (size_t) copy_width;
|
||||
copy_line(src_ptr, dst_ptr, cmap, tran, len);
|
||||
}
|
||||
} else {
|
||||
LOGW(MSG("Can't find color map"));
|
||||
}
|
||||
}
|
||||
|
||||
void GIF_advance(GIF* gif)
|
||||
{
|
||||
int index;
|
||||
GIF_FRAME_INFO frame_info;
|
||||
|
||||
index = (gif->buffer_index + 1) % gif->gif_file->ImageCount;
|
||||
if (index != 0 && gif->partially) {
|
||||
LOGE(MSG("The png is only decoded partially. Only the first frame can be shown."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (gif->frame_info_array == NULL) {
|
||||
frame_info.tran = -1;
|
||||
frame_info.disposal = DISPOSE_DO_NOT;
|
||||
frame_info.delay = 0;
|
||||
frame_info.prepare = IMAGE_GIF_PREPARE_BACKGROUND;
|
||||
} else {
|
||||
memcpy(&frame_info, gif->frame_info_array + index, sizeof(GIF_FRAME_INFO));
|
||||
}
|
||||
|
||||
if (frame_info.disposal == DISPOSE_PREVIOUS && frame_info.prepare == IMAGE_GIF_PREPARE_USE_BACKUP) {
|
||||
switch_buffer_backup(gif);
|
||||
} else {
|
||||
// Backup
|
||||
if (frame_info.disposal == DISPOSE_PREVIOUS) {
|
||||
backup(gif);
|
||||
}
|
||||
|
||||
// Prepare
|
||||
switch (frame_info.prepare) {
|
||||
case IMAGE_GIF_PREPARE_NONE:
|
||||
// Do nothing
|
||||
break;
|
||||
default:
|
||||
case IMAGE_GIF_PREPARE_BACKGROUND:
|
||||
// Set bg
|
||||
clear_bg(gif->gif_file, gif->buffer);
|
||||
break;
|
||||
case IMAGE_GIF_PREPARE_USE_BACKUP:
|
||||
restore(gif);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
blend(gif->gif_file, index, gif->buffer, frame_info.tran);
|
||||
|
||||
// Copy to shown buffer
|
||||
memcpy(gif->shown_buffer, gif->buffer, (size_t) (gif->gif_file->SWidth * gif->gif_file->SHeight * 4));
|
||||
|
||||
gif->buffer_index = index;
|
||||
}
|
||||
|
||||
int GIF_get_delay(GIF* gif)
|
||||
{
|
||||
if (gif->frame_info_array == NULL) {
|
||||
return 0;
|
||||
} else {
|
||||
return gif->frame_info_array[gif->buffer_index].delay;
|
||||
}
|
||||
}
|
||||
|
||||
int GIF_get_frame_count(GIF* gif)
|
||||
{
|
||||
return gif->gif_file->ImageCount;
|
||||
}
|
||||
|
||||
bool GIF_is_opaque(GIF* gif)
|
||||
{
|
||||
return gif->frame_info_array->tran < 0;
|
||||
}
|
||||
|
||||
void GIF_recycle(JNIEnv* env, GIF* gif)
|
||||
{
|
||||
DGifCloseFile(gif->gif_file, &error_code);
|
||||
gif->gif_file = NULL;
|
||||
|
||||
free(gif->frame_info_array);
|
||||
gif->frame_info_array = NULL;
|
||||
|
||||
free(gif->buffer);
|
||||
gif->buffer = NULL;
|
||||
|
||||
free(gif->backup);
|
||||
gif->backup = NULL;
|
||||
|
||||
free(gif->shown_buffer);
|
||||
gif->shown_buffer = NULL;
|
||||
|
||||
if (gif->patch_head_input_stream != NULL) {
|
||||
close_patch_head_input_stream(env, gif->patch_head_input_stream);
|
||||
destroy_patch_head_input_stream(env, &gif->patch_head_input_stream);
|
||||
gif->patch_head_input_stream = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // IMAGE_SUPPORT_GIF
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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/27/2015.
|
||||
//
|
||||
|
||||
#ifndef IMAGE_IMAGE_GIF_H
|
||||
#define IMAGE_IMAGE_GIF_H
|
||||
|
||||
#include "config.h"
|
||||
#ifdef IMAGE_SUPPORT_GIF
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "patch_head_input_stream.h"
|
||||
#include "gif_lib.h"
|
||||
#include "../utils.h"
|
||||
|
||||
#define IMAGE_GIF_DECODER_DESCRIPTION ("giflib " MAKESTRING(STRINGIZE, GIFLIB_MAJOR) "." \
|
||||
MAKESTRING(STRINGIZE, GIFLIB_MINOR) "." \
|
||||
MAKESTRING(STRINGIZE, GIFLIB_RELEASE))
|
||||
|
||||
#define IMAGE_GIF_MAGIC_NUMBER_0 0x47
|
||||
#define IMAGE_GIF_MAGIC_NUMBER_1 0x49
|
||||
|
||||
#define IMAGE_GIF_PREPARE_UNKNOWN 0x00
|
||||
#define IMAGE_GIF_PREPARE_NONE 0x01
|
||||
#define IMAGE_GIF_PREPARE_BACKGROUND 0x02
|
||||
#define IMAGE_GIF_PREPARE_USE_BACKUP 0x03
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int tran;
|
||||
int disposal;
|
||||
int delay;
|
||||
int prepare;
|
||||
} GIF_FRAME_INFO;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GifFileType* gif_file;
|
||||
GIF_FRAME_INFO* frame_info_array;
|
||||
void* buffer;
|
||||
int buffer_index;
|
||||
void* backup;
|
||||
bool partially;
|
||||
// Use extra buffer to avoid blink
|
||||
void* shown_buffer;
|
||||
PatchHeadInputStream* patch_head_input_stream;
|
||||
} GIF;
|
||||
|
||||
void* GIF_decode(JNIEnv* env, PatchHeadInputStream* patch_head_input_stream, bool partially);
|
||||
bool GIF_complete(JNIEnv* env, GIF* gif);
|
||||
bool GIF_is_completed(GIF* gif);
|
||||
void* GIF_get_pixels(GIF* gif);
|
||||
int GIF_get_width(GIF* gif);
|
||||
int GIF_get_height(GIF* gif);
|
||||
int GIF_get_byte_count(GIF* gif);
|
||||
void GIF_render(GIF* gif, 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);
|
||||
void GIF_advance(GIF* gif);
|
||||
int GIF_get_delay(GIF* gif);
|
||||
int GIF_get_frame_count(GIF* gif);
|
||||
bool GIF_is_opaque(GIF* gif);
|
||||
void GIF_recycle(JNIEnv* env, GIF* gif);
|
||||
|
||||
#endif // IMAGE_SUPPORT_GIF
|
||||
|
||||
#endif // IMAGE_IMAGE_GIF_H
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// Created by Hippo on 1/3/2016.
|
||||
//
|
||||
|
||||
#include "config.h"
|
||||
#ifdef IMAGE_SUPPORT_JPEG
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "image_jpeg.h"
|
||||
#include "image_utils.h"
|
||||
#include "java_wrapper.h"
|
||||
#include "../log.h"
|
||||
|
||||
struct my_error_mgr {
|
||||
struct jpeg_error_mgr pub;
|
||||
jmp_buf setjmp_buffer;
|
||||
};
|
||||
|
||||
typedef struct my_error_mgr * my_error_ptr;
|
||||
|
||||
static char emsg[JMSG_LENGTH_MAX];
|
||||
|
||||
static void my_error_exit(j_common_ptr cinfo)
|
||||
{
|
||||
my_error_ptr myerr = (my_error_ptr) cinfo->err;
|
||||
(*cinfo->err->format_message)(cinfo, emsg);
|
||||
longjmp(myerr->setjmp_buffer, 1);
|
||||
}
|
||||
|
||||
static size_t custom_read(void * custom_stuff, unsigned char * buffer, size_t size)
|
||||
{
|
||||
bool attach;
|
||||
size_t read;
|
||||
PatchHeadInputStream* patch_head_input_stream = custom_stuff;
|
||||
JNIEnv *env = obtain_env(&attach);
|
||||
|
||||
if (env == NULL) {
|
||||
LOGE(MSG("Can't get JNIEnv"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
read = read_patch_head_input_stream(env, patch_head_input_stream, buffer, 0, size);
|
||||
|
||||
if (attach) {
|
||||
release_env();
|
||||
}
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
void* JPEG_decode(JNIEnv* env, PatchHeadInputStream* patch_head_input_stream, bool partially)
|
||||
{
|
||||
JPEG* jpeg = NULL;
|
||||
struct jpeg_decompress_struct cinfo;
|
||||
struct my_error_mgr jerr;
|
||||
unsigned char* buffer = NULL;
|
||||
size_t stride;
|
||||
unsigned char* line_buffer_array[3];
|
||||
int read_lines;
|
||||
|
||||
jpeg = (JPEG*) malloc(sizeof(JPEG));
|
||||
if (jpeg == NULL) {
|
||||
WTF_OM;
|
||||
close_patch_head_input_stream(env, patch_head_input_stream);
|
||||
destroy_patch_head_input_stream(env, &patch_head_input_stream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Init
|
||||
cinfo.err = jpeg_std_error(&jerr.pub);
|
||||
jerr.pub.error_exit = my_error_exit;
|
||||
if (setjmp(jerr.setjmp_buffer)) {
|
||||
LOGE(MSG("%s"), emsg);
|
||||
free(jpeg);
|
||||
free(buffer);
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
close_patch_head_input_stream(env, patch_head_input_stream);
|
||||
destroy_patch_head_input_stream(env, &patch_head_input_stream);
|
||||
return NULL;
|
||||
}
|
||||
jpeg_create_decompress(&cinfo);
|
||||
jpeg_custom_src(&cinfo, &custom_read, patch_head_input_stream);
|
||||
jpeg_read_header(&cinfo, TRUE);
|
||||
|
||||
// Start decompress
|
||||
cinfo.out_color_space = JCS_EXT_RGBA;
|
||||
jpeg_start_decompress(&cinfo);
|
||||
|
||||
stride = cinfo.output_components * cinfo.output_width;
|
||||
buffer = malloc(stride * cinfo.output_height);
|
||||
if (buffer == NULL) {
|
||||
free(jpeg);
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
close_patch_head_input_stream(env, patch_head_input_stream);
|
||||
destroy_patch_head_input_stream(env, &patch_head_input_stream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Copy buffer
|
||||
line_buffer_array[0] = buffer;
|
||||
line_buffer_array[1] = line_buffer_array[0] + stride;
|
||||
line_buffer_array[2] = line_buffer_array[1] + stride;
|
||||
while (cinfo.output_scanline < cinfo.output_height) {
|
||||
read_lines = jpeg_read_scanlines(&cinfo, line_buffer_array, 3);
|
||||
line_buffer_array[0] += stride * read_lines;
|
||||
line_buffer_array[1] = line_buffer_array[0] + stride;
|
||||
line_buffer_array[2] = line_buffer_array[1] + stride;
|
||||
}
|
||||
|
||||
// Finish decompress
|
||||
jpeg_finish_decompress(&cinfo);
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
|
||||
// Close stream
|
||||
close_patch_head_input_stream(env, patch_head_input_stream);
|
||||
destroy_patch_head_input_stream(env, &patch_head_input_stream);
|
||||
|
||||
// Fill jpeg
|
||||
jpeg->width = cinfo.output_width;
|
||||
jpeg->height = cinfo.output_height;
|
||||
jpeg->buffer = buffer;
|
||||
|
||||
return jpeg;
|
||||
}
|
||||
|
||||
bool JPEG_complete(JPEG* jpeg)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JPEG_is_completed(JPEG* jpeg)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void* JPEG_get_pixels(JPEG* jpeg)
|
||||
{
|
||||
return jpeg->buffer;
|
||||
}
|
||||
|
||||
int JPEG_get_width(JPEG* jpeg)
|
||||
{
|
||||
return jpeg->width;
|
||||
}
|
||||
|
||||
int JPEG_get_height(JPEG* jpeg)
|
||||
{
|
||||
return jpeg->height;
|
||||
}
|
||||
|
||||
int JPEG_get_byte_count(JPEG* jpeg)
|
||||
{
|
||||
return jpeg->width * jpeg->height * 4;
|
||||
}
|
||||
|
||||
void JPEG_render(JPEG* jpeg, 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)
|
||||
{
|
||||
copy_pixels(jpeg->buffer, jpeg->width, jpeg->height, src_x, src_y,
|
||||
dst, dst_w, dst_h, dst_x, dst_y,
|
||||
width, height, fill_blank, default_color);
|
||||
}
|
||||
|
||||
void JPEG_advance(JPEG* jpeg)
|
||||
{
|
||||
}
|
||||
|
||||
int JPEG_get_delay(JPEG* jpeg)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int JPEG_get_frame_count(JPEG* jpeg)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool JPEG_is_opaque(JPEG* jpeg)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void JPEG_recycle(JPEG* jpeg)
|
||||
{
|
||||
free(jpeg->buffer);
|
||||
jpeg->buffer = NULL;
|
||||
|
||||
free(jpeg);
|
||||
}
|
||||
|
||||
#endif // IMAGE_SUPPORT_JPEG
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// Created by Hippo on 1/3/2016.
|
||||
//
|
||||
|
||||
#ifndef IMAGE_IMAGE_JPEG_H
|
||||
#define IMAGE_IMAGE_JPEG_H
|
||||
|
||||
#include "config.h"
|
||||
#ifdef IMAGE_SUPPORT_JPEG
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "jpeglib.h"
|
||||
#include "patch_head_input_stream.h"
|
||||
#include "../utils.h"
|
||||
|
||||
#define IMAGE_JPEG_DECODER_DESCRIPTION ("libjpeg-turbo " MAKESTRING(STRINGIZE, LIBJPEG_TURBO_VERSION))
|
||||
|
||||
#define IMAGE_JPEG_MAGIC_NUMBER_0 0xFF
|
||||
#define IMAGE_JPEG_MAGIC_NUMBER_1 0xD8
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
void* buffer;
|
||||
} JPEG;
|
||||
|
||||
void* JPEG_decode(JNIEnv* env, PatchHeadInputStream* patch_head_input_stream, bool partially);
|
||||
bool JPEG_complete(JPEG* jpeg);
|
||||
bool JPEG_is_completed(JPEG* jpeg);
|
||||
void* JPEG_get_pixels(JPEG* jpeg);
|
||||
int JPEG_get_width(JPEG* jpeg);
|
||||
int JPEG_get_height(JPEG* jpeg);
|
||||
int JPEG_get_byte_count(JPEG* jpeg);
|
||||
void JPEG_render(JPEG* jpeg, 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);
|
||||
void JPEG_advance(JPEG* jpeg);
|
||||
int JPEG_get_delay(JPEG* jpeg);
|
||||
int JPEG_get_frame_count(JPEG* jpeg);
|
||||
bool JPEG_is_opaque(JPEG* jpeg);
|
||||
void JPEG_recycle(JPEG* jpeg);
|
||||
|
||||
#endif // IMAGE_SUPPORT_JPEG
|
||||
|
||||
#endif // IMAGE_IMAGE_JPEG_H
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// Created by Hippo on 5/3/2016.
|
||||
//
|
||||
|
||||
#include "config.h"
|
||||
#ifdef IMAGE_SUPPORT_PLAIN
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "image_plain.h"
|
||||
#include "image_utils.h"
|
||||
#include "../log.h"
|
||||
|
||||
void* PLAIN_create(unsigned int width, unsigned int height, const void* data)
|
||||
{
|
||||
PLAIN* plain = NULL;
|
||||
void* buffer = NULL;
|
||||
size_t length;
|
||||
|
||||
plain = (PLAIN*) malloc(sizeof(PLAIN));
|
||||
if (plain == NULL) {
|
||||
WTF_OM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
length = (size_t) (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;
|
||||
|
||||
return plain;
|
||||
}
|
||||
|
||||
bool PLAIN_complete(PLAIN* plain)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PLAIN_is_completed(PLAIN* plain)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void* PLAIN_get_pixels(PLAIN* plain)
|
||||
{
|
||||
return plain->buffer;
|
||||
}
|
||||
|
||||
int PLAIN_get_width(PLAIN* plain)
|
||||
{
|
||||
return plain->width;
|
||||
}
|
||||
|
||||
int PLAIN_get_height(PLAIN* plain)
|
||||
{
|
||||
return plain->height;
|
||||
}
|
||||
|
||||
int PLAIN_get_byte_count(PLAIN* plain)
|
||||
{
|
||||
return plain->width * plain->height * 4;
|
||||
}
|
||||
|
||||
void PLAIN_render(PLAIN* plain, 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)
|
||||
{
|
||||
copy_pixels(plain->buffer, plain->width, plain->height, src_x, src_y,
|
||||
dst, dst_w, dst_h, dst_x, dst_y,
|
||||
width, height, fill_blank, default_color);
|
||||
}
|
||||
|
||||
void PLAIN_advance(PLAIN* plain)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int PLAIN_get_delay(PLAIN* plain)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PLAIN_get_frame_count(PLAIN* plain)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool PLAIN_is_opaque(PLAIN* plain)
|
||||
{
|
||||
// TODO Check plain all alpha
|
||||
return false;
|
||||
}
|
||||
|
||||
void PLAIN_recycle(PLAIN* plain)
|
||||
{
|
||||
free(plain->buffer);
|
||||
plain->buffer = NULL;
|
||||
|
||||
free(plain);
|
||||
}
|
||||
|
||||
#endif // IMAGE_SUPPORT_PLAIN
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// Created by Hippo on 5/3/2016.
|
||||
//
|
||||
|
||||
#ifndef IMAGE_IMAGE_PLAIN_H
|
||||
#define IMAGE_IMAGE_PLAIN_H
|
||||
|
||||
#include "config.h"
|
||||
#ifdef IMAGE_SUPPORT_PLAIN
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "patch_head_input_stream.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
void* buffer;
|
||||
} PLAIN;
|
||||
|
||||
void* PLAIN_create(unsigned int width, unsigned int height, const void* data);
|
||||
bool PLAIN_complete(PLAIN* plain);
|
||||
bool PLAIN_is_completed(PLAIN* plain);
|
||||
void* PLAIN_get_pixels(PLAIN* plain);
|
||||
int PLAIN_get_width(PLAIN* plain);
|
||||
int PLAIN_get_height(PLAIN* plain);
|
||||
int PLAIN_get_byte_count(PLAIN* plain);
|
||||
void PLAIN_render(PLAIN* plain, 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);
|
||||
void PLAIN_advance(PLAIN* plain);
|
||||
int PLAIN_get_delay(PLAIN* plain);
|
||||
int PLAIN_get_frame_count(PLAIN* plain);
|
||||
bool PLAIN_is_opaque(PLAIN* plain);
|
||||
void PLAIN_recycle(PLAIN* plain);
|
||||
|
||||
#endif // IMAGE_SUPPORT_PLAIN
|
||||
|
||||
#endif // IMAGE_IMAGE_PLAIN_H
|
||||
@@ -0,0 +1,642 @@
|
||||
/*
|
||||
* 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/27/2015.
|
||||
//
|
||||
|
||||
#include "config.h"
|
||||
#ifdef IMAGE_SUPPORT_PNG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../log.h"
|
||||
#include "../utils.h"
|
||||
#include "image_png.h"
|
||||
#include "image_utils.h"
|
||||
#include "java_wrapper.h"
|
||||
|
||||
static void user_read_fn(png_structp png_ptr,
|
||||
png_bytep data, png_size_t length)
|
||||
{
|
||||
bool attach;
|
||||
PatchHeadInputStream* patch_head_input_stream = png_get_io_ptr(png_ptr);
|
||||
JNIEnv *env = obtain_env(&attach);
|
||||
|
||||
if (env == NULL) {
|
||||
LOGE(MSG("Can't get JNIEnv"));
|
||||
}
|
||||
|
||||
read_patch_head_input_stream(env, patch_head_input_stream, data, 0, length);
|
||||
|
||||
if (attach) {
|
||||
release_env();
|
||||
}
|
||||
}
|
||||
|
||||
static void user_error_fn(png_structp png_ptr,
|
||||
png_const_charp error_msg)
|
||||
{
|
||||
LOGE(MSG("%s"), error_msg);
|
||||
}
|
||||
|
||||
static void user_warn_fn(png_structp png_ptr,
|
||||
png_const_charp error_msg)
|
||||
{
|
||||
LOGW(MSG("%s"), error_msg);
|
||||
}
|
||||
|
||||
static void free_frame_info_array(PNG_FRAME_INFO* frame_info_array, unsigned int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (frame_info_array == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
PNG_FRAME_INFO* frame_info = frame_info_array + i;
|
||||
free(frame_info->buffer);
|
||||
frame_info->buffer = NULL;
|
||||
}
|
||||
free(frame_info_array);
|
||||
}
|
||||
|
||||
static bool read_image(png_structp png_ptr, unsigned char* buffer, unsigned int width, unsigned int height)
|
||||
{
|
||||
int i;
|
||||
unsigned char** line_buffer_ptr_array = (unsigned char**) malloc(height * sizeof(unsigned char*));
|
||||
if (line_buffer_ptr_array == NULL) {
|
||||
WTF_OM;
|
||||
return false;
|
||||
}
|
||||
for (i = 0; i < height; i++) {
|
||||
line_buffer_ptr_array[i] = buffer + (width * i * 4);
|
||||
}
|
||||
png_read_image(png_ptr, line_buffer_ptr_array);
|
||||
free(line_buffer_ptr_array);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void read_frame(png_structp png_ptr, png_infop info_ptr, PNG_FRAME_INFO* frame_info)
|
||||
{
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
unsigned int offset_x;
|
||||
unsigned int offset_y;
|
||||
unsigned short delay_num;
|
||||
unsigned short delay_den;
|
||||
unsigned char dop;
|
||||
unsigned char bop;
|
||||
unsigned int delay;
|
||||
unsigned char* buffer = NULL;
|
||||
|
||||
png_read_frame_head(png_ptr, info_ptr);
|
||||
png_get_next_frame_fcTL(png_ptr, info_ptr, &width, &height, &offset_x, &offset_y, &delay_num, &delay_den, &dop, &bop);
|
||||
|
||||
delay = 1000u * delay_num / delay_den;
|
||||
|
||||
frame_info->width = width;
|
||||
frame_info->height = height;
|
||||
frame_info->offset_x = offset_x;
|
||||
frame_info->offset_y = offset_y;
|
||||
frame_info->delay = delay;
|
||||
frame_info->dop = dop;
|
||||
frame_info->bop = bop;
|
||||
frame_info->pop = IMAGE_PNG_PREPARE_UNKNOWN;
|
||||
|
||||
buffer = (unsigned char*) malloc(width * height * 4);
|
||||
if (buffer == NULL) {
|
||||
frame_info->buffer = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
read_image(png_ptr, buffer, width, height);
|
||||
frame_info->buffer = buffer;
|
||||
}
|
||||
|
||||
static void generate_pop(PNG_FRAME_INFO* frame_info_array, int count)
|
||||
{
|
||||
unsigned char dop = 0xff;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++){
|
||||
PNG_FRAME_INFO* frame_info = frame_info_array + i;
|
||||
|
||||
switch (dop) {
|
||||
case PNG_DISPOSE_OP_NONE:
|
||||
frame_info->pop = IMAGE_PNG_PREPARE_NONE;
|
||||
break;
|
||||
case PNG_DISPOSE_OP_BACKGROUND:
|
||||
frame_info->pop = IMAGE_PNG_PREPARE_BACKGROUND;
|
||||
break;
|
||||
case PNG_DISPOSE_OP_PREVIOUS:
|
||||
frame_info->pop = IMAGE_PNG_PREPARE_USE_BACKUP;
|
||||
break;
|
||||
default:
|
||||
frame_info->pop = IMAGE_PNG_PREPARE_BACKGROUND;
|
||||
break;
|
||||
}
|
||||
|
||||
dop = frame_info->dop;
|
||||
}
|
||||
}
|
||||
|
||||
void* PNG_decode(JNIEnv* env, PatchHeadInputStream* patch_head_input_stream, bool partially)
|
||||
{
|
||||
PNG *png = NULL;
|
||||
png_structp png_ptr = NULL;
|
||||
png_infop info_ptr = NULL;
|
||||
bool apng;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
int color_type;
|
||||
int bit_depth;
|
||||
bool is_opaque;
|
||||
unsigned char* buffer = NULL;
|
||||
unsigned int frame_count = 0;
|
||||
bool hide_first_frame = false;
|
||||
PNG_FRAME_INFO* frame_info_array = NULL;
|
||||
int i;
|
||||
|
||||
png = (PNG *) malloc(sizeof(PNG));
|
||||
if (png == NULL) {
|
||||
WTF_OM;
|
||||
close_patch_head_input_stream(env, patch_head_input_stream);
|
||||
destroy_patch_head_input_stream(env, &patch_head_input_stream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, &user_error_fn, &user_warn_fn);
|
||||
if (png_ptr == NULL) {
|
||||
free(png);
|
||||
png = NULL;
|
||||
close_patch_head_input_stream(env, patch_head_input_stream);
|
||||
destroy_patch_head_input_stream(env, &patch_head_input_stream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
info_ptr = png_create_info_struct(png_ptr);
|
||||
if (info_ptr == NULL) {
|
||||
png_destroy_read_struct(&png_ptr, NULL, NULL);
|
||||
free(png);
|
||||
png = NULL;
|
||||
close_patch_head_input_stream(env, patch_head_input_stream);
|
||||
destroy_patch_head_input_stream(env, &patch_head_input_stream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (setjmp(png_jmpbuf(png_ptr))) {
|
||||
LOGE(MSG("Error in png decode"));
|
||||
free_frame_info_array(frame_info_array, frame_count);
|
||||
frame_info_array = NULL;
|
||||
free(buffer);
|
||||
buffer = NULL;
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
free(png);
|
||||
png = NULL;
|
||||
close_patch_head_input_stream(env, patch_head_input_stream);
|
||||
destroy_patch_head_input_stream(env, &patch_head_input_stream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Set custom read function
|
||||
png_set_read_fn(png_ptr, patch_head_input_stream, &user_read_fn);
|
||||
|
||||
// Get png info
|
||||
png_read_info(png_ptr, info_ptr);
|
||||
|
||||
// Check apng
|
||||
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_acTL)) {
|
||||
apng = true;
|
||||
} else {
|
||||
apng = false;
|
||||
}
|
||||
|
||||
// PNG info
|
||||
width = png_get_image_width(png_ptr, info_ptr);
|
||||
height = png_get_image_height(png_ptr, info_ptr);
|
||||
color_type = png_get_color_type(png_ptr, info_ptr);
|
||||
bit_depth = png_get_bit_depth(png_ptr, info_ptr);
|
||||
|
||||
// Create buffer
|
||||
buffer = (unsigned char*) malloc(width * height * 4);
|
||||
if (buffer == NULL) {
|
||||
WTF_OM;
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
free(png);
|
||||
png = NULL;
|
||||
close_patch_head_input_stream(env, patch_head_input_stream);
|
||||
destroy_patch_head_input_stream(env, &patch_head_input_stream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (apng) {
|
||||
// Get frame count
|
||||
frame_count = png_get_num_frames(png_ptr, info_ptr);
|
||||
hide_first_frame = png_get_first_frame_is_hidden(png_ptr, info_ptr);
|
||||
if (hide_first_frame) {
|
||||
frame_count--;
|
||||
}
|
||||
|
||||
// Create frame info array
|
||||
frame_info_array = (PNG_FRAME_INFO*) calloc(frame_count, sizeof(PNG_FRAME_INFO));
|
||||
if (frame_info_array == NULL) {
|
||||
WTF_OM;
|
||||
free(buffer);
|
||||
buffer = NULL;
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
free(png);
|
||||
png = NULL;
|
||||
close_patch_head_input_stream(env, patch_head_input_stream);
|
||||
destroy_patch_head_input_stream(env, &patch_head_input_stream);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Configure to ARGB
|
||||
png_set_expand(png_ptr);
|
||||
if (bit_depth == 16) {
|
||||
png_set_scale_16(png_ptr);
|
||||
}
|
||||
if (color_type == PNG_COLOR_TYPE_GRAY ||
|
||||
color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
|
||||
png_set_gray_to_rgb(png_ptr);
|
||||
}
|
||||
if (!(color_type & PNG_COLOR_MASK_ALPHA)) {
|
||||
is_opaque = true;
|
||||
png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER);
|
||||
} else {
|
||||
is_opaque = false;
|
||||
}
|
||||
|
||||
if (apng) {
|
||||
if (hide_first_frame) {
|
||||
// Skip first frame
|
||||
read_image(png_ptr, buffer, width, height);
|
||||
}
|
||||
|
||||
// Read first frame
|
||||
read_frame(png_ptr, info_ptr, frame_info_array);
|
||||
// Fix dop
|
||||
if (frame_info_array->dop == PNG_DISPOSE_OP_PREVIOUS) {
|
||||
frame_info_array->dop = PNG_DISPOSE_OP_BACKGROUND;
|
||||
}
|
||||
|
||||
if (!partially || frame_count == 1) {
|
||||
// Read all frame
|
||||
for (i = 1; i < frame_count; read_frame(png_ptr, info_ptr, frame_info_array + i++));
|
||||
|
||||
// Generate pop
|
||||
generate_pop(frame_info_array, frame_count);
|
||||
|
||||
// End read
|
||||
png_read_end(png_ptr, info_ptr);
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
|
||||
// Close input stream
|
||||
close_patch_head_input_stream(env, patch_head_input_stream);
|
||||
destroy_patch_head_input_stream(env, &patch_head_input_stream);
|
||||
|
||||
png->partially = false;
|
||||
png->png_ptr = NULL;
|
||||
png->info_ptr = NULL;
|
||||
png->patch_head_input_stream = NULL;
|
||||
} else {
|
||||
png->partially = true;
|
||||
png->png_ptr = png_ptr;
|
||||
png->info_ptr = info_ptr;
|
||||
png->patch_head_input_stream = patch_head_input_stream;
|
||||
}
|
||||
|
||||
// Fill PNG
|
||||
png->width = width;
|
||||
png->height = height;
|
||||
png->is_opaque = is_opaque;
|
||||
png->buffer = buffer;
|
||||
png->apng = true;
|
||||
png->buffer_index = -1;
|
||||
png->frame_info_array = frame_info_array;
|
||||
png->frame_count = frame_count;
|
||||
png->backup = NULL;
|
||||
|
||||
// Render first frame
|
||||
PNG_advance(png);
|
||||
} else {
|
||||
read_image(png_ptr, buffer, width, height);
|
||||
|
||||
// End read
|
||||
png_read_end(png_ptr, info_ptr);
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
|
||||
// Close input stream
|
||||
close_patch_head_input_stream(env, patch_head_input_stream);
|
||||
destroy_patch_head_input_stream(env, &patch_head_input_stream);
|
||||
|
||||
// Fill PNG
|
||||
png->width = width;
|
||||
png->height = height;
|
||||
png->buffer = buffer;
|
||||
png->apng = false;
|
||||
png->buffer_index = 0;
|
||||
png->frame_info_array = NULL;
|
||||
png->frame_count = 0;
|
||||
png->backup = NULL;
|
||||
png->partially = false;
|
||||
png->png_ptr = NULL;
|
||||
png->info_ptr = NULL;
|
||||
png->patch_head_input_stream = NULL;
|
||||
}
|
||||
|
||||
return png;
|
||||
}
|
||||
|
||||
bool PNG_complete(JNIEnv *env, PNG* png)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!png->partially) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (png->png_ptr == NULL || png->info_ptr == NULL || png->patch_head_input_stream == NULL) {
|
||||
LOGE(MSG("Some stuff is NULL"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read left frames
|
||||
for (i = 1; i < png->frame_count; read_frame(png->png_ptr, png->info_ptr, png->frame_info_array + i++));
|
||||
|
||||
// Generate pop
|
||||
generate_pop(png->frame_info_array, png->frame_count);
|
||||
|
||||
// End read
|
||||
png_read_end(png->png_ptr, png->info_ptr);
|
||||
png_destroy_read_struct(&png->png_ptr, &png->info_ptr, NULL);
|
||||
|
||||
// Close input stream
|
||||
close_patch_head_input_stream(env, png->patch_head_input_stream);
|
||||
destroy_patch_head_input_stream(env, &png->patch_head_input_stream);
|
||||
|
||||
// Clean up
|
||||
png->partially = false;
|
||||
png->png_ptr = NULL;
|
||||
png->info_ptr = NULL;
|
||||
png->patch_head_input_stream = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PNG_is_completed(PNG* png)
|
||||
{
|
||||
return !png->partially;
|
||||
}
|
||||
|
||||
void* PNG_get_pixels(PNG* png)
|
||||
{
|
||||
if (!png->partially && PNG_get_frame_count(png) == 1) {
|
||||
return png->buffer;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int PNG_get_width(PNG* png)
|
||||
{
|
||||
return png->width;
|
||||
}
|
||||
|
||||
int PNG_get_height(PNG* png)
|
||||
{
|
||||
return png->height;
|
||||
}
|
||||
|
||||
int PNG_get_byte_count(PNG* png)
|
||||
{
|
||||
int i;
|
||||
PNG_FRAME_INFO* frame_info;
|
||||
int size = 0;
|
||||
// Add buffer size
|
||||
if (png->buffer != NULL) {
|
||||
size += png->width * png->height * 4;
|
||||
}
|
||||
// Add backup size
|
||||
if (png->backup != NULL) {
|
||||
size += png->width * png->height * 4;
|
||||
}
|
||||
// Add frames size
|
||||
if (png->frame_info_array != NULL) {
|
||||
for (i = 0; i < png->frame_count; i++) {
|
||||
frame_info = png->frame_info_array + i;
|
||||
// Add frame buffer size
|
||||
if (frame_info->buffer != NULL) {
|
||||
size += frame_info->width * frame_info->height * 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void PNG_render(PNG* png, 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)
|
||||
{
|
||||
copy_pixels(png->buffer, png->width, png->height, src_x, src_y,
|
||||
dst, dst_w, dst_h, dst_x, dst_y,
|
||||
width, height, fill_blank, default_color);
|
||||
}
|
||||
|
||||
static void backup(PNG* png)
|
||||
{
|
||||
if (png->backup == NULL) {
|
||||
png->backup = (unsigned char*) malloc(png->width * png->height * 4);
|
||||
if (png->backup == NULL) {
|
||||
WTF_OM;
|
||||
return;
|
||||
}
|
||||
}
|
||||
memcpy(png->backup, png->buffer, png->width * png->height * 4);
|
||||
}
|
||||
|
||||
static void restore(PNG* png)
|
||||
{
|
||||
if (png->backup == NULL) {
|
||||
LOGE(MSG("Backup is NULL"));
|
||||
} else {
|
||||
memcpy(png->buffer, png->backup, png->width * png->height * 4);
|
||||
}
|
||||
}
|
||||
|
||||
static void switch_buffer_backup(PNG* png)
|
||||
{
|
||||
unsigned char* temp;
|
||||
|
||||
if (png->backup == NULL) {
|
||||
backup(png);
|
||||
} else {
|
||||
temp = png->buffer;
|
||||
png->buffer = png->backup;
|
||||
png->backup = temp;
|
||||
}
|
||||
}
|
||||
|
||||
static void blend_over(unsigned char* dp, const unsigned char* sp, size_t len)
|
||||
{
|
||||
unsigned int i;
|
||||
int u, v, al;
|
||||
|
||||
for (i = 0; i < len; i += 4, sp += 4, dp += 4) {
|
||||
if (sp[3] == 255) {
|
||||
memcpy(dp, sp, 4);
|
||||
} else if (sp[3] != 0) {
|
||||
if (dp[3] != 0) {
|
||||
u = sp[3] * 255;
|
||||
v = (255 - sp[3]) * dp[3];
|
||||
al = u + v;
|
||||
dp[0] = (unsigned char) ((sp[0] * u + dp[0] * v) / al);
|
||||
dp[1] = (unsigned char) ((sp[1] * u + dp[1] * v) / al);
|
||||
dp[2] = (unsigned char) ((sp[2] * u + dp[2] * v) / al);
|
||||
dp[3] = (unsigned char) (al / 255);
|
||||
} else {
|
||||
memcpy(dp, sp, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void blend(unsigned char* src, int src_width, int src_height, int offset_x, int offset_y,
|
||||
unsigned char* dst, int dst_width, int dst_height, bool blend_op_over)
|
||||
{
|
||||
int i;
|
||||
unsigned char* src_ptr;
|
||||
unsigned char* dst_ptr;
|
||||
size_t len;
|
||||
int copy_width = MIN(dst_width - offset_x, src_width);
|
||||
int copy_height = MIN(dst_height - offset_y, src_height);
|
||||
|
||||
for (i = 0; i < copy_height; i++) {
|
||||
src_ptr = src + (i * src_width * 4);
|
||||
dst_ptr = dst + (((offset_y + i) * dst_width + offset_x) * 4);
|
||||
len = (size_t) (copy_width * 4);
|
||||
|
||||
if (blend_op_over) {
|
||||
blend_over(dst_ptr, src_ptr, len);
|
||||
} else {
|
||||
memcpy(dst_ptr, src_ptr, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PNG_advance(PNG* png)
|
||||
{
|
||||
int index;
|
||||
|
||||
if (!png->apng) {
|
||||
LOGW(MSG("It is not apng, no need to advance"));
|
||||
return;
|
||||
}
|
||||
|
||||
index = (png->buffer_index + 1) % png->frame_count;
|
||||
if (index != 0 && png->partially) {
|
||||
LOGE(MSG("The png is only decoded partially. Only the first frame can be shown."));
|
||||
return;
|
||||
}
|
||||
|
||||
PNG_FRAME_INFO* frame_info = png->frame_info_array + index;
|
||||
|
||||
if (frame_info->dop == PNG_DISPOSE_OP_PREVIOUS && frame_info->pop == IMAGE_PNG_PREPARE_USE_BACKUP) {
|
||||
switch_buffer_backup(png);
|
||||
} else {
|
||||
// Backup
|
||||
if (frame_info->dop == PNG_DISPOSE_OP_PREVIOUS) {
|
||||
backup(png);
|
||||
}
|
||||
|
||||
// Prepare
|
||||
switch (frame_info->pop) {
|
||||
case IMAGE_PNG_PREPARE_NONE:
|
||||
// Do nothing
|
||||
break;
|
||||
default:
|
||||
case IMAGE_PNG_PREPARE_BACKGROUND:
|
||||
// Set transparent
|
||||
memset(png->buffer, '\0', png->width * png->height * 4);
|
||||
break;
|
||||
case IMAGE_PNG_PREPARE_USE_BACKUP:
|
||||
restore(png);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
blend(frame_info->buffer, frame_info->width, frame_info->height, frame_info->offset_x, frame_info->offset_y,
|
||||
png->buffer, png->width, png->height, frame_info->bop == PNG_BLEND_OP_OVER);
|
||||
|
||||
png->buffer_index = index;
|
||||
}
|
||||
|
||||
int PNG_get_delay(PNG* png)
|
||||
{
|
||||
if (png->apng) {
|
||||
return png->frame_info_array[png->buffer_index].delay;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int PNG_get_frame_count(PNG* png)
|
||||
{
|
||||
if (png->apng) {
|
||||
return png->frame_count;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool PNG_is_opaque(PNG* png)
|
||||
{
|
||||
return png->is_opaque;
|
||||
}
|
||||
|
||||
void PNG_recycle(JNIEnv *env, PNG* png)
|
||||
{
|
||||
if (png == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
free(png->buffer);
|
||||
png->buffer = NULL;
|
||||
|
||||
free_frame_info_array(png->frame_info_array, png->frame_count);
|
||||
png->frame_info_array = NULL;
|
||||
|
||||
free(png->backup);
|
||||
png->backup = NULL;
|
||||
|
||||
if (png->png_ptr != NULL && png->info_ptr != NULL) {
|
||||
png_destroy_read_struct(&png->png_ptr, &png->info_ptr, NULL);
|
||||
}
|
||||
png->png_ptr = NULL;
|
||||
png->info_ptr = NULL;
|
||||
|
||||
if (png->patch_head_input_stream != NULL) {
|
||||
close_patch_head_input_stream(env, png->patch_head_input_stream);
|
||||
destroy_patch_head_input_stream(env, &png->patch_head_input_stream);
|
||||
png->patch_head_input_stream = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // IMAGE_SUPPORT_PNG
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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/27/2015.
|
||||
//
|
||||
|
||||
#ifndef IMAGE_IMAGE_PNG_H
|
||||
#define IMAGE_IMAGE_PNG_H
|
||||
|
||||
#include "config.h"
|
||||
#ifdef IMAGE_SUPPORT_PNG
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "png.h"
|
||||
#include "patch_head_input_stream.h"
|
||||
|
||||
#define IMAGE_PNG_DECODER_DESCRIPTION ("libpng " PNG_LIBPNG_VER_STRING)
|
||||
|
||||
#define IMAGE_PNG_MAGIC_NUMBER_0 0x89
|
||||
#define IMAGE_PNG_MAGIC_NUMBER_1 0x50
|
||||
|
||||
#define IMAGE_PNG_PREPARE_UNKNOWN 0x00
|
||||
#define IMAGE_PNG_PREPARE_NONE 0x01
|
||||
#define IMAGE_PNG_PREPARE_BACKGROUND 0x02
|
||||
#define IMAGE_PNG_PREPARE_USE_BACKUP 0x03
|
||||
|
||||
typedef struct {
|
||||
unsigned char* buffer;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
unsigned int offset_x;
|
||||
unsigned int offset_y;
|
||||
unsigned int delay; // ms
|
||||
unsigned char dop;
|
||||
unsigned char bop;
|
||||
unsigned char pop;
|
||||
} PNG_FRAME_INFO;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
bool is_opaque;
|
||||
unsigned char* buffer;
|
||||
bool apng;
|
||||
int buffer_index;
|
||||
PNG_FRAME_INFO* frame_info_array;
|
||||
unsigned int frame_count;
|
||||
unsigned char* backup;
|
||||
bool partially;
|
||||
png_structp png_ptr;
|
||||
png_infop info_ptr;
|
||||
PatchHeadInputStream* patch_head_input_stream;
|
||||
} PNG;
|
||||
|
||||
void* PNG_decode(JNIEnv* env, PatchHeadInputStream* patch_head_input_stream, bool partially);
|
||||
bool PNG_complete(JNIEnv* env, PNG* png);
|
||||
bool PNG_is_completed(PNG* png);
|
||||
void* PNG_get_pixels(PNG* png);
|
||||
int PNG_get_width(PNG* png);
|
||||
int PNG_get_height(PNG* png);
|
||||
int PNG_get_byte_count(PNG* png);
|
||||
void PNG_render(PNG* png, 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);
|
||||
void PNG_advance(PNG* png);
|
||||
int PNG_get_delay(PNG* png);
|
||||
int PNG_get_frame_count(PNG* png);
|
||||
bool PNG_is_opaque(PNG* png);
|
||||
void PNG_recycle(JNIEnv* env, PNG* png);
|
||||
|
||||
#endif // IMAGE_SUPPORT_PNG
|
||||
|
||||
#endif // IMAGE_IMAGE_PNG_H
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* 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/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)
|
||||
{
|
||||
int left;
|
||||
int line;
|
||||
size_t line_stride;
|
||||
int src_stride;
|
||||
int src_pos;
|
||||
int dst_pos;
|
||||
size_t dst_blank_length;
|
||||
|
||||
// Sanitize
|
||||
if (src_x < 0) {
|
||||
width -= src_x;
|
||||
dst_x -= src_x;
|
||||
src_x = 0;
|
||||
}
|
||||
if (dst_x < 0) {
|
||||
width -= dst_x;
|
||||
src_x -= dst_x;
|
||||
dst_x = 0;
|
||||
}
|
||||
if (width <= 0) {
|
||||
return false;
|
||||
}
|
||||
if (src_y < 0) {
|
||||
height -= src_y;
|
||||
dst_y -= src_y;
|
||||
src_y = 0;
|
||||
}
|
||||
if (dst_y < 0) {
|
||||
height -= dst_y;
|
||||
src_y -= dst_y;
|
||||
dst_y = 0;
|
||||
}
|
||||
if (height <= 0) {
|
||||
return false;
|
||||
}
|
||||
left = src_x + width - src_w;
|
||||
if (left > 0) {
|
||||
width -= left;
|
||||
}
|
||||
left = dst_x + width - dst_w;
|
||||
if (left > 0) {
|
||||
width -= left;
|
||||
}
|
||||
if (width <= 0) {
|
||||
return false;
|
||||
}
|
||||
left = src_y + height - src_h;
|
||||
if (left > 0) {
|
||||
height -= left;
|
||||
}
|
||||
left = dst_y + height - dst_h;
|
||||
if (left > 0) {
|
||||
height -= left;
|
||||
}
|
||||
if (height <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Init
|
||||
line_stride = (size_t) (width * 4);
|
||||
src_stride = src_w * 4;
|
||||
src_pos = src_y * src_stride + src_x * 4;
|
||||
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;
|
||||
memcpy(dst + dst_pos, src + src_pos, line_stride);
|
||||
dst_pos += line_stride;
|
||||
src_pos += src_stride;
|
||||
|
||||
// Other lines
|
||||
dst_blank_length = (size_t) ((dst_w - width) * 4);
|
||||
for (line = 1; line < height; line++) {
|
||||
if (fill_blank) {
|
||||
memset_int((int *) (dst + dst_pos), color, dst_blank_length / 4);
|
||||
}
|
||||
dst_pos += dst_blank_length;
|
||||
memcpy(dst + dst_pos, src + src_pos, line_stride);
|
||||
dst_pos += line_stride;
|
||||
src_pos += src_stride;
|
||||
}
|
||||
|
||||
// Fill left blank if necessary
|
||||
if (fill_blank) {
|
||||
memset_int((int *) (dst + dst_pos), color, (size_t) (dst_w * dst_h * 4 - dst_pos) / 4);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void copy_pixels(const void* src, int src_w, int src_h, int src_x, int src_y,
|
||||
void* dst, int dst_w, int dst_h, int dst_x, int dst_y,
|
||||
int width, int height, bool fill_blank, int default_color)
|
||||
{
|
||||
int color = 0;
|
||||
if (fill_blank) {
|
||||
color = convert_color(default_color);
|
||||
}
|
||||
|
||||
if (!copy_pixels_internal(src, src_w, src_h, src_x, src_y, dst, dst_w, dst_h, dst_x,
|
||||
dst_y, width, height, fill_blank, color) && fill_blank) {
|
||||
memset_int(dst, color, (size_t) (dst_w * dst_h));
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -26,8 +26,8 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
#endif //IMAGE_IMAGE_UTILS_H
|
||||
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
* 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/27/2015.
|
||||
//
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <android/bitmap.h>
|
||||
#include <GLES2/gl2.h>
|
||||
|
||||
#include "java_wrapper.h"
|
||||
#include "input_stream.h"
|
||||
#include "image.h"
|
||||
#include "../log.h"
|
||||
|
||||
static JavaVM* jvm;
|
||||
|
||||
static void* tile_buffer;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_com_hippo_image_Image_nativeDecode(JNIEnv* env,
|
||||
jclass clazz, jobject is, jboolean partially)
|
||||
{
|
||||
InputStream* input_stream;
|
||||
int format;
|
||||
void* image;
|
||||
jobject image_object;
|
||||
|
||||
input_stream = create_input_stream(env, is);
|
||||
if (input_stream == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
image = decode(env, input_stream, partially, &format);
|
||||
if (image == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
image_object = create_image_object(env, image, format,
|
||||
get_width(image, format), get_height(image, format));
|
||||
if (image_object == NULL) {
|
||||
recycle(env, image, format);
|
||||
return NULL;
|
||||
} else {
|
||||
return image_object;
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_com_hippo_image_Image_nativeCreate(JNIEnv* env,
|
||||
jclass clazz, jobject bitmap)
|
||||
{
|
||||
#ifdef IMAGE_SUPPORT_PLAIN
|
||||
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, IMAGE_FORMAT_PLAIN,
|
||||
info.width, info.height);
|
||||
if (image_object == NULL) {
|
||||
recycle(env, image, IMAGE_FORMAT_PLAIN);
|
||||
return NULL;
|
||||
} else {
|
||||
return image_object;
|
||||
}
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_hippo_image_Image_nativeComplete(JNIEnv* env,
|
||||
jclass clazz, jlong ptr, jint format)
|
||||
{
|
||||
return (jboolean) complete(env, (void*) (intptr_t) ptr, format);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_hippo_image_Image_nativeIsCompleted(JNIEnv* env,
|
||||
jclass clazz, jlong ptr, jint format)
|
||||
{
|
||||
return (jboolean) is_completed((void*) (intptr_t) ptr, format);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
AndroidBitmap_unlockPixels(env, dst);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_hippo_image_Image_nativeTexImage(JNIEnv* env,
|
||||
jclass clazz, jlong ptr, jint format, jboolean init,
|
||||
jint src_x, jint src_y, jint width, jint height)
|
||||
{
|
||||
// Check tile_buffer NULL
|
||||
if (NULL == tile_buffer) {
|
||||
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);
|
||||
|
||||
if (init) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_hippo_image_Image_nativeAdvance(JNIEnv* env,
|
||||
jclass clazz, jlong ptr, jint format)
|
||||
{
|
||||
advance((void*) (intptr_t) ptr, format);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_com_hippo_image_Image_nativeFrameCount(JNIEnv* env,
|
||||
jclass clazz, jlong ptr, jint format)
|
||||
{
|
||||
return (jint) get_frame_count((void*) (intptr_t) ptr, format);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_hippo_image_Image_nativeRecycle(JNIEnv* env,
|
||||
jclass clazz, jlong ptr, jint format)
|
||||
{
|
||||
recycle(env, (void*) (intptr_t) ptr, format);
|
||||
}
|
||||
|
||||
JNIEXPORT jintArray JNICALL
|
||||
Java_com_hippo_image_Image_nativeGetSupportedImageFormats(
|
||||
JNIEnv *env, jclass clazz)
|
||||
{
|
||||
int formats[IMAGE_MAX_SUPPORTED_FORMAT_COUNT];
|
||||
int count = get_supported_formats(formats);
|
||||
jintArray array = (*env)->NewIntArray(env, count);
|
||||
if (array == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
(*env)->SetIntArrayRegion(env, array, 0, count, formats);
|
||||
return array;
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_com_hippo_image_Image_nativeGetDecoderDescription(
|
||||
JNIEnv *env, jclass clazz, jint format)
|
||||
{
|
||||
const char *description = get_decoder_description(format);
|
||||
if (description == NULL) {
|
||||
return NULL;
|
||||
} else {
|
||||
return (*env)->NewStringUTF(env, description);
|
||||
}
|
||||
}
|
||||
|
||||
bool image_onLoad(JavaVM *vm)
|
||||
{
|
||||
jvm = vm;
|
||||
|
||||
tile_buffer = malloc(IMAGE_TILE_MAX_SIZE * 4);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
JNI_OnUnload(JavaVM *vm, void *reserved)
|
||||
{
|
||||
free(tile_buffer);
|
||||
tile_buffer = NULL;
|
||||
}
|
||||
File renamed without changes.
@@ -1,183 +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/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) {
|
||||
int left;
|
||||
int line;
|
||||
size_t line_stride;
|
||||
int src_stride;
|
||||
int src_pos;
|
||||
int dst_pos;
|
||||
size_t dst_blank_length;
|
||||
|
||||
// Sanitize
|
||||
if (src_x < 0) {
|
||||
width -= src_x;
|
||||
dst_x -= src_x;
|
||||
src_x = 0;
|
||||
}
|
||||
if (dst_x < 0) {
|
||||
width -= dst_x;
|
||||
src_x -= dst_x;
|
||||
dst_x = 0;
|
||||
}
|
||||
if (width <= 0) {
|
||||
return false;
|
||||
}
|
||||
if (src_y < 0) {
|
||||
height -= src_y;
|
||||
dst_y -= src_y;
|
||||
src_y = 0;
|
||||
}
|
||||
if (dst_y < 0) {
|
||||
height -= dst_y;
|
||||
src_y -= dst_y;
|
||||
dst_y = 0;
|
||||
}
|
||||
if (height <= 0) {
|
||||
return false;
|
||||
}
|
||||
left = src_x + width - src_w;
|
||||
if (left > 0) {
|
||||
width -= left;
|
||||
}
|
||||
left = dst_x + width - dst_w;
|
||||
if (left > 0) {
|
||||
width -= left;
|
||||
}
|
||||
if (width <= 0) {
|
||||
return false;
|
||||
}
|
||||
left = src_y + height - src_h;
|
||||
if (left > 0) {
|
||||
height -= left;
|
||||
}
|
||||
left = dst_y + height - dst_h;
|
||||
if (left > 0) {
|
||||
height -= left;
|
||||
}
|
||||
if (height <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Init
|
||||
line_stride = (size_t) (width * 4);
|
||||
src_stride = src_w * 4;
|
||||
src_pos = src_y * src_stride + src_x * 4;
|
||||
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;
|
||||
memcpy(dst + dst_pos, src + src_pos, line_stride);
|
||||
dst_pos += line_stride;
|
||||
src_pos += src_stride;
|
||||
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
@@ -1,279 +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.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <android/bitmap.h>
|
||||
#include <GLES2/gl2.h>
|
||||
|
||||
#include "java_wrapper.h"
|
||||
#include "image.h"
|
||||
#include "log.h"
|
||||
|
||||
static JavaVM *jvm;
|
||||
|
||||
static void *tile_buffer;
|
||||
|
||||
static int jniGetFDFromFileDescriptor(JNIEnv *env, jobject fileDescriptor) {
|
||||
jint fd = -1;
|
||||
jclass fdClass = (*env)->FindClass(env, "java/io/FileDescriptor");
|
||||
|
||||
if (fdClass != NULL) {
|
||||
jfieldID fdClassDescriptorFieldID = (*env)->GetFieldID(env, fdClass, "descriptor", "I");
|
||||
if (fdClassDescriptorFieldID != NULL && fileDescriptor != NULL) {
|
||||
fd = (*env)->GetIntField(env, fileDescriptor, fdClassDescriptorFieldID);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_com_hippo_image_Image_nativeDecodeFdInt(JNIEnv *env,
|
||||
jclass clazz, jint fd, jboolean partially) {
|
||||
int format;
|
||||
void *image;
|
||||
jobject image_object;
|
||||
|
||||
image = createFromFd(env, fd, partially, &format);
|
||||
if (image == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
image_object = create_image_object(env, image, format,
|
||||
get_width(image, format), get_height(image, format));
|
||||
if (image_object == NULL) {
|
||||
recycle(env, image, format);
|
||||
return NULL;
|
||||
} else {
|
||||
return image_object;
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_com_hippo_image_Image_nativeDecode(JNIEnv *env,
|
||||
jclass clazz, jobject fd, jboolean partially) {
|
||||
return Java_com_hippo_image_Image_nativeDecodeFdInt(env, clazz,
|
||||
jniGetFDFromFileDescriptor(env, fd),
|
||||
partially);
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
|
||||
AndroidBitmap_unlockPixels(env, dst);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_hippo_image_Image_nativeTexImage(JNIEnv *env,
|
||||
jclass clazz, jlong ptr, jint format, jboolean init,
|
||||
jint src_x, jint src_y, jint width, jint height) {
|
||||
// Check tile_buffer NULL
|
||||
if (NULL == tile_buffer) {
|
||||
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);
|
||||
|
||||
if (init) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_hippo_image_Image_nativeAdvance(JNIEnv *env,
|
||||
jclass clazz, jlong ptr, jint format) {
|
||||
advance((void *) (intptr_t) ptr, format);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
tile_buffer = malloc(IMAGE_TILE_MAX_SIZE * 4);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
JNI_OnUnload(JavaVM *vm, void *reserved) {
|
||||
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;
|
||||
|
||||
Memarea *memarea = (Memarea *) addr;
|
||||
image = createFromAddr(env, memarea->buffer, memarea->size, partially, &format);
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
# 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.
|
||||
|
||||
cmake_minimum_required(VERSION 3.4.1)
|
||||
project(jpeg C)
|
||||
|
||||
set(LIBJPEG_TURBO_SOURCES
|
||||
libjpeg-turbo/jaricom.c
|
||||
libjpeg-turbo/jcomapi.c
|
||||
libjpeg-turbo/jdapimin.c
|
||||
libjpeg-turbo/jdapistd.c
|
||||
libjpeg-turbo/jdarith.c
|
||||
libjpeg-turbo/jdatasrc.c
|
||||
libjpeg-turbo/jdatasrc-tj.c
|
||||
libjpeg-turbo/jdcoefct.c
|
||||
libjpeg-turbo/jdcolor.c
|
||||
libjpeg-turbo/jddctmgr.c
|
||||
libjpeg-turbo/jdhuff.c
|
||||
libjpeg-turbo/jdinput.c
|
||||
libjpeg-turbo/jdmainct.c
|
||||
libjpeg-turbo/jdmarker.c
|
||||
libjpeg-turbo/jdmaster.c
|
||||
libjpeg-turbo/jdmerge.c
|
||||
libjpeg-turbo/jdphuff.c
|
||||
libjpeg-turbo/jdpostct.c
|
||||
libjpeg-turbo/jdsample.c
|
||||
libjpeg-turbo/jdtrans.c
|
||||
libjpeg-turbo/jerror.c
|
||||
libjpeg-turbo/jfdctflt.c
|
||||
libjpeg-turbo/jfdctfst.c
|
||||
libjpeg-turbo/jfdctint.c
|
||||
libjpeg-turbo/jidctflt.c
|
||||
libjpeg-turbo/jidctfst.c
|
||||
libjpeg-turbo/jidctint.c
|
||||
libjpeg-turbo/jidctred.c
|
||||
libjpeg-turbo/jmemmgr.c
|
||||
libjpeg-turbo/jmemnobs.c
|
||||
libjpeg-turbo/jquant1.c
|
||||
libjpeg-turbo/jquant2.c
|
||||
libjpeg-turbo/jutils.c
|
||||
)
|
||||
set(LIBJPEG_TURBO_INCLUDES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/libjpeg-turbo
|
||||
)
|
||||
|
||||
if (${ANDROID_ABI} STREQUAL "armeabi-v7a")
|
||||
|
||||
enable_language(ASM)
|
||||
|
||||
add_definitions(-DNEON_INTRINSICS)
|
||||
|
||||
set(LIBJPEG_TURBO_SOURCES
|
||||
${LIBJPEG_TURBO_SOURCES}
|
||||
libjpeg-turbo/simd/arm/jccolor-neon.c
|
||||
libjpeg-turbo/simd/arm/jidctred-neon.c
|
||||
libjpeg-turbo/simd/arm/jquanti-neon.c
|
||||
libjpeg-turbo/simd/arm/jidctint-neon.c
|
||||
libjpeg-turbo/simd/arm/jidctfst-neon.c
|
||||
libjpeg-turbo/simd/arm/jfdctint-neon.c
|
||||
libjpeg-turbo/simd/arm/jfdctfst-neon.c
|
||||
libjpeg-turbo/simd/arm/jdsample-neon.c
|
||||
libjpeg-turbo/simd/arm/jdmerge-neon.c
|
||||
libjpeg-turbo/simd/arm/jdcolor-neon.c
|
||||
libjpeg-turbo/simd/arm/jcsample-neon.c
|
||||
libjpeg-turbo/simd/arm/jcphuff-neon.c
|
||||
libjpeg-turbo/simd/arm/jcgray-neon.c
|
||||
libjpeg-turbo/simd/arm/aarch32/jchuff-neon.c
|
||||
libjpeg-turbo/simd/arm/aarch32/jsimd.c
|
||||
)
|
||||
|
||||
elseif (${ANDROID_ABI} STREQUAL "arm64-v8a")
|
||||
|
||||
enable_language(ASM)
|
||||
|
||||
add_definitions(-DNEON_INTRINSICS)
|
||||
|
||||
set(LIBJPEG_TURBO_SOURCES
|
||||
${LIBJPEG_TURBO_SOURCES}
|
||||
libjpeg-turbo/simd/arm/jccolor-neon.c
|
||||
libjpeg-turbo/simd/arm/jidctred-neon.c
|
||||
libjpeg-turbo/simd/arm/jquanti-neon.c
|
||||
libjpeg-turbo/simd/arm/jidctint-neon.c
|
||||
libjpeg-turbo/simd/arm/jidctfst-neon.c
|
||||
libjpeg-turbo/simd/arm/jfdctint-neon.c
|
||||
libjpeg-turbo/simd/arm/jfdctfst-neon.c
|
||||
libjpeg-turbo/simd/arm/jdsample-neon.c
|
||||
libjpeg-turbo/simd/arm/jdmerge-neon.c
|
||||
libjpeg-turbo/simd/arm/jdcolor-neon.c
|
||||
libjpeg-turbo/simd/arm/jcsample-neon.c
|
||||
libjpeg-turbo/simd/arm/jcphuff-neon.c
|
||||
libjpeg-turbo/simd/arm/jcgray-neon.c
|
||||
libjpeg-turbo/simd/arm/aarch64/jchuff-neon.c
|
||||
libjpeg-turbo/simd/arm/aarch64/jsimd.c
|
||||
)
|
||||
|
||||
elseif (${ANDROID_ABI} STREQUAL "x86")
|
||||
|
||||
enable_language(ASM_NASM)
|
||||
|
||||
set(LIBJPEG_TURBO_SOURCES
|
||||
${LIBJPEG_TURBO_SOURCES}
|
||||
libjpeg-turbo/simd/i386/jsimd.c
|
||||
libjpeg-turbo/simd/i386/jsimdcpu.asm
|
||||
libjpeg-turbo/simd/i386/jfdctflt-3dn.asm
|
||||
libjpeg-turbo/simd/i386/jidctflt-3dn.asm
|
||||
libjpeg-turbo/simd/i386/jquant-3dn.asm
|
||||
libjpeg-turbo/simd/i386/jccolor-mmx.asm
|
||||
libjpeg-turbo/simd/i386/jcgray-mmx.asm
|
||||
libjpeg-turbo/simd/i386/jcsample-mmx.asm
|
||||
libjpeg-turbo/simd/i386/jdcolor-mmx.asm
|
||||
libjpeg-turbo/simd/i386/jdmerge-mmx.asm
|
||||
libjpeg-turbo/simd/i386/jdsample-mmx.asm
|
||||
libjpeg-turbo/simd/i386/jfdctfst-mmx.asm
|
||||
libjpeg-turbo/simd/i386/jfdctint-mmx.asm
|
||||
libjpeg-turbo/simd/i386/jidctfst-mmx.asm
|
||||
libjpeg-turbo/simd/i386/jidctint-mmx.asm
|
||||
libjpeg-turbo/simd/i386/jidctred-mmx.asm
|
||||
libjpeg-turbo/simd/i386/jquant-mmx.asm
|
||||
libjpeg-turbo/simd/i386/jfdctflt-sse.asm
|
||||
libjpeg-turbo/simd/i386/jidctflt-sse.asm
|
||||
libjpeg-turbo/simd/i386/jquant-sse.asm
|
||||
libjpeg-turbo/simd/i386/jccolor-sse2.asm
|
||||
libjpeg-turbo/simd/i386/jcgray-sse2.asm
|
||||
libjpeg-turbo/simd/i386/jchuff-sse2.asm
|
||||
libjpeg-turbo/simd/i386/jcphuff-sse2.asm
|
||||
libjpeg-turbo/simd/i386/jcsample-sse2.asm
|
||||
libjpeg-turbo/simd/i386/jdcolor-sse2.asm
|
||||
libjpeg-turbo/simd/i386/jdmerge-sse2.asm
|
||||
libjpeg-turbo/simd/i386/jdsample-sse2.asm
|
||||
libjpeg-turbo/simd/i386/jfdctfst-sse2.asm
|
||||
libjpeg-turbo/simd/i386/jfdctint-sse2.asm
|
||||
libjpeg-turbo/simd/i386/jidctflt-sse2.asm
|
||||
libjpeg-turbo/simd/i386/jidctfst-sse2.asm
|
||||
libjpeg-turbo/simd/i386/jidctint-sse2.asm
|
||||
libjpeg-turbo/simd/i386/jidctred-sse2.asm
|
||||
libjpeg-turbo/simd/i386/jquantf-sse2.asm
|
||||
libjpeg-turbo/simd/i386/jquanti-sse2.asm
|
||||
libjpeg-turbo/simd/i386/jccolor-avx2.asm
|
||||
libjpeg-turbo/simd/i386/jcgray-avx2.asm
|
||||
libjpeg-turbo/simd/i386/jcsample-avx2.asm
|
||||
libjpeg-turbo/simd/i386/jdcolor-avx2.asm
|
||||
libjpeg-turbo/simd/i386/jdmerge-avx2.asm
|
||||
libjpeg-turbo/simd/i386/jdsample-avx2.asm
|
||||
libjpeg-turbo/simd/i386/jfdctint-avx2.asm
|
||||
libjpeg-turbo/simd/i386/jidctint-avx2.asm
|
||||
libjpeg-turbo/simd/i386/jquanti-avx2.asm
|
||||
)
|
||||
|
||||
set(CMAKE_ASM_NASM_FLAGS "-DELF -DPIC -I${CMAKE_CURRENT_SOURCE_DIR}/libjpeg-turbo/simd/nasm")
|
||||
|
||||
elseif (${ANDROID_ABI} STREQUAL "x86_64")
|
||||
|
||||
enable_language(ASM_NASM)
|
||||
|
||||
set(LIBJPEG_TURBO_SOURCES
|
||||
${LIBJPEG_TURBO_SOURCES}
|
||||
libjpeg-turbo/simd/x86_64/jsimd.c
|
||||
libjpeg-turbo/simd/x86_64/jsimdcpu.asm
|
||||
libjpeg-turbo/simd/x86_64/jfdctflt-sse.asm
|
||||
libjpeg-turbo/simd/x86_64/jccolor-sse2.asm
|
||||
libjpeg-turbo/simd/x86_64/jcgray-sse2.asm
|
||||
libjpeg-turbo/simd/x86_64/jchuff-sse2.asm
|
||||
libjpeg-turbo/simd/x86_64/jcphuff-sse2.asm
|
||||
libjpeg-turbo/simd/x86_64/jcsample-sse2.asm
|
||||
libjpeg-turbo/simd/x86_64/jdcolor-sse2.asm
|
||||
libjpeg-turbo/simd/x86_64/jdmerge-sse2.asm
|
||||
libjpeg-turbo/simd/x86_64/jdsample-sse2.asm
|
||||
libjpeg-turbo/simd/x86_64/jfdctfst-sse2.asm
|
||||
libjpeg-turbo/simd/x86_64/jfdctint-sse2.asm
|
||||
libjpeg-turbo/simd/x86_64/jidctflt-sse2.asm
|
||||
libjpeg-turbo/simd/x86_64/jidctfst-sse2.asm
|
||||
libjpeg-turbo/simd/x86_64/jidctint-sse2.asm
|
||||
libjpeg-turbo/simd/x86_64/jidctred-sse2.asm
|
||||
libjpeg-turbo/simd/x86_64/jquantf-sse2.asm
|
||||
libjpeg-turbo/simd/x86_64/jquanti-sse2.asm
|
||||
libjpeg-turbo/simd/x86_64/jccolor-avx2.asm
|
||||
libjpeg-turbo/simd/x86_64/jcgray-avx2.asm
|
||||
libjpeg-turbo/simd/x86_64/jcsample-avx2.asm
|
||||
libjpeg-turbo/simd/x86_64/jdcolor-avx2.asm
|
||||
libjpeg-turbo/simd/x86_64/jdmerge-avx2.asm
|
||||
libjpeg-turbo/simd/x86_64/jdsample-avx2.asm
|
||||
libjpeg-turbo/simd/x86_64/jfdctint-avx2.asm
|
||||
libjpeg-turbo/simd/x86_64/jidctint-avx2.asm
|
||||
libjpeg-turbo/simd/x86_64/jquanti-avx2.asm
|
||||
)
|
||||
|
||||
set(CMAKE_ASM_NASM_FLAGS "-D__x86_64__ -DELF -DPIC -I${CMAKE_CURRENT_SOURCE_DIR}/libjpeg-turbo/simd/nasm")
|
||||
|
||||
else ()
|
||||
|
||||
set(LIBJPEG_TURBO_SOURCES
|
||||
${LIBJPEG_TURBO_SOURCES}
|
||||
libjpeg-turbo/jsimd_none.c
|
||||
)
|
||||
|
||||
endif ()
|
||||
|
||||
add_library(jpeg STATIC ${LIBJPEG_TURBO_SOURCES})
|
||||
target_include_directories(jpeg PUBLIC ${LIBJPEG_TURBO_INCLUDES})
|
||||
@@ -0,0 +1,37 @@
|
||||
/* Version ID for the JPEG library.
|
||||
* Might be useful for tests like "#if JPEG_LIB_VERSION >= 60".
|
||||
*/
|
||||
#define JPEG_LIB_VERSION 62
|
||||
|
||||
/* libjpeg-turbo version */
|
||||
#define LIBJPEG_TURBO_VERSION 2.1.3
|
||||
|
||||
/* libjpeg-turbo version in integer form */
|
||||
#define LIBJPEG_TURBO_VERSION_NUMBER 2001003
|
||||
|
||||
/* Support arithmetic encoding */
|
||||
#define C_ARITH_CODING_SUPPORTED 1
|
||||
|
||||
/* Support arithmetic decoding */
|
||||
#define D_ARITH_CODING_SUPPORTED 1
|
||||
|
||||
/* Support in-memory source/destination managers */
|
||||
#define MEM_SRCDST_SUPPORTED 1
|
||||
|
||||
/* Use accelerated SIMD routines. */
|
||||
#define WITH_SIMD 1
|
||||
|
||||
/*
|
||||
* Define BITS_IN_JSAMPLE as either
|
||||
* 8 for 8-bit sample values (the usual setting)
|
||||
* 12 for 12-bit sample values
|
||||
* Only 8 and 12 are legal data precisions for lossy JPEG according to the
|
||||
* JPEG standard, and the IJG code does not support anything else!
|
||||
* We do not support run-time selection of data precision, sorry.
|
||||
*/
|
||||
|
||||
#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */
|
||||
|
||||
/* Define if your (broken) compiler shifts signed values as if they were
|
||||
unsigned. */
|
||||
/* #undef RIGHT_SHIFT_IS_UNSIGNED */
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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 General Public 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/>.
|
||||
*/
|
||||
|
||||
/* libjpeg-turbo build number */
|
||||
#define BUILD "20220523"
|
||||
|
||||
/* Compiler's inline keyword */
|
||||
#undef inline
|
||||
|
||||
/* How to obtain function inlining. */
|
||||
#define INLINE __inline__ __attribute__((always_inline))
|
||||
|
||||
/* How to obtain thread-local storage */
|
||||
#define THREAD_LOCAL __thread
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME "libjpeg-turbo"
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "2.1.3"
|
||||
|
||||
/* The size of `size_t', as computed by sizeof. */
|
||||
#define SIZEOF_SIZE_T __SIZEOF_SIZE_T__
|
||||
|
||||
/* Define if your compiler has __builtin_ctzl() and sizeof(unsigned long) == sizeof(size_t). */
|
||||
#define HAVE_BUILTIN_CTZL
|
||||
|
||||
/* Define to 1 if you have the <intrin.h> header file. */
|
||||
/* #undef HAVE_INTRIN_H */
|
||||
|
||||
#if defined(_MSC_VER) && defined(HAVE_INTRIN_H)
|
||||
#if (SIZEOF_SIZE_T == 8)
|
||||
#define HAVE_BITSCANFORWARD64
|
||||
#elif (SIZEOF_SIZE_T == 4)
|
||||
#define HAVE_BITSCANFORWARD
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__has_attribute)
|
||||
#if __has_attribute(fallthrough)
|
||||
#define FALLTHROUGH __attribute__((fallthrough));
|
||||
#else
|
||||
#define FALLTHROUGH
|
||||
#endif
|
||||
#else
|
||||
#define FALLTHROUGH
|
||||
#endif
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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 General Public 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/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* jversion.h
|
||||
*
|
||||
* This file was part of the Independent JPEG Group's software:
|
||||
* Copyright (C) 1991-2020, Thomas G. Lane, Guido Vollbeding.
|
||||
* libjpeg-turbo Modifications:
|
||||
* Copyright (C) 2010, 2012-2022, D. R. Commander.
|
||||
* For conditions of distribution and use, see the accompanying README.ijg
|
||||
* file.
|
||||
*
|
||||
* This file contains software version identification.
|
||||
*/
|
||||
|
||||
#if JPEG_LIB_VERSION >= 80
|
||||
|
||||
#define JVERSION "8d 15-Jan-2012"
|
||||
|
||||
#elif JPEG_LIB_VERSION >= 70
|
||||
|
||||
#define JVERSION "7 27-Jun-2009"
|
||||
|
||||
#else
|
||||
|
||||
#define JVERSION "6b 27-Mar-1998"
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* NOTE: It is our convention to place the authors in the following order:
|
||||
* - libjpeg-turbo authors (2009-) in descending order of the date of their
|
||||
* most recent contribution to the project, then in ascending order of the
|
||||
* date of their first contribution to the project, then in alphabetical
|
||||
* order
|
||||
* - Upstream authors in descending order of the date of the first inclusion of
|
||||
* their code
|
||||
*/
|
||||
|
||||
#define JCOPYRIGHT \
|
||||
"Copyright (C) 2009-2022 D. R. Commander\n" \
|
||||
"Copyright (C) 2015, 2020 Google, Inc.\n" \
|
||||
"Copyright (C) 2019-2020 Arm Limited\n" \
|
||||
"Copyright (C) 2015-2016, 2018 Matthieu Darbois\n" \
|
||||
"Copyright (C) 2011-2016 Siarhei Siamashka\n" \
|
||||
"Copyright (C) 2015 Intel Corporation\n" \
|
||||
"Copyright (C) 2013-2014 Linaro Limited\n" \
|
||||
"Copyright (C) 2013-2014 MIPS Technologies, Inc.\n" \
|
||||
"Copyright (C) 2009, 2012 Pierre Ossman for Cendio AB\n" \
|
||||
"Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies)\n" \
|
||||
"Copyright (C) 1999-2006 MIYASAKA Masaru\n" \
|
||||
"Copyright (C) 1991-2020 Thomas G. Lane, Guido Vollbeding"
|
||||
|
||||
#define JCOPYRIGHT_SHORT \
|
||||
"Copyright (C) 1991-2022 The libjpeg-turbo Project and many others"
|
||||
Submodule native/src/main/jni/image/libjpeg-turbo/libjpeg-turbo added at 3331f85edc.
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2020, D. R. Commander. All Rights Reserved.
|
||||
* Copyright (C) 2020-2021, Arm Limited. All Rights Reserved.
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#define HAVE_VLD1_S16_X3
|
||||
#define HAVE_VLD1_U16_X2
|
||||
#define HAVE_VLD1Q_U8_X4
|
||||
|
||||
/* Define compiler-independent count-leading-zeros and byte-swap macros */
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#define BUILTIN_CLZ(x) _CountLeadingZeros(x)
|
||||
#define BUILTIN_CLZLL(x) _CountLeadingZeros64(x)
|
||||
#define BUILTIN_BSWAP64(x) _byteswap_uint64(x)
|
||||
#elif defined(__clang__) || defined(__GNUC__)
|
||||
#define BUILTIN_CLZ(x) __builtin_clz(x)
|
||||
#define BUILTIN_CLZLL(x) __builtin_clzll(x)
|
||||
#define BUILTIN_BSWAP64(x) __builtin_bswap64(x)
|
||||
#else
|
||||
#error "Unknown compiler"
|
||||
#endif
|
||||
@@ -0,0 +1,97 @@
|
||||
# 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.
|
||||
|
||||
cmake_minimum_required(VERSION 3.4.1)
|
||||
project(png C)
|
||||
|
||||
set(LIBPNG_SOURCES
|
||||
libpng/png.c
|
||||
libpng/pngerror.c
|
||||
libpng/pngget.c
|
||||
libpng/pngmem.c
|
||||
libpng/pngpread.c
|
||||
libpng/pngread.c
|
||||
libpng/pngrio.c
|
||||
libpng/pngrtran.c
|
||||
libpng/pngrutil.c
|
||||
libpng/pngset.c
|
||||
libpng/pngtrans.c
|
||||
)
|
||||
|
||||
set(LIBPNG_INCLUDES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/libpng
|
||||
)
|
||||
set(LIBPNG_DEFINITIONS)
|
||||
set(LIBPNG_LIBRARIES z)
|
||||
|
||||
if (${ANDROID_ABI} STREQUAL "armeabi-v7a")
|
||||
|
||||
enable_language(ASM)
|
||||
|
||||
set(LIBPNG_SOURCES
|
||||
${LIBPNG_SOURCES}
|
||||
libpng/arm/arm_init.c
|
||||
libpng/arm/filter_neon.S
|
||||
${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c
|
||||
)
|
||||
set(LIBPNG_INCLUDES
|
||||
${LIBPNG_INCLUDES}
|
||||
${ANDROID_NDK}/sources/android/cpufeatures
|
||||
)
|
||||
set(LIBPNG_DEFINITIONS
|
||||
${LIBPNG_DEFINITIONS}
|
||||
-DPNG_ARM_NEON_API_SUPPORTED
|
||||
-DPNG_ARM_NEON_CHECK_SUPPORTED
|
||||
-DPNG_ARM_NEON_OPT=1
|
||||
-DPNG_ARM_NEON_IMPLEMENTATION=2
|
||||
-DPNG_ARM_NEON_FILE=\"contrib/arm-neon/android-ndk.c\"
|
||||
)
|
||||
set(LIBPNG_LIBRARIES
|
||||
${LIBPNG_LIBRARIES}
|
||||
)
|
||||
|
||||
elseif (${ANDROID_ABI} STREQUAL "arm64-v8a")
|
||||
|
||||
enable_language(ASM)
|
||||
|
||||
set(LIBPNG_SOURCES
|
||||
${LIBPNG_SOURCES}
|
||||
libpng/arm/arm_init.c
|
||||
libpng/arm/filter_neon_intrinsics.c
|
||||
libpng/arm/palette_neon_intrinsics.c
|
||||
${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c
|
||||
)
|
||||
set(LIBPNG_INCLUDES
|
||||
${LIBPNG_INCLUDES}
|
||||
${ANDROID_NDK}/sources/android/cpufeatures
|
||||
)
|
||||
set(LIBPNG_DEFINITIONS
|
||||
${LIBPNG_DEFINITIONS}
|
||||
-DPNG_ARM_NEON_API_SUPPORTED
|
||||
-DPNG_ARM_NEON_CHECK_SUPPORTED
|
||||
-DPNG_ARM_NEON_OPT=1
|
||||
-DPNG_ARM_NEON_IMPLEMENTATION=1
|
||||
-DPNG_ARM_NEON_FILE=\"contrib/arm-neon/android-ndk.c\"
|
||||
)
|
||||
set(LIBPNG_LIBRARIES
|
||||
${LIBPNG_LIBRARIES}
|
||||
)
|
||||
|
||||
endif ()
|
||||
|
||||
add_library(png STATIC ${LIBPNG_SOURCES})
|
||||
target_include_directories(png PUBLIC ${LIBPNG_INCLUDES})
|
||||
target_compile_definitions(png PRIVATE ${LIBPNG_DEFINITIONS})
|
||||
target_link_libraries(png PRIVATE ${LIBPNG_LIBRARIES})
|
||||
Submodule
+1
Submodule native/src/main/jni/image/libpng/libpng added at c81fed4715.
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* 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 General Public 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/>.
|
||||
*/
|
||||
|
||||
/* libpng 1.6.34 STANDARD API DEFINITION */
|
||||
|
||||
/* pnglibconf.h - library build configuration */
|
||||
|
||||
/* Libpng version 1.6.34 - September 29, 2017 */
|
||||
|
||||
/* Copyright (c) 1998-2017 Glenn Randers-Pehrson */
|
||||
|
||||
/* This code is released under the libpng license. */
|
||||
/* For conditions of distribution and use, see the disclaimer */
|
||||
/* and license in png.h */
|
||||
|
||||
/* pnglibconf.h */
|
||||
/* Machine generated file: DO NOT EDIT */
|
||||
/* Derived from: scripts/pnglibconf.dfa */
|
||||
#ifndef PNGLCONF_H
|
||||
#define PNGLCONF_H
|
||||
/* options */
|
||||
#define PNG_16BIT_SUPPORTED
|
||||
#define PNG_ALIGNED_MEMORY_SUPPORTED
|
||||
/*#undef PNG_ARM_NEON_API_SUPPORTED*/
|
||||
/*#undef PNG_ARM_NEON_CHECK_SUPPORTED*/
|
||||
/*#undef PNG_POWERPC_VSX_API_SUPPORTED*/
|
||||
/*#undef PNG_POWERPC_VSX_CHECK_SUPPORTED*/
|
||||
#define PNG_BENIGN_ERRORS_SUPPORTED
|
||||
#define PNG_BENIGN_READ_ERRORS_SUPPORTED
|
||||
/*#undef PNG_BENIGN_WRITE_ERRORS_SUPPORTED*/
|
||||
#define PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED
|
||||
#define PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
|
||||
#define PNG_COLORSPACE_SUPPORTED
|
||||
#define PNG_CONSOLE_IO_SUPPORTED
|
||||
#define PNG_CONVERT_tIME_SUPPORTED
|
||||
#define PNG_EASY_ACCESS_SUPPORTED
|
||||
/*#undef PNG_ERROR_NUMBERS_SUPPORTED*/
|
||||
#define PNG_ERROR_TEXT_SUPPORTED
|
||||
#define PNG_FIXED_POINT_SUPPORTED
|
||||
#define PNG_FLOATING_ARITHMETIC_SUPPORTED
|
||||
#define PNG_FLOATING_POINT_SUPPORTED
|
||||
#define PNG_FORMAT_AFIRST_SUPPORTED
|
||||
#define PNG_FORMAT_BGR_SUPPORTED
|
||||
#define PNG_GAMMA_SUPPORTED
|
||||
#define PNG_GET_PALETTE_MAX_SUPPORTED
|
||||
#define PNG_HANDLE_AS_UNKNOWN_SUPPORTED
|
||||
#define PNG_INCH_CONVERSIONS_SUPPORTED
|
||||
#define PNG_INFO_IMAGE_SUPPORTED
|
||||
#define PNG_IO_STATE_SUPPORTED
|
||||
#define PNG_MNG_FEATURES_SUPPORTED
|
||||
#define PNG_POINTER_INDEXING_SUPPORTED
|
||||
#define PNG_PROGRESSIVE_READ_SUPPORTED
|
||||
#define PNG_READ_16BIT_SUPPORTED
|
||||
#define PNG_READ_ALPHA_MODE_SUPPORTED
|
||||
#define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED
|
||||
#define PNG_READ_BACKGROUND_SUPPORTED
|
||||
#define PNG_READ_BGR_SUPPORTED
|
||||
#define PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
|
||||
#define PNG_READ_COMPOSITE_NODIV_SUPPORTED
|
||||
#define PNG_READ_COMPRESSED_TEXT_SUPPORTED
|
||||
#define PNG_READ_EXPAND_16_SUPPORTED
|
||||
#define PNG_READ_EXPAND_SUPPORTED
|
||||
#define PNG_READ_FILLER_SUPPORTED
|
||||
#define PNG_READ_GAMMA_SUPPORTED
|
||||
#define PNG_READ_GET_PALETTE_MAX_SUPPORTED
|
||||
#define PNG_READ_GRAY_TO_RGB_SUPPORTED
|
||||
#define PNG_READ_INTERLACING_SUPPORTED
|
||||
#define PNG_READ_INT_FUNCTIONS_SUPPORTED
|
||||
#define PNG_READ_INVERT_ALPHA_SUPPORTED
|
||||
#define PNG_READ_INVERT_SUPPORTED
|
||||
#define PNG_READ_OPT_PLTE_SUPPORTED
|
||||
#define PNG_READ_PACKSWAP_SUPPORTED
|
||||
#define PNG_READ_PACK_SUPPORTED
|
||||
#define PNG_READ_QUANTIZE_SUPPORTED
|
||||
#define PNG_READ_RGB_TO_GRAY_SUPPORTED
|
||||
#define PNG_READ_SCALE_16_TO_8_SUPPORTED
|
||||
#define PNG_READ_SHIFT_SUPPORTED
|
||||
#define PNG_READ_STRIP_16_TO_8_SUPPORTED
|
||||
#define PNG_READ_STRIP_ALPHA_SUPPORTED
|
||||
#define PNG_READ_SUPPORTED
|
||||
#define PNG_READ_SWAP_ALPHA_SUPPORTED
|
||||
#define PNG_READ_SWAP_SUPPORTED
|
||||
#define PNG_READ_TEXT_SUPPORTED
|
||||
#define PNG_READ_TRANSFORMS_SUPPORTED
|
||||
#define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
|
||||
#define PNG_READ_USER_CHUNKS_SUPPORTED
|
||||
#define PNG_READ_USER_TRANSFORM_SUPPORTED
|
||||
#define PNG_READ_bKGD_SUPPORTED
|
||||
#define PNG_READ_cHRM_SUPPORTED
|
||||
#define PNG_READ_eXIf_SUPPORTED
|
||||
#define PNG_READ_gAMA_SUPPORTED
|
||||
#define PNG_READ_hIST_SUPPORTED
|
||||
#define PNG_READ_iCCP_SUPPORTED
|
||||
#define PNG_READ_iTXt_SUPPORTED
|
||||
#define PNG_READ_oFFs_SUPPORTED
|
||||
#define PNG_READ_pCAL_SUPPORTED
|
||||
#define PNG_READ_pHYs_SUPPORTED
|
||||
#define PNG_READ_sBIT_SUPPORTED
|
||||
#define PNG_READ_sCAL_SUPPORTED
|
||||
#define PNG_READ_sPLT_SUPPORTED
|
||||
#define PNG_READ_sRGB_SUPPORTED
|
||||
#define PNG_READ_tEXt_SUPPORTED
|
||||
#define PNG_READ_tIME_SUPPORTED
|
||||
#define PNG_READ_tRNS_SUPPORTED
|
||||
#define PNG_READ_zTXt_SUPPORTED
|
||||
/*#undef PNG_SAVE_INT_32_SUPPORTED*/
|
||||
#define PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED
|
||||
#define PNG_SEQUENTIAL_READ_SUPPORTED
|
||||
#define PNG_SETJMP_SUPPORTED
|
||||
#define PNG_SET_OPTION_SUPPORTED
|
||||
#define PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
|
||||
#define PNG_SET_USER_LIMITS_SUPPORTED
|
||||
/*#undef PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED*/
|
||||
/*#undef PNG_SIMPLIFIED_READ_BGR_SUPPORTED*/
|
||||
/*#undef PNG_SIMPLIFIED_READ_SUPPORTED*/
|
||||
/*#undef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED*/
|
||||
/*#undef PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED*/
|
||||
/*#undef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED*/
|
||||
/*#undef PNG_SIMPLIFIED_WRITE_SUPPORTED*/
|
||||
/*#undef PNG_STDIO_SUPPORTED*/
|
||||
#define PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
|
||||
#define PNG_TEXT_SUPPORTED
|
||||
#define PNG_TIME_RFC1123_SUPPORTED
|
||||
#define PNG_UNKNOWN_CHUNKS_SUPPORTED
|
||||
#define PNG_USER_CHUNKS_SUPPORTED
|
||||
#define PNG_USER_LIMITS_SUPPORTED
|
||||
#define PNG_USER_MEM_SUPPORTED
|
||||
#define PNG_USER_TRANSFORM_INFO_SUPPORTED
|
||||
#define PNG_USER_TRANSFORM_PTR_SUPPORTED
|
||||
#define PNG_WARNINGS_SUPPORTED
|
||||
/*
|
||||
#define PNG_WRITE_16BIT_SUPPORTED
|
||||
#define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED
|
||||
#define PNG_WRITE_BGR_SUPPORTED
|
||||
#define PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
|
||||
#define PNG_WRITE_COMPRESSED_TEXT_SUPPORTED
|
||||
#define PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
|
||||
#define PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
|
||||
#define PNG_WRITE_FILLER_SUPPORTED
|
||||
#define PNG_WRITE_FILTER_SUPPORTED
|
||||
#define PNG_WRITE_FLUSH_SUPPORTED
|
||||
#define PNG_WRITE_GET_PALETTE_MAX_SUPPORTED
|
||||
#define PNG_WRITE_INTERLACING_SUPPORTED
|
||||
#define PNG_WRITE_INT_FUNCTIONS_SUPPORTED
|
||||
#define PNG_WRITE_INVERT_ALPHA_SUPPORTED
|
||||
#define PNG_WRITE_INVERT_SUPPORTED
|
||||
#define PNG_WRITE_OPTIMIZE_CMF_SUPPORTED
|
||||
#define PNG_WRITE_PACKSWAP_SUPPORTED
|
||||
#define PNG_WRITE_PACK_SUPPORTED
|
||||
#define PNG_WRITE_SHIFT_SUPPORTED
|
||||
#define PNG_WRITE_SUPPORTED
|
||||
#define PNG_WRITE_SWAP_ALPHA_SUPPORTED
|
||||
#define PNG_WRITE_SWAP_SUPPORTED
|
||||
#define PNG_WRITE_TEXT_SUPPORTED
|
||||
#define PNG_WRITE_TRANSFORMS_SUPPORTED
|
||||
#define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
|
||||
#define PNG_WRITE_USER_TRANSFORM_SUPPORTED
|
||||
#define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
|
||||
#define PNG_WRITE_bKGD_SUPPORTED
|
||||
#define PNG_WRITE_cHRM_SUPPORTED
|
||||
#define PNG_WRITE_eXIf_SUPPORTED
|
||||
#define PNG_WRITE_gAMA_SUPPORTED
|
||||
#define PNG_WRITE_hIST_SUPPORTED
|
||||
#define PNG_WRITE_iCCP_SUPPORTED
|
||||
#define PNG_WRITE_iTXt_SUPPORTED
|
||||
#define PNG_WRITE_oFFs_SUPPORTED
|
||||
#define PNG_WRITE_pCAL_SUPPORTED
|
||||
#define PNG_WRITE_pHYs_SUPPORTED
|
||||
#define PNG_WRITE_sBIT_SUPPORTED
|
||||
#define PNG_WRITE_sCAL_SUPPORTED
|
||||
#define PNG_WRITE_sPLT_SUPPORTED
|
||||
#define PNG_WRITE_sRGB_SUPPORTED
|
||||
#define PNG_WRITE_tEXt_SUPPORTED
|
||||
#define PNG_WRITE_tIME_SUPPORTED
|
||||
#define PNG_WRITE_tRNS_SUPPORTED
|
||||
#define PNG_WRITE_zTXt_SUPPORTED
|
||||
*/
|
||||
#define PNG_bKGD_SUPPORTED
|
||||
#define PNG_cHRM_SUPPORTED
|
||||
#define PNG_eXIf_SUPPORTED
|
||||
#define PNG_gAMA_SUPPORTED
|
||||
#define PNG_hIST_SUPPORTED
|
||||
#define PNG_iCCP_SUPPORTED
|
||||
#define PNG_iTXt_SUPPORTED
|
||||
#define PNG_oFFs_SUPPORTED
|
||||
#define PNG_pCAL_SUPPORTED
|
||||
#define PNG_pHYs_SUPPORTED
|
||||
#define PNG_sBIT_SUPPORTED
|
||||
#define PNG_sCAL_SUPPORTED
|
||||
#define PNG_sPLT_SUPPORTED
|
||||
#define PNG_sRGB_SUPPORTED
|
||||
#define PNG_tEXt_SUPPORTED
|
||||
#define PNG_tIME_SUPPORTED
|
||||
#define PNG_tRNS_SUPPORTED
|
||||
#define PNG_zTXt_SUPPORTED
|
||||
/* end of options */
|
||||
/* apng */
|
||||
#define PNG_APNG_SUPPORTED
|
||||
#define PNG_READ_APNG_SUPPORTED
|
||||
/*#undef PNG_WRITE_APNG_SUPPORTED*/
|
||||
/* end of apng */
|
||||
/* settings */
|
||||
#define PNG_API_RULE 0
|
||||
#define PNG_DEFAULT_READ_MACROS 1
|
||||
#define PNG_GAMMA_THRESHOLD_FIXED 5000
|
||||
#define PNG_IDAT_READ_SIZE PNG_ZBUF_SIZE
|
||||
#define PNG_INFLATE_BUF_SIZE 1024
|
||||
#define PNG_LINKAGE_API extern
|
||||
#define PNG_LINKAGE_CALLBACK extern
|
||||
#define PNG_LINKAGE_DATA extern
|
||||
#define PNG_LINKAGE_FUNCTION extern
|
||||
#define PNG_MAX_GAMMA_8 11
|
||||
#define PNG_QUANTIZE_BLUE_BITS 5
|
||||
#define PNG_QUANTIZE_GREEN_BITS 5
|
||||
#define PNG_QUANTIZE_RED_BITS 5
|
||||
#define PNG_TEXT_Z_DEFAULT_COMPRESSION (-1)
|
||||
#define PNG_TEXT_Z_DEFAULT_STRATEGY 0
|
||||
#define PNG_USER_CHUNK_CACHE_MAX 1000
|
||||
#define PNG_USER_CHUNK_MALLOC_MAX 8000000
|
||||
#define PNG_USER_HEIGHT_MAX 1000000
|
||||
#define PNG_USER_WIDTH_MAX 1000000
|
||||
#define PNG_ZBUF_SIZE 8192
|
||||
#define PNG_ZLIB_VERNUM 0 /* unknown */
|
||||
#define PNG_Z_DEFAULT_COMPRESSION (-1)
|
||||
#define PNG_Z_DEFAULT_NOFILTER_STRATEGY 0
|
||||
#define PNG_Z_DEFAULT_STRATEGY 1
|
||||
#define PNG_sCAL_PRECISION 5
|
||||
#define PNG_sRGB_PROFILE_CHECKS 2
|
||||
/* end of settings */
|
||||
#endif /* PNGLCONF_H */
|
||||
@@ -0,0 +1,27 @@
|
||||
# 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.
|
||||
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := stream
|
||||
LOCAL_SRC_FILES := \
|
||||
input_stream.c \
|
||||
input_stream_pipe.c \
|
||||
output_stream.c \
|
||||
output_stream_pipe.c \
|
||||
patch_head_input_stream.c
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
@@ -0,0 +1,28 @@
|
||||
# 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.
|
||||
|
||||
cmake_minimum_required(VERSION 3.4.1)
|
||||
project(stream C)
|
||||
|
||||
set(STREAM_SOURCES
|
||||
input_stream.c
|
||||
input_stream_pipe.c
|
||||
output_stream.c
|
||||
output_stream_pipe.c
|
||||
patch_head_input_stream.c
|
||||
)
|
||||
set(STREAM_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
add_library(stream STATIC ${STREAM_SOURCES})
|
||||
target_include_directories(stream PUBLIC ${STREAM_INCLUDES})
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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/28/2015.
|
||||
//
|
||||
|
||||
#ifndef STREAM_CONFIG_H
|
||||
#define STREAM_CONFIG_H
|
||||
|
||||
#define STREAM_SUPPORT_INPUT
|
||||
//#define STREAM_SUPPORT_INPUT_PIPE
|
||||
#define STREAM_SUPPORT_INPUT_PATCH_HEAD
|
||||
#define STREAM_SUPPORT_OUTPUT
|
||||
//#define STREAM_SUPPORT_OUTPUT_PIPE
|
||||
|
||||
#endif // STREAM_CONFIG_H
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* 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 10/19/2015.
|
||||
//
|
||||
|
||||
#include "config.h"
|
||||
#ifdef STREAM_SUPPORT_INPUT
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../log.h"
|
||||
#include "../utils.h"
|
||||
#include "input_stream.h"
|
||||
#include "stream_utils.h"
|
||||
|
||||
InputStream* create_input_stream(JNIEnv* env, jobject is)
|
||||
{
|
||||
jclass streamCls = (*env)->GetObjectClass(env, is);
|
||||
jmethodID readMID = (*env)->GetMethodID(env, streamCls, "read", "([BII)I");
|
||||
jmethodID closeMID = (*env)->GetMethodID(env, streamCls, "close", "()V");
|
||||
jbyteArray buffer;
|
||||
|
||||
if (readMID == NULL || closeMID == NULL) {
|
||||
LOGE(MSG("Can't get read or close method id"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buffer = (*env)->NewByteArray(env, BUFFER_SIZE);
|
||||
buffer = (*env)->NewGlobalRef(env, buffer);
|
||||
if (buffer == NULL) {
|
||||
LOGE(MSG("Can't create buffer"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
InputStream* inputStream = (InputStream*) malloc(sizeof(InputStream));
|
||||
if (inputStream == NULL) {
|
||||
LOGE(MSG("Out of memory"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inputStream->is = (*env)->NewGlobalRef(env, is);
|
||||
inputStream->readMID = readMID;
|
||||
inputStream->closeMID = closeMID;
|
||||
inputStream->buffer = buffer;
|
||||
|
||||
return inputStream;
|
||||
}
|
||||
|
||||
void destroy_input_stream(JNIEnv* env, InputStream** inputStream)
|
||||
{
|
||||
if (inputStream != NULL && *inputStream != NULL) {
|
||||
(*env)->DeleteGlobalRef(env, (*inputStream)->is);
|
||||
(*env)->DeleteGlobalRef(env, (*inputStream)->buffer);
|
||||
free(*inputStream);
|
||||
*inputStream = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
size_t read_input_stream(JNIEnv* env, InputStream* inputStream, unsigned char* buffer, int offset, size_t size)
|
||||
{
|
||||
size_t remainSize = size;
|
||||
size_t readSize = 0;
|
||||
int bufferOffset = offset;
|
||||
int len;
|
||||
|
||||
while (remainSize > 0) {
|
||||
len = MIN(BUFFER_SIZE, remainSize);
|
||||
|
||||
len = (*env)->CallIntMethod(env, inputStream->is, inputStream->readMID, inputStream->buffer, 0, len);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
LOGE(MSG("Catch exception"));
|
||||
(*env)->ExceptionDescribe(env);
|
||||
(*env)->ExceptionClear(env);
|
||||
len = -1;
|
||||
}
|
||||
|
||||
// end of the stream or catch exception
|
||||
if (len < 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
(*env)->GetByteArrayRegion(env, inputStream->buffer, 0, len, (jbyte *) (buffer + bufferOffset));
|
||||
|
||||
remainSize -= len;
|
||||
readSize += len;
|
||||
bufferOffset += len;
|
||||
}
|
||||
|
||||
return readSize;
|
||||
}
|
||||
|
||||
void close_input_stream(JNIEnv* env, InputStream* inputStream)
|
||||
{
|
||||
(*env)->CallVoidMethod(env, inputStream->is, inputStream->closeMID);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
LOGE(MSG("Catch exception"));
|
||||
(*env)->ExceptionDescribe(env);
|
||||
(*env)->ExceptionClear(env);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // STREAM_SUPPORT_INPUT
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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 10/19/2015.
|
||||
//
|
||||
|
||||
#ifndef STREAM_INPUT_STREAM_H
|
||||
#define STREAM_INPUT_STREAM_H
|
||||
|
||||
#include "config.h"
|
||||
#ifdef STREAM_SUPPORT_INPUT
|
||||
|
||||
#include <jni.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
jobject is;
|
||||
jmethodID readMID;
|
||||
jmethodID closeMID;
|
||||
jbyteArray buffer;
|
||||
} InputStream;
|
||||
|
||||
InputStream* create_input_stream(JNIEnv* env, jobject is);
|
||||
void destroy_input_stream(JNIEnv* env, InputStream** inputStream);
|
||||
size_t read_input_stream(JNIEnv* env, InputStream* inputStream, unsigned char* buffer, int offset, size_t size);
|
||||
void close_input_stream(JNIEnv* env, InputStream* inputStream);
|
||||
|
||||
#endif // STREAM_SUPPORT_INPUT
|
||||
|
||||
#endif // STREAM_INPUT_STREAM_H
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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 10/19/2015.
|
||||
//
|
||||
|
||||
#include "config.h"
|
||||
#if defined(STREAM_SUPPORT_INPUT) && defined(STREAM_SUPPORT_INPUT_PIPE)
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "input_stream_pipe.h"
|
||||
#include "../log.h"
|
||||
|
||||
InputStreamPipe* create_input_stream_pipe(JNIEnv* env, jobject isPipe)
|
||||
{
|
||||
jclass streamPipeCls = (*env)->GetObjectClass(env, isPipe);
|
||||
jmethodID obtainMID = (*env)->GetMethodID(env, streamPipeCls, "obtain", "()V");
|
||||
jmethodID releaseMID = (*env)->GetMethodID(env, streamPipeCls, "release", "()V");
|
||||
jmethodID openMID = (*env)->GetMethodID(env, streamPipeCls, "open", "()Ljava/io/InputStream;");
|
||||
jmethodID closeMID = (*env)->GetMethodID(env, streamPipeCls, "close", "()V");
|
||||
|
||||
if (obtainMID == NULL || releaseMID == NULL || openMID == NULL || closeMID == NULL) {
|
||||
LOGE(MSG("Can't get method id"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
InputStreamPipe* inputStreamPipe = (InputStreamPipe*) malloc(sizeof(InputStreamPipe));
|
||||
if (inputStreamPipe == NULL) {
|
||||
LOGE(MSG("Out of memory"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inputStreamPipe->isPipe = (*env)->NewGlobalRef(env, isPipe);
|
||||
inputStreamPipe->obtainMID = obtainMID;
|
||||
inputStreamPipe->releaseMID = releaseMID;
|
||||
inputStreamPipe->openMID = openMID;
|
||||
inputStreamPipe->closeMID = closeMID;
|
||||
|
||||
return inputStreamPipe;
|
||||
}
|
||||
|
||||
void destroy_input_stream_pipe(JNIEnv* env, InputStreamPipe** inputStreamPipe)
|
||||
{
|
||||
if (inputStreamPipe != NULL && *inputStreamPipe != NULL) {
|
||||
(*env)->DeleteGlobalRef(env, (*inputStreamPipe)->isPipe);
|
||||
free(*inputStreamPipe);
|
||||
*inputStreamPipe = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void obtain_input_stream_pipe(JNIEnv* env, InputStreamPipe* inputStreamPipe)
|
||||
{
|
||||
(*env)->CallVoidMethod(env, inputStreamPipe->isPipe, inputStreamPipe->obtainMID);
|
||||
}
|
||||
|
||||
void release_input_stream_pipe(JNIEnv* env, InputStreamPipe* inputStreamPipe)
|
||||
{
|
||||
(*env)->CallVoidMethod(env, inputStreamPipe->isPipe, inputStreamPipe->releaseMID);
|
||||
}
|
||||
|
||||
InputStream* open_input_stream_from_pipe(JNIEnv* env, InputStreamPipe* inputStreamPipe)
|
||||
{
|
||||
jobject is = (*env)->CallObjectMethod(env, inputStreamPipe->isPipe, inputStreamPipe->openMID);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
LOGE(MSG("Catch exception"));
|
||||
(*env)->ExceptionDescribe(env);
|
||||
(*env)->ExceptionClear(env);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return create_input_stream(env, is);
|
||||
}
|
||||
|
||||
void close_input_stream_from_pipe(JNIEnv* env, InputStreamPipe* inputStreamPipe)
|
||||
{
|
||||
(*env)->CallVoidMethod(env, inputStreamPipe->isPipe, inputStreamPipe->closeMID);
|
||||
}
|
||||
|
||||
#endif // STREAM_SUPPORT_INPUT && STREAM_SUPPORT_INPUT_PIPE
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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 10/19/2015.
|
||||
//
|
||||
|
||||
#ifndef STREAM_INPUT_STREAM_PIPE_H
|
||||
#define STREAM_INPUT_STREAM_PIPE_H
|
||||
|
||||
#include "config.h"
|
||||
#if defined(STREAM_SUPPORT_INPUT) && defined(STREAM_SUPPORT_INPUT_PIPE)
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "input_stream.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
jobject isPipe;
|
||||
jmethodID obtainMID;
|
||||
jmethodID releaseMID;
|
||||
jmethodID openMID;
|
||||
jmethodID closeMID;
|
||||
} InputStreamPipe;
|
||||
|
||||
InputStreamPipe* create_input_stream_pipe(JNIEnv* env, jobject isPipe);
|
||||
void destroy_input_stream_pipe(JNIEnv* env, InputStreamPipe** inputStreamPipe);
|
||||
void obtain_input_stream_pipe(JNIEnv* env, InputStreamPipe* inputStreamPipe);
|
||||
void release_input_stream_pipe(JNIEnv* env, InputStreamPipe* inputStreamPipe);
|
||||
InputStream* open_input_stream_from_pipe(JNIEnv* env, InputStreamPipe* inputStreamPipe);
|
||||
void close_input_stream_from_pipe(JNIEnv* env, InputStreamPipe* inputStreamPipe);
|
||||
|
||||
#endif // STREAM_SUPPORT_INPUT && STREAM_SUPPORT_INPUT_PIPE
|
||||
|
||||
#endif // STREAM_INPUT_STREAM_PIPE_H
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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 10/19/2015.
|
||||
//
|
||||
|
||||
#include "config.h"
|
||||
#ifdef STREAM_SUPPORT_OUTPUT
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../log.h"
|
||||
#include "../utils.h"
|
||||
#include "output_stream.h"
|
||||
#include "stream_utils.h"
|
||||
|
||||
OutputStream* create_output_stream(JNIEnv* env, jobject os)
|
||||
{
|
||||
jclass streamCls = (*env)->GetObjectClass(env, os);
|
||||
jmethodID writeMID = (*env)->GetMethodID(env, streamCls, "write", "([BII)V");
|
||||
jmethodID closeMID = (*env)->GetMethodID(env, streamCls, "close", "()V");
|
||||
jbyteArray buffer;
|
||||
|
||||
if (writeMID == NULL || closeMID == NULL) {
|
||||
LOGE(MSG("Can't get write or close method id"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buffer = (*env)->NewByteArray(env, BUFFER_SIZE);
|
||||
buffer = (*env)->NewGlobalRef(env, buffer);
|
||||
if (buffer == NULL) {
|
||||
LOGE(MSG("Can't create buffer"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
OutputStream* outputStream = (OutputStream*) malloc(sizeof(OutputStream));
|
||||
if (outputStream == NULL) {
|
||||
LOGE(MSG("Out of memory"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
outputStream->os = (*env)->NewGlobalRef(env, os);
|
||||
outputStream->writeMID = writeMID;
|
||||
outputStream->closeMID = closeMID;
|
||||
outputStream->buffer = buffer;
|
||||
|
||||
return outputStream;
|
||||
}
|
||||
|
||||
void destroy_output_stream(JNIEnv* env, OutputStream** outputStream)
|
||||
{
|
||||
if (outputStream != NULL && *outputStream != NULL) {
|
||||
(*env)->DeleteGlobalRef(env, (*outputStream)->os);
|
||||
(*env)->DeleteGlobalRef(env, (*outputStream)->buffer);
|
||||
free(*outputStream);
|
||||
*outputStream = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
size_t write_output_stream(JNIEnv* env, OutputStream* outputStream, const unsigned char* buffer, int offset, size_t size)
|
||||
{
|
||||
size_t remainSize = size;
|
||||
size_t readSize = 0;
|
||||
int bufferOffset = offset;
|
||||
int len;
|
||||
|
||||
while (remainSize > 0) {
|
||||
len = MIN(BUFFER_SIZE, remainSize);
|
||||
|
||||
// Copy date from buffer to outputStream->buffer
|
||||
(*env)->SetByteArrayRegion(env, outputStream->buffer, 0, len, (jbyte *) (buffer + bufferOffset));
|
||||
|
||||
// Invoke OutputStream.write
|
||||
(*env)->CallVoidMethod(env, outputStream->os, outputStream->writeMID, outputStream->buffer, 0, len);
|
||||
|
||||
// Catch exception
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
LOGE(MSG("Catch exception"));
|
||||
(*env)->ExceptionDescribe(env);
|
||||
(*env)->ExceptionClear(env);
|
||||
break;
|
||||
}
|
||||
|
||||
remainSize -= len;
|
||||
readSize += len;
|
||||
bufferOffset += len;
|
||||
}
|
||||
|
||||
return readSize;
|
||||
}
|
||||
|
||||
void close_output_stream(JNIEnv* env, OutputStream* outputStream)
|
||||
{
|
||||
(*env)->CallVoidMethod(env, outputStream->os, outputStream->closeMID);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
LOGE(MSG("Catch exception"));
|
||||
(*env)->ExceptionDescribe(env);
|
||||
(*env)->ExceptionClear(env);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // STREAM_SUPPORT_OUTPUT
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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 10/19/2015.
|
||||
//
|
||||
|
||||
#ifndef STREAM_OUTPUT_STREAM_H
|
||||
#define STREAM_OUTPUT_STREAM_H
|
||||
|
||||
#include "config.h"
|
||||
#ifdef STREAM_SUPPORT_OUTPUT
|
||||
|
||||
#include <jni.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
jobject os;
|
||||
jmethodID writeMID;
|
||||
jmethodID closeMID;
|
||||
jbyteArray buffer;
|
||||
} OutputStream;
|
||||
|
||||
OutputStream* create_output_stream(JNIEnv* env, jobject os);
|
||||
void destroy_output_stream(JNIEnv* env, OutputStream** outputStream);
|
||||
size_t write_output_stream(JNIEnv* env, OutputStream* outputStream, const unsigned char* buffer, int offset, size_t size);
|
||||
void close_output_stream(JNIEnv* env, OutputStream* outputStream);
|
||||
|
||||
#endif // STREAM_SUPPORT_OUTPUT
|
||||
|
||||
#endif // STREAM_OUTPUT_STREAM_H
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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 10/19/2015.
|
||||
//
|
||||
|
||||
#include "config.h"
|
||||
#if defined(STREAM_SUPPORT_OUTPUT) && defined(STREAM_SUPPORT_OUTPUT_PIPE)
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "output_stream_pipe.h"
|
||||
#include "../log.h"
|
||||
|
||||
OutputStreamPipe* create_output_stream_pipe(JNIEnv* env, jobject osPipe)
|
||||
{
|
||||
jclass streamPipeCls = (*env)->GetObjectClass(env, osPipe);
|
||||
jmethodID obtainMID = (*env)->GetMethodID(env, streamPipeCls, "obtain", "()V");
|
||||
jmethodID releaseMID = (*env)->GetMethodID(env, streamPipeCls, "release", "()V");
|
||||
jmethodID openMID = (*env)->GetMethodID(env, streamPipeCls, "open", "()Ljava/io/OutputStream;");
|
||||
jmethodID closeMID = (*env)->GetMethodID(env, streamPipeCls, "close", "()V");
|
||||
|
||||
if (obtainMID == NULL || releaseMID == NULL || openMID == NULL || closeMID == NULL) {
|
||||
LOGE(MSG("Can't get method id"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
OutputStreamPipe* outputStreamPipe = (OutputStreamPipe*) malloc(sizeof(OutputStreamPipe));
|
||||
if (outputStreamPipe == NULL) {
|
||||
LOGE(MSG("Out of memory"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
outputStreamPipe->osPipe = (*env)->NewGlobalRef(env, osPipe);
|
||||
outputStreamPipe->obtainMID = obtainMID;
|
||||
outputStreamPipe->releaseMID = releaseMID;
|
||||
outputStreamPipe->openMID = openMID;
|
||||
outputStreamPipe->closeMID = closeMID;
|
||||
|
||||
return outputStreamPipe;
|
||||
}
|
||||
|
||||
void destroy_output_stream_pipe(JNIEnv* env, OutputStreamPipe** outputStreamPipe)
|
||||
{
|
||||
if (outputStreamPipe != NULL && *outputStreamPipe != NULL) {
|
||||
(*env)->DeleteGlobalRef(env, (*outputStreamPipe)->osPipe);
|
||||
free(*outputStreamPipe);
|
||||
*outputStreamPipe = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void obtain_output_stream_pipe(JNIEnv* env, OutputStreamPipe* outputStreamPipe)
|
||||
{
|
||||
(*env)->CallVoidMethod(env, outputStreamPipe->osPipe, outputStreamPipe->obtainMID);
|
||||
}
|
||||
|
||||
void release_output_stream_pipe(JNIEnv* env, OutputStreamPipe* outputStreamPipe)
|
||||
{
|
||||
(*env)->CallVoidMethod(env, outputStreamPipe->osPipe, outputStreamPipe->releaseMID);
|
||||
}
|
||||
|
||||
OutputStream* open_output_stream_from_pipe(JNIEnv* env, OutputStreamPipe* outputStreamPipe)
|
||||
{
|
||||
jobject os = (*env)->CallObjectMethod(env, outputStreamPipe->osPipe, outputStreamPipe->openMID);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
LOGE(MSG("Catch exception"));
|
||||
(*env)->ExceptionDescribe(env);
|
||||
(*env)->ExceptionClear(env);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return create_output_stream(env, os);
|
||||
}
|
||||
|
||||
void close_output_stream_from_pipe(JNIEnv* env, OutputStreamPipe* outputStreamPipe)
|
||||
{
|
||||
(*env)->CallVoidMethod(env, outputStreamPipe->osPipe, outputStreamPipe->closeMID);
|
||||
}
|
||||
|
||||
#endif // STREAM_SUPPORT_OUTPUT && STREAM_SUPPORT_OUTPUT_PIPE
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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 10/19/2015.
|
||||
//
|
||||
|
||||
#ifndef STREAM_OUTPUT_STREAM_PIPE_H
|
||||
#define STREAM_OUTPUT_STREAM_PIPE_H
|
||||
|
||||
#include "config.h"
|
||||
#if defined(STREAM_SUPPORT_OUTPUT) && defined(STREAM_SUPPORT_OUTPUT_PIPE)
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include "output_stream.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
jobject osPipe;
|
||||
jmethodID obtainMID;
|
||||
jmethodID releaseMID;
|
||||
jmethodID openMID;
|
||||
jmethodID closeMID;
|
||||
} OutputStreamPipe;
|
||||
|
||||
OutputStreamPipe* create_output_stream_pipe(JNIEnv* env, jobject osPipe);
|
||||
void destroy_output_stream_pipe(JNIEnv* env, OutputStreamPipe** outputStreamPipe);
|
||||
void obtain_output_stream_pipe(JNIEnv* env, OutputStreamPipe* outputStreamPipe);
|
||||
void release_output_stream_pipe(JNIEnv* env, OutputStreamPipe* outputStreamPipe);
|
||||
OutputStream* open_output_stream_from_pipe(JNIEnv* env, OutputStreamPipe* outputStreamPipe);
|
||||
void close_output_stream_from_pipe(JNIEnv* env, OutputStreamPipe* outputStreamPipe);
|
||||
|
||||
#endif // STREAM_SUPPORT_OUTPUT && STREAM_SUPPORT_OUTPUT_PIPE
|
||||
|
||||
#endif // STREAM_OUTPUT_STREAM_PIPE_H
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// Created by Hippo on 1/1/2016.
|
||||
//
|
||||
|
||||
#include "config.h"
|
||||
#if defined(STREAM_SUPPORT_INPUT) && defined(STREAM_SUPPORT_INPUT_PATCH_HEAD)
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "patch_head_input_stream.h"
|
||||
#include "../log.h"
|
||||
#include "../utils.h"
|
||||
|
||||
#define READ_BUFFER_SIZE (256 * 1024) // 256KB
|
||||
|
||||
PatchHeadInputStream* create_patch_head_input_stream(
|
||||
InputStream* input_stream, const unsigned char* patch, unsigned int patch_length)
|
||||
{
|
||||
unsigned char* patch_copy;
|
||||
|
||||
PatchHeadInputStream* patch_head_input_stream = (PatchHeadInputStream*) malloc(sizeof(PatchHeadInputStream));
|
||||
if (patch_head_input_stream == NULL) {
|
||||
WTF_OM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Copy patch
|
||||
patch_copy = (unsigned char*) malloc(patch_length * sizeof(char));
|
||||
if (patch_copy == NULL) {
|
||||
WTF_OM;
|
||||
free(patch_head_input_stream);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(patch_copy, patch, patch_length);
|
||||
|
||||
patch_head_input_stream->input_stream = input_stream;
|
||||
patch_head_input_stream->patch = patch_copy;
|
||||
patch_head_input_stream->patch_length = patch_length;
|
||||
patch_head_input_stream->read_count = 0;
|
||||
|
||||
return patch_head_input_stream;
|
||||
}
|
||||
|
||||
size_t read_patch_head_input_stream(JNIEnv* env, PatchHeadInputStream* patch_head_input_stream,
|
||||
unsigned char* buffer, int offset, size_t size)
|
||||
{
|
||||
size_t len = MIN(size, patch_head_input_stream->patch_length - patch_head_input_stream->read_count);
|
||||
int buffer_offset = offset;
|
||||
|
||||
if (len > 0) {
|
||||
memcpy(buffer + buffer_offset, patch_head_input_stream->patch + patch_head_input_stream->read_count, len);
|
||||
patch_head_input_stream->read_count += len;
|
||||
buffer_offset += len;
|
||||
}
|
||||
|
||||
if (size > len) {
|
||||
len += read_input_stream(env, patch_head_input_stream->input_stream, buffer, buffer_offset, size - len);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void* read_patch_head_input_stream_all(JNIEnv* env, PatchHeadInputStream* patch_head_input_stream, size_t* length)
|
||||
{
|
||||
size_t len = 0;
|
||||
size_t read;
|
||||
void* buffer = NULL;
|
||||
|
||||
buffer = malloc(READ_BUFFER_SIZE);
|
||||
if (buffer == NULL) {
|
||||
WTF_OM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
// Read from stream
|
||||
read = read_patch_head_input_stream(env, patch_head_input_stream, buffer, len, READ_BUFFER_SIZE);
|
||||
len += read;
|
||||
// Check stream end
|
||||
if (read < READ_BUFFER_SIZE) {
|
||||
// Get the end, shrink the buffer
|
||||
buffer = realloc(buffer, len);
|
||||
*length = len;
|
||||
return buffer;
|
||||
}
|
||||
// Extent buffer
|
||||
buffer = realloc(buffer, len + READ_BUFFER_SIZE);
|
||||
if (buffer == NULL) {
|
||||
WTF_OM;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void destroy_patch_head_input_stream(JNIEnv* env, PatchHeadInputStream** patch_head_input_stream)
|
||||
{
|
||||
if (patch_head_input_stream != NULL && *patch_head_input_stream != NULL) {
|
||||
// Free input stream
|
||||
destroy_input_stream(env, &(*patch_head_input_stream)->input_stream);
|
||||
// Free patch
|
||||
free((*patch_head_input_stream)->patch);
|
||||
(*patch_head_input_stream)->patch = NULL;
|
||||
// Free itself
|
||||
free(*patch_head_input_stream);
|
||||
*patch_head_input_stream = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void close_patch_head_input_stream(JNIEnv* env, PatchHeadInputStream* patch_head_input_stream)
|
||||
{
|
||||
close_input_stream(env, patch_head_input_stream->input_stream);
|
||||
}
|
||||
|
||||
#endif // STREAM_SUPPORT_INPUT && STREAM_SUPPORT_INPUT_PATCH_HEAD
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// Created by Hippo on 1/1/2016.
|
||||
//
|
||||
|
||||
#ifndef STREAM_PATCH_HEAD_INPUT_STREAM_H
|
||||
#define STREAM_PATCH_HEAD_INPUT_STREAM_H
|
||||
|
||||
#include "config.h"
|
||||
#if defined(STREAM_SUPPORT_INPUT) && defined(STREAM_SUPPORT_INPUT_PATCH_HEAD)
|
||||
|
||||
#include "input_stream.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
InputStream* input_stream;
|
||||
unsigned char* patch;
|
||||
unsigned int patch_length;
|
||||
unsigned int read_count;
|
||||
} PatchHeadInputStream;
|
||||
|
||||
PatchHeadInputStream* create_patch_head_input_stream(
|
||||
InputStream* input_stream, const unsigned char* patch, unsigned int patch_length);
|
||||
void destroy_patch_head_input_stream(JNIEnv* env, PatchHeadInputStream** patch_head_input_stream);
|
||||
size_t read_patch_head_input_stream(JNIEnv* env, PatchHeadInputStream* patch_head_input_stream,
|
||||
unsigned char* buffer, int offset, size_t size);
|
||||
void* read_patch_head_input_stream_all(JNIEnv* env, PatchHeadInputStream* patch_head_input_stream, size_t* length);
|
||||
void close_patch_head_input_stream(JNIEnv* env, PatchHeadInputStream* patch_head_input_stream);
|
||||
|
||||
#endif // STREAM_SUPPORT_INPUT && STREAM_SUPPORT_INPUT_PATCH_HEAD
|
||||
|
||||
#endif // STREAM_PATCH_HEAD_INPUT_STREAM_H
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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 10/19/2015.
|
||||
//
|
||||
|
||||
#ifndef STREAM_STREAM_UTILS_H
|
||||
#define STREAM_STREAM_UTILS_H
|
||||
|
||||
#define BUFFER_SIZE 256
|
||||
|
||||
#endif // STREAM_STREAM_UTILS_H
|
||||
@@ -21,9 +21,10 @@
|
||||
#include <archive.h>
|
||||
#include <lzma.h>
|
||||
#include <zlib.h>
|
||||
#include "image/libjpeg-turbo/jconfigint.h"
|
||||
#include <nettle/config.h>
|
||||
|
||||
#include "image/java_wrapper.h"
|
||||
#include "java_wrapper.h"
|
||||
|
||||
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
JNIEnv *env;
|
||||
@@ -49,6 +50,11 @@ Java_com_hippo_Native_getliblzmaVersion(JNIEnv *env, jclass clazz) {
|
||||
return (*env)->NewStringUTF(env, lzma_version_string());
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_com_hippo_Native_getlibjpeg_1turboVersion(JNIEnv *env, jclass clazz) {
|
||||
return (*env)->NewStringUTF(env, VERSION);
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_com_hippo_Native_getzlibVersion(JNIEnv *env, jclass clazz) {
|
||||
return (*env)->NewStringUTF(env, ZLIB_VERSION);
|
||||
|
||||
Reference in new issue
Block a user