From d0a9c4d3f0ea1acfe339128624ddcb28c4bf85df Mon Sep 17 00:00:00 2001 From: SkyKai <1132234509@qq.com> Date: Sat, 6 Nov 2021 13:27:12 +0800 Subject: [PATCH 01/16] Update README.md --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 8da3a53..02faa10 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,10 @@ + +### [Android 工程师进阶手册(8 年 Android 开发者的成长感悟)](https://github.com/Skykai521/AndroidDeveloperAdvancedManual) + +### 点击查看:https://github.com/Skykai521/AndroidDeveloperAdvancedManual + +*** + # StickerCamera This is an Android application with camera,picture cropping,collage sticking and tagging. From 9b512d2d5f201b67959cb07b8a7a1cbd0dc543dd Mon Sep 17 00:00:00 2001 From: SkyKai <1132234509@qq.com> Date: Thu, 18 Jun 2026 18:29:38 +0800 Subject: [PATCH 02/16] =?UTF-8?q?docs:=20=E7=BC=96=E8=AF=91=E9=93=BE?= =?UTF-8?q?=E7=8E=B0=E4=BB=A3=E5=8C=96=E8=AE=BE=E8=AE=A1=20spec?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AGP 8.11 + Gradle 8.13 + JDK 17 + AndroidX 全面现代化方案, compileSdk/targetSdk 36, minSdk 26。 Co-Authored-By: Claude Opus 4.8 (1M context) --- ...18-build-toolchain-modernization-design.md | 161 ++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 docs/superpowers/specs/2026-06-18-build-toolchain-modernization-design.md diff --git a/docs/superpowers/specs/2026-06-18-build-toolchain-modernization-design.md b/docs/superpowers/specs/2026-06-18-build-toolchain-modernization-design.md new file mode 100644 index 0000000..75e5310 --- /dev/null +++ b/docs/superpowers/specs/2026-06-18-build-toolchain-modernization-design.md @@ -0,0 +1,161 @@ +# StickerCamera 编译链现代化设计 + +- 日期: 2026-06-18 +- 状态: 已批准设计,待写实现计划 +- 作者: SkyKai + Claude Code + +## 背景 + +StickerCamera 是 2015 年的 Android 工程,编译链停留在 AGP 1.2.3 / Gradle 2.4 / compileSdk 22,依赖 `jcenter()`(2021 年已停服)、`android.support.*`(已 EOL)、Retrolambda、ButterKnife 6.1.0,以及若干已废弃的 jcenter UI 库。本工程当前无法在现代开发机上构建。 + +开发机环境已就绪:JDK 8/11/17(默认 17),Android SDK 含 `android-36` 平台与 `build-tools 36.0.0`,NDK 已装。 + +## 目标 + +把整个工程的编译链升级到现代、可长期维护的版本,完成 AndroidX 全面迁移,使其能在当前开发机上 `./gradlew assembleDebug` 构建通过,并保持原有功能。 + +### 目标版本(已确认) + +| 项 | 现状 | 目标 | +|---|---|---| +| JDK(运行 Gradle) | — | 17 | +| Java source/target | Retrolambda 模拟 8 | 17(移除 Retrolambda) | +| Gradle wrapper | 2.4 | 8.13 | +| AGP | 1.2.3 | 8.11.1 | +| compileSdk | 22 | 36 | +| targetSdk | 22 | 36 | +| minSdk | 15 | 26 | +| 仓库 | `jcenter()` | `google()` + `mavenCentral()` | +| AndroidX | support 库 | `android.useAndroidX=true` 全迁移 | + +> 备注:AGP 8.11.x 是稳定支持 compileSdk 36 的版本线,配对 Gradle 8.13。若实现时该精确版本号有微调,以"能稳定支持 compileSdk 36 的最近 AGP 8.11+/配套 Gradle"为准。 + +## 范围 + +### 范围内 + +1. 构建脚本与 wrapper 全面升级(根、settings、gradle.properties、三模块、wrapper、local.properties)。 +2. `android.support.*` → `androidx.*` 全迁移(java + xml)。 +3. ButterKnife 6.1.0 → 10.2.3(保留 ButterKnife)。 +4. EventBus 2.4.0 → 3.3.1。 +5. 替换 3 个仍在用的废弃 UI 库:melnykov FAB、sephiroth HListView、systembartint。 +6. 删除未使用的 rengwuxian MaterialEditText 依赖。 +7. Gpu-Image 原生 `.so` 迁移到 `jniLibs` 并裁剪废弃 ABI。 +8. 本地 jar(fastjson、UIL)切换为 mavenCentral 坐标。 +9. 移除 Retrolambda。 +10. targetSdk 36 带来的强制 edge-to-edge 适配(各界面 WindowInsets)。 + +### 范围外(本次不做) + +- 不替换 UIL 为 Glide、不替换 fastjson 为 fastjson2(仅升版本/换坐标,API 不变)。 +- 不重构 app 业务架构、不动自定义控件(贴纸/标签引擎)逻辑。 +- 不引入 Kotlin、不引入 View Binding(除非 ButterKnife 与 AGP 8 冲突,见风险)。 +- 不做单元测试补全(工程现仅有空的 instrumentation 桩)。 + +## 详细设计 + +### 1. 构建文件 + +- **根 `build.gradle`**:删除 `me.tatarka:gradle-retrolambda` classpath;AGP `1.2.3` → `8.11.1`;移除 `buildscript`/`allprojects` 里的 `jcenter()`(仓库改到 settings 集中声明)。 +- **`settings.gradle`**:新增 `pluginManagement { repositories { google(); mavenCentral(); gradlePluginPortal() } }` 与 `dependencyResolutionManagement { repositories { google(); mavenCentral() } }`;保留 `include ':app', ':Gpu-Image', ':ImageViewTouch'`。 +- **`gradle.properties`**:新增 `android.useAndroidX=true`、`android.nonTransitiveRClass=true`;设置合理 `org.gradle.jvmargs`(如 `-Xmx2048m -Dfile.encoding=UTF-8`)。 +- **`gradle/wrapper/gradle-wrapper.properties`**:`distributionUrl` → `gradle-8.13-all.zip`。 +- **`local.properties`**:写入 `sdk.dir=/Users/skykai/Library/Android/sdk`(该文件不纳入 git)。 +- **各模块 `build.gradle`**: + - `apply plugin` 形式保留或转 `plugins {}` 均可,但移除 `me.tatarka.retrolambda`。 + - `android { namespace "" }`,并从对应 `AndroidManifest.xml` 删除 `package=` 属性。 + - `compileSdk 36`;`:app` 设 `minSdk 26 / targetSdk 36`,库模块设 `minSdk 26`。 + - `buildToolsVersion` 可省略(AGP 自动选默认)。 + - `compileOptions { sourceCompatibility JavaVersion.VERSION_17; targetCompatibility JavaVersion.VERSION_17 }`。 + - 依赖配置 `compile` → `implementation`(模块间 `compile project(...)` → `implementation project(...)`;库模块对外暴露的 API 用 `api`)。 + - 启用 `buildFeatures { }` 视需要(本次无需 viewBinding,除非回退方案触发)。 + +各模块 namespace: +- `:app` → `com.github.skykai.stickercamera` +- `:Gpu-Image` → `jp.co.cyberagent.android.gpuimage` +- `:ImageViewTouch` → `com.imagezoom`(已确认;该模块为标准 `src/main` 布局,无需 sourceSets 调整,仅需加 namespace、删 manifest 的 `package`) + +### 2. AndroidX 迁移(实测范围) + +仅 7 个 java 文件 + 3 处 XML 含 `android.support.*`,均为 1:1 改名: + +| 旧 | 新 | +|---|---| +| `android.support.v7.app.AppCompatActivity` | `androidx.appcompat.app.AppCompatActivity` | +| `android.support.v4.app.Fragment` / `FragmentActivity` / `FragmentManager` / `FragmentPagerAdapter` | `androidx.fragment.app.*` | +| `android.support.v4.view.ViewPager`(含 `OnPageChangeListener`) | `androidx.viewpager.widget.ViewPager` | +| `android.support.v4.widget.SwipeRefreshLayout` | `androidx.swiperefreshlayout.widget.SwipeRefreshLayout` | +| `android.support.v7.widget.RecyclerView` / `LinearLayoutManager` | `androidx.recyclerview.widget.*` | +| `android.support.v7.widget.CardView` | `androidx.cardview.widget.CardView` | +| `android.support.annotation.Nullable` | `androidx.annotation.Nullable` | + +XML 中 3 处全限定标签同步改名:`android.support.v4.view.ViewPager`、`android.support.v7.widget.CardView`、`android.support.v7.widget.RecyclerView`。 + +### 3. ButterKnife 6.1.0 → 10.2.3 + +- 依赖:`implementation 'com.jakewharton:butterknife:10.2.3'` + `annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.3'`。 +- 代码:`@InjectView` → `@BindView`(6 文件共 30 处);`ButterKnife.inject(...)` → `ButterKnife.bind(...)`(7 处,含 MainActivity 的 ViewHolder `bind(this, itemView)`);其它 ButterKnife 注解(如 `@OnClick`,若有)一并按 10.x API 调整。 +- 注意:ButterKnife 10.x 要求 AndroidX,需先完成第 2 步。 + +### 4. EventBus 2.4.0 → 3.3.1 + +- 依赖:`implementation 'org.greenrobot:eventbus:3.3.1'`。 +- 代码(2 文件):`import de.greenrobot.event.EventBus` → `org.greenrobot.eventbus.EventBus`;`register`/`unregister`/`post` API 不变;`public void onEventMainThread(FeedItem)` → 加注解 `@Subscribe(threadMode = ThreadMode.MAIN)`,方法名可改为 `onEvent`(MainActivity)。 + +### 5. 废弃 UI 库替换(功能优先,允许观感微调) + +- **melnykov FAB → Material Components FAB**(`com.google.android.material:material:1.11.0`): + - `activity_main.xml`:`com.melnykov.fab.FloatingActionButton` → `com.google.android.material.floatingactionbutton.FloatingActionButton`,属性按 Material API 调整。 + - `MainActivity.java`:导入与字段类型改为 Material FAB;放弃 `attachToRecyclerView` 的随滚动自动隐藏特性(Material FAB 无此 API)。 +- **sephiroth HListView → 水平 RecyclerView**(本次最重一块): + - `activity_image_process.xml`:`it.sephiroth.android.library.widget.HListView` → `androidx.recyclerview.widget.RecyclerView`。 + - `PhotoProcessActivity.java`:`bottomToolBar` 类型改为 `RecyclerView`,设置 `LinearLayoutManager(HORIZONTAL)`;`setOnItemClickListener` 改走 adapter 点击回调。 + - `FilterAdapter`、`StickerToolAdapter`:从 `BaseAdapter` 重写为 `RecyclerView.Adapter`(getView → onCreateViewHolder/onBindViewHolder,新增点击回调接口)。 +- **systembartint → edge-to-edge + 状态栏着色**: + - `BaseActivity.initWindow()`:移除 `FLAG_TRANSLUCENT_STATUS/NAVIGATION` 与 `SystemBarTintManager`;改用 `getWindow().setStatusBarColor(getColorPrimary())` 等价表达原"状态栏着主题色"意图。 +- **rengwuxian MaterialEditText → 删除**:实测全工程无引用,直接从 `app/build.gradle` 删依赖,无代码改动。 + +### 6. Gpu-Image 原生库 + +- 将 `Gpu-Image/libs//libgpuimage-library.so` 迁移到 `Gpu-Image/src/main/jniLibs//`(或在 build.gradle 配 `sourceSets.main.jniLibs.srcDirs`)。 +- 裁剪废弃 ABI:删除 `armeabi`、`mips`、`mips64`;保留 `arm64-v8a`、`armeabi-v7a`、`x86`、`x86_64`。 +- 非标准 sourceSets(`src/`、`res/`)归位到 AGP 8 标准布局或显式声明 `sourceSets`;加 `namespace`,删 manifest 的 `package`。 + +### 7. 依赖坐标与版本映射 + +| 旧 | 新 | +|---|---| +| `com.android.support:appcompat-v7:22.2.0` | `androidx.appcompat:appcompat:1.6.1` | +| `com.android.support:recyclerview-v7:22.2.0` | `androidx.recyclerview:recyclerview:1.3.2` | +| `com.android.support:cardview-v7:22.2.0` | `androidx.cardview:cardview:1.0.0` | +| (新增) | `com.google.android.material:material:1.11.0` | +| `com.jakewharton:butterknife:6.1.0` | `com.jakewharton:butterknife:10.2.3` + compiler | +| `de.greenrobot:eventbus:2.4.0` | `org.greenrobot:eventbus:3.3.1` | +| `files('libs/fastjson-1.2.5.jar')` | `com.alibaba:fastjson:1.2.83` | +| `files('universal-image-loader-1.9.4.jar')` | `com.nostra13.universalimageloader:universal-image-loader:1.9.5` | +| `systembartint` / melnykov FAB / MaterialEditText / hlistview | 移除 | + +> 上述 androidx/material 版本为兼容 minSdk 26 的稳定版;实现时若 AGP 8.11 要求更高的某传递依赖版本,以 Gradle 实际解析为准做最小上调。 + +### 8. targetSdk 36 的 edge-to-edge 适配 + +targetSdk ≥ 35 在 Android 15+/16 设备上强制 edge-to-edge,内容会延伸到系统栏后方。需: + +- 在 `BaseActivity` 启用 `WindowCompat.setDecorFitsSystemWindows(window, false)` 并对内容根视图应用 `systemBars()` insets 作为 padding,避免标题栏/按钮被状态栏或导航栏遮挡。 +- 全屏相机/裁剪预览(已是 FullScreen 主题)按需对覆盖控件(快门、返回等)应用 insets。 +- 该适配与第 5 步 systembartint 的移除合并处理。 + +## 风险与缓解 + +1. **ButterKnife 10.2.3 + AGP 8 / Java 17 注解处理兼容性(最高风险)**:这是已知痛点。用户选择保留 ButterKnife,先按此实施;若构建无法通过,**回退方案为改用 ViewBinding**(届时再与用户确认,涉及各 Activity 注入代码改写)。 +2. **edge-to-edge 遮挡**:targetSdk 36 下界面可能被系统栏遮挡,需逐界面验证 insets。 +3. **HListView → RecyclerView 行为差异**:滤镜/贴纸工具条滚动与点击需实机回归。 +4. **依赖解析**:个别旧坐标在 mavenCentral 的可用性与传递依赖版本冲突,以 Gradle 解析报错为准逐个修正。 +5. **原生库加载**:ABI 裁剪后需在真机(arm64)与模拟器(x86_64)各验证一次滤镜功能,确保 `.so` 正确打包加载。 + +## 验证标准 + +- `./gradlew clean assembleDebug` 构建成功产出 APK。 +- (可选)`./gradlew installDebug` 后实机/模拟器走通主流程:拍照 → 裁剪 → 滤镜 → 贴纸 → 标签 → 保存 → 主界面展示。 +- GPU 滤镜实际生效(验证 `.so` 加载)。 +- 各界面无被系统栏遮挡的可见问题。 From f03eb482bb64d66ee10b022d8f03f36de75abcb1 Mon Sep 17 00:00:00 2001 From: SkyKai <1132234509@qq.com> Date: Thu, 18 Jun 2026 18:39:47 +0800 Subject: [PATCH 03/16] =?UTF-8?q?docs:=20=E7=BC=96=E8=AF=91=E9=93=BE?= =?UTF-8?q?=E7=8E=B0=E4=BB=A3=E5=8C=96=E5=AE=9E=E7=8E=B0=E8=AE=A1=E5=88=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 12 个任务的逐步执行计划,含完整代码与构建/grep 验证门。 Co-Authored-By: Claude Opus 4.8 (1M context) --- ...026-06-18-build-toolchain-modernization.md | 927 ++++++++++++++++++ 1 file changed, 927 insertions(+) create mode 100644 docs/superpowers/plans/2026-06-18-build-toolchain-modernization.md diff --git a/docs/superpowers/plans/2026-06-18-build-toolchain-modernization.md b/docs/superpowers/plans/2026-06-18-build-toolchain-modernization.md new file mode 100644 index 0000000..0049ea0 --- /dev/null +++ b/docs/superpowers/plans/2026-06-18-build-toolchain-modernization.md @@ -0,0 +1,927 @@ +# StickerCamera 编译链现代化 Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** 把 StickerCamera 的编译链升级到 AGP 8.11 / Gradle 8.13 / JDK 17 / AndroidX,在现代开发机上构建通过并保持原有功能。 + +**Architecture:** 先升级构建系统骨架(wrapper/根/settings/properties),再逐模块(两个 library 可独立验证),最后迁移 :app 源码(AndroidX、ButterKnife、EventBus、死库替换、edge-to-edge),以 `assembleDebug` + 模拟器冒烟为终点验证。 + +**Tech Stack:** Android Gradle Plugin 8.11.x, Gradle 8.13, JDK 17, AndroidX(appcompat/recyclerview/cardview/core/fragment/viewpager/swiperefreshlayout), Material Components, ButterKnife 10.2.3, EventBus 3.3.1, GPUImage(prebuilt .so)。 + +## Global Constraints + +- JDK 运行版本:17;Java source/target:17(移除 Retrolambda)。 +- Gradle:8.13;AGP:8.11.1(以"能稳定支持 compileSdk 36 的最近 AGP 8.11+ / 配套 Gradle"为准)。 +- compileSdk = 36;targetSdk = 36;minSdk = 26。 +- 仓库:仅 `google()` + `mavenCentral()`(+ pluginManagement 加 `gradlePluginPortal()`);禁止 `jcenter()`。 +- AndroidX:`android.useAndroidX=true`;为降低旧工程风险 `android.nonTransitiveRClass=false`(保留传递 R,避免跨模块 R 引用断裂)。 +- 各模块必须声明 `namespace`,并从对应 `AndroidManifest.xml` 删除 `package=`。 +- 依赖配置用 `implementation`/`api`,不用已废弃的 `compile`。 +- 死库一律移除:`systembartint`、melnykov `floatingactionbutton`、rengwuxian `materialedittext`、sephiroth `hlistview`。 +- 模块 namespace:`:app`=`com.github.skykai.stickercamera`,`:Gpu-Image`=`jp.co.cyberagent.android.gpuimage`,`:ImageViewTouch`=`com.imagezoom`。 + +> 说明:本工程无单元测试,"测试周期"为构建/grep 验证。:app 源码在全部迁移完成前无法编译,因此 Task 5–10 的验证用定向 grep/检视,首个完整构建绿灯在 Task 11。 + +--- + +### Task 1: 构建系统骨架 + +**Files:** +- Modify: `gradle/wrapper/gradle-wrapper.properties` +- Modify: `build.gradle`(根) +- Modify: `settings.gradle` +- Modify: `gradle.properties` +- Create: `local.properties`(不入 git) + +- [ ] **Step 1: 升级 Gradle wrapper** + +`gradle/wrapper/gradle-wrapper.properties` 的 `distributionUrl` 改为: + +``` +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip +``` + +- [ ] **Step 2: 重写根 `build.gradle`** + +```gradle +buildscript { + repositories { + google() + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:8.11.1' + } +} +``` + +(删除 retrolambda classpath、`allprojects {}` 与所有 `jcenter()`。) + +- [ ] **Step 3: 重写 `settings.gradle`** + +```gradle +pluginManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} +dependencyResolutionManagement { + repositories { + google() + mavenCentral() + } +} +rootProject.name = "StickerCamera" +include ':app', ':Gpu-Image', ':ImageViewTouch' +``` + +- [ ] **Step 4: 更新 `gradle.properties`** + +追加: + +``` +android.useAndroidX=true +android.nonTransitiveRClass=false +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +``` + +- [ ] **Step 5: 写 `local.properties`** + +``` +sdk.dir=/Users/skykai/Library/Android/sdk +``` + +- [ ] **Step 6: 验证 Gradle/AGP 起得来** + +Run: `JAVA_HOME=$(/usr/libexec/java_home -v 17) ./gradlew --version` +Expected: `Gradle 8.13` + +Run: `JAVA_HOME=$(/usr/libexec/java_home -v 17) ./gradlew projects` +Expected: 列出 `:app`、`:Gpu-Image`、`:ImageViewTouch`,无 jcenter/AGP 报错(模块自身配置报错下一步处理)。 + +- [ ] **Step 7: Commit** + +```bash +git add gradle/wrapper/gradle-wrapper.properties build.gradle settings.gradle gradle.properties +git commit -m "build: 升级 Gradle 8.13 + AGP 8.11 骨架,仓库切换到 google/mavenCentral" +``` + +--- + +### Task 2: ImageViewTouch library 模块 + +**Files:** +- Modify: `ImageViewTouch/build.gradle` +- Modify: `ImageViewTouch/AndroidManifest.xml` + +**Interfaces:** +- Produces: AndroidX 版 `com.imagezoom.ImageViewTouch`(供 :app 使用,API 不变)。 + +- [ ] **Step 1: 重写 `ImageViewTouch/build.gradle`** + +```gradle +apply plugin: 'com.android.library' + +android { + namespace 'com.imagezoom' + compileSdk 36 + + defaultConfig { + minSdk 26 + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + + lint { + abortOnError false + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'androidx.appcompat:appcompat:1.7.0' +} +``` + +- [ ] **Step 2: 精简 `ImageViewTouch/AndroidManifest.xml`** + +```xml + + + +``` + +(删除 `package=` 与 `` 块,namespace 已提供包名,避免 library label 合并问题。) + +- [ ] **Step 3: 验证模块独立编译** + +Run: `JAVA_HOME=$(/usr/libexec/java_home -v 17) ./gradlew :ImageViewTouch:assembleDebug` +Expected: `BUILD SUCCESSFUL` + +- [ ] **Step 4: Commit** + +```bash +git add ImageViewTouch/build.gradle ImageViewTouch/AndroidManifest.xml +git commit -m "build(ImageViewTouch): AGP 8 + AndroidX + namespace" +``` + +--- + +### Task 3: Gpu-Image library 模块(含 .so 迁移) + +**Files:** +- Modify: `Gpu-Image/build.gradle` +- Modify: `Gpu-Image/AndroidManifest.xml` +- Delete: `Gpu-Image/libs/armeabi/`、`Gpu-Image/libs/mips/`、`Gpu-Image/libs/mips64/` + +**Interfaces:** +- Produces: AndroidX 版 `jp.co.cyberagent.android.gpuimage.*`(GPUImageView/GPUImageFilter 等,API 不变);`.so` 通过 `jniLibs.srcDirs=['libs']` 打包。 + +- [ ] **Step 1: 删除废弃 ABI** + +```bash +git rm -r Gpu-Image/libs/armeabi Gpu-Image/libs/mips Gpu-Image/libs/mips64 +``` + +保留:`arm64-v8a`、`armeabi-v7a`、`x86`、`x86_64`。 + +- [ ] **Step 2: 重写 `Gpu-Image/build.gradle`** + +```gradle +apply plugin: 'com.android.library' + +android { + namespace 'jp.co.cyberagent.android.gpuimage' + compileSdk 36 + + defaultConfig { + minSdk 26 + } + + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + java.srcDirs = ['src'] + res.srcDirs = ['res'] + assets.srcDirs = ['assets'] + jniLibs.srcDirs = ['libs'] + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + + lint { + abortOnError false + } +} +``` + +(沿用非标准 `src/`/`res/` 布局;把原 `jni.srcDirs`/`renderscript`/`aidl` 去掉——本模块只有预编译 `.so`,无 native/rs/aidl 源;`.so` 用 `jniLibs.srcDirs=['libs']` 打包。) + +- [ ] **Step 3: 清理 `Gpu-Image/AndroidManifest.xml`** + +```xml + + + +``` + +(删除 `package=`。) + +- [ ] **Step 4: 验证模块独立编译且打包 .so** + +Run: `JAVA_HOME=$(/usr/libexec/java_home -v 17) ./gradlew :Gpu-Image:assembleDebug` +Expected: `BUILD SUCCESSFUL` + +Run: `unzip -l Gpu-Image/build/outputs/aar/Gpu-Image-debug.aar | grep '\.so'` +Expected: 仅列出 `arm64-v8a`、`armeabi-v7a`、`x86`、`x86_64` 下的 `libgpuimage-library.so` + +- [ ] **Step 5: Commit** + +```bash +git add Gpu-Image/build.gradle Gpu-Image/AndroidManifest.xml Gpu-Image/libs +git commit -m "build(Gpu-Image): AGP 8 + namespace, .so 迁 jniLibs 并裁废弃 ABI" +``` + +--- + +### Task 4: :app 构建脚本与依赖映射 + +**Files:** +- Modify: `app/build.gradle` +- Modify: `app/src/main/AndroidManifest.xml` +- Delete: `app/libs/fastjson-1.2.5.jar`、`app/libs/universal-image-loader-1.9.4.jar` + +> 本任务后 :app 仍无法编译(源码未迁移),验证仅到"配置可解析"。 + +- [ ] **Step 1: 删除被坐标替换的本地 jar** + +```bash +git rm app/libs/fastjson-1.2.5.jar app/libs/universal-image-loader-1.9.4.jar +``` + +- [ ] **Step 2: 重写 `app/build.gradle`** + +```gradle +apply plugin: 'com.android.application' + +android { + namespace 'com.github.skykai.stickercamera' + compileSdk 36 + + defaultConfig { + applicationId "com.github.skykai.stickercamera" + minSdk 26 + targetSdk 36 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } +} + +dependencies { + implementation 'androidx.appcompat:appcompat:1.7.0' + implementation 'androidx.recyclerview:recyclerview:1.3.2' + implementation 'androidx.cardview:cardview:1.0.0' + implementation 'androidx.core:core:1.13.1' + implementation 'androidx.fragment:fragment:1.8.5' + implementation 'androidx.viewpager:viewpager:1.0.0' + implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' + implementation 'com.google.android.material:material:1.12.0' + implementation 'com.jakewharton:butterknife:10.2.3' + annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.3' + implementation 'com.alibaba:fastjson:1.2.83' + implementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.5' + implementation 'org.greenrobot:eventbus:3.3.1' + implementation project(':Gpu-Image') + implementation project(':ImageViewTouch') +} +``` + +- [ ] **Step 3: 删除 manifest 的 `package`** + +`app/src/main/AndroidManifest.xml` 的 `` 删去 `package="com.github.skykai.stickercamera"`,其余(权限、application、activity 全限定名)不变。 + +- [ ] **Step 4: 验证配置解析** + +Run: `JAVA_HOME=$(/usr/libexec/java_home -v 17) ./gradlew :app:dependencies --configuration debugRuntimeClasspath` +Expected: 依赖树解析成功(出现 androidx/material/eventbus/fastjson),无"Could not resolve"。 + +- [ ] **Step 5: Commit** + +```bash +git add app/build.gradle app/src/main/AndroidManifest.xml app/libs +git commit -m "build(app): AGP 8 依赖映射到 AndroidX/Material,移除死库与本地 jar" +``` + +--- + +### Task 5: :app AndroidX 源码迁移 + +**Files(java,8 个):** +- Modify: `app/src/main/java/com/stickercamera/base/BaseActivity.java:8` +- Modify: `app/src/main/java/com/stickercamera/base/BaseFragmentActivity.java:3` +- Modify: `app/src/main/java/com/stickercamera/app/ui/MainActivity.java:4-9` +- Modify: `app/src/main/java/com/stickercamera/app/camera/ui/AlbumActivity.java:5-8` +- Modify: `app/src/main/java/com/stickercamera/app/camera/fragment/AlbumFragment.java:4` +- Modify: `app/src/main/java/com/stickercamera/app/camera/ui/PhotoProcessActivity.java:12` +- Modify: `app/src/main/java/com/customview/PagerSlidingTabStrip.java:29-30` + +**Files(xml):** 含 `android.support.*` 标签的布局(用 grep 定位,通常 `activity_main.xml`、`activity_album.xml`、`item_picture.xml`)。 + +- [ ] **Step 1: 替换 java import(按下表逐项全局替换)** + +| 旧 | 新 | +|---|---| +| `android.support.v7.app.AppCompatActivity` | `androidx.appcompat.app.AppCompatActivity` | +| `android.support.v4.app.Fragment` | `androidx.fragment.app.Fragment` | +| `android.support.v4.app.FragmentActivity` | `androidx.fragment.app.FragmentActivity` | +| `android.support.v4.app.FragmentManager` | `androidx.fragment.app.FragmentManager` | +| `android.support.v4.app.FragmentPagerAdapter` | `androidx.fragment.app.FragmentPagerAdapter` | +| `android.support.v4.view.ViewPager` | `androidx.viewpager.widget.ViewPager` | +| `android.support.v4.view.ViewPager.OnPageChangeListener` | `androidx.viewpager.widget.ViewPager.OnPageChangeListener` | +| `android.support.v4.widget.SwipeRefreshLayout` | `androidx.swiperefreshlayout.widget.SwipeRefreshLayout` | +| `android.support.v7.widget.RecyclerView` | `androidx.recyclerview.widget.RecyclerView` | +| `android.support.v7.widget.LinearLayoutManager` | `androidx.recyclerview.widget.LinearLayoutManager` | +| `android.support.v7.widget.CardView` | `androidx.cardview.widget.CardView` | +| `android.support.annotation.Nullable` | `androidx.annotation.Nullable` | + +可用: + +```bash +cd app/src/main/java +grep -rl "android.support" . | while read f; do + sed -i '' \ + -e 's#android\.support\.v7\.app\.AppCompatActivity#androidx.appcompat.app.AppCompatActivity#g' \ + -e 's#android\.support\.v4\.app\.FragmentPagerAdapter#androidx.fragment.app.FragmentPagerAdapter#g' \ + -e 's#android\.support\.v4\.app\.FragmentActivity#androidx.fragment.app.FragmentActivity#g' \ + -e 's#android\.support\.v4\.app\.FragmentManager#androidx.fragment.app.FragmentManager#g' \ + -e 's#android\.support\.v4\.app\.Fragment#androidx.fragment.app.Fragment#g' \ + -e 's#android\.support\.v4\.view\.ViewPager#androidx.viewpager.widget.ViewPager#g' \ + -e 's#android\.support\.v4\.widget\.SwipeRefreshLayout#androidx.swiperefreshlayout.widget.SwipeRefreshLayout#g' \ + -e 's#android\.support\.v7\.widget\.RecyclerView#androidx.recyclerview.widget.RecyclerView#g' \ + -e 's#android\.support\.v7\.widget\.LinearLayoutManager#androidx.recyclerview.widget.LinearLayoutManager#g' \ + -e 's#android\.support\.v7\.widget\.CardView#androidx.cardview.widget.CardView#g' \ + -e 's#android\.support\.annotation\.Nullable#androidx.annotation.Nullable#g' \ + "$f" +done +``` + +- [ ] **Step 2: 替换 xml 中的全限定 support 标签** + +```bash +cd app/src/main/res +grep -rl "android.support" . | while read f; do + sed -i '' \ + -e 's#android\.support\.v4\.view\.ViewPager#androidx.viewpager.widget.ViewPager#g' \ + -e 's#android\.support\.v7\.widget\.RecyclerView#androidx.recyclerview.widget.RecyclerView#g' \ + -e 's#android\.support\.v7\.widget\.CardView#androidx.cardview.widget.CardView#g' \ + "$f" +done +``` + +- [ ] **Step 3: 验证无残留** + +Run: `grep -rn "android.support" app/src && echo "STILL HAS SUPPORT" || echo "CLEAN"` +Expected: `CLEAN` + +- [ ] **Step 4: Commit** + +```bash +git add app/src +git commit -m "refactor(app): android.support.* 全量迁移到 androidx" +``` + +--- + +### Task 6: :app ButterKnife 6 → 10 + +**Files(6 个含注解):** `EditTextActivity.java`、`MainActivity.java`、`AlbumActivity.java`、`CameraActivity.java`、`CropPhotoActivity.java`、`PhotoProcessActivity.java`(`BaseActivity.java` 仅有一行无用 `import butterknife.ButterKnife` 可一并删)。 + +- [ ] **Step 1: 注解与调用改名** + +```bash +cd app/src/main/java +grep -rl "InjectView\|ButterKnife" . | while read f; do + sed -i '' \ + -e 's#import butterknife\.InjectView;#import butterknife.BindView;#g' \ + -e 's#@InjectView#@BindView#g' \ + -e 's#ButterKnife\.inject(#ButterKnife.bind(#g' \ + "$f" +done +``` + +(若某文件同时有 `@OnClick` 等其它 ButterKnife 注解,10.x API 兼容,无需改;仅 `@InjectView`→`@BindView`、`inject`→`bind` 有变。) + +- [ ] **Step 2: 删除 BaseActivity 无用 import** + +`app/src/main/java/com/stickercamera/base/BaseActivity.java` 删除 `import butterknife.ButterKnife;`(该类不调用 ButterKnife)。 + +- [ ] **Step 3: 验证无残留旧 API** + +Run: `grep -rn "InjectView\|ButterKnife.inject" app/src && echo "STILL OLD" || echo "CLEAN"` +Expected: `CLEAN` + +- [ ] **Step 4: Commit** + +```bash +git add app/src +git commit -m "refactor(app): ButterKnife 6 -> 10 (@BindView/bind)" +``` + +--- + +### Task 7: :app EventBus 2 → 3 + +**Files:** `MainActivity.java`、`PhotoProcessActivity.java` + +- [ ] **Step 1: 改包名 import** + +两文件:`import de.greenrobot.event.EventBus;` → `import org.greenrobot.eventbus.EventBus;` +`MainActivity.java` 另加:`import org.greenrobot.eventbus.Subscribe;` 和 `import org.greenrobot.eventbus.ThreadMode;` + +- [ ] **Step 2: 注解订阅方法(MainActivity)** + +`MainActivity.java` 中: + +```java +public void onEventMainThread(FeedItem feedItem) { +``` + +改为: + +```java +@Subscribe(threadMode = ThreadMode.MAIN) +public void onEvent(FeedItem feedItem) { +``` + +(`register`/`unregister`/`post` API 在 3.x 不变,无需改。) + +- [ ] **Step 3: 验证无残留旧包** + +Run: `grep -rn "de.greenrobot" app/src && echo "STILL OLD" || echo "CLEAN"` +Expected: `CLEAN` + +- [ ] **Step 4: Commit** + +```bash +git add app/src +git commit -m "refactor(app): EventBus 2.4 -> 3.3.1 (@Subscribe)" +``` + +--- + +### Task 8: melnykov FAB → Material FAB + +**Files:** `app/src/main/res/layout/activity_main.xml`、`app/src/main/java/com/stickercamera/app/ui/MainActivity.java` + +- [ ] **Step 1: 替换布局中的 FAB** + +`activity_main.xml` 把 `com.melnykov.fab.FloatingActionButton` 节点整体替换为: + +```xml + +``` + +- [ ] **Step 2: 替换 MainActivity import** + +`MainActivity.java`:`import com.melnykov.fab.FloatingActionButton;` → `import com.google.android.material.floatingactionbutton.FloatingActionButton;` +(字段 `FloatingActionButton fab;` 与 `fab.setOnClickListener(...)` 不变。) + +- [ ] **Step 3: 验证无残留** + +Run: `grep -rn "melnykov" app/src && echo "STILL OLD" || echo "CLEAN"` +Expected: `CLEAN` + +- [ ] **Step 4: Commit** + +```bash +git add app/src +git commit -m "refactor(app): melnykov FAB -> Material FloatingActionButton" +``` + +--- + +### Task 9: sephiroth HListView → 水平 RecyclerView + +**Files:** +- Modify: `app/src/main/res/layout/activity_image_process.xml` +- Modify: `app/src/main/java/com/stickercamera/app/camera/ui/PhotoProcessActivity.java` +- Rewrite: `app/src/main/java/com/stickercamera/app/camera/adapter/FilterAdapter.java` +- Rewrite: `app/src/main/java/com/stickercamera/app/camera/adapter/StickerToolAdapter.java` + +**Interfaces:** +- Produces: `FilterAdapter` / `StickerToolAdapter` 提供 `setOnItemClickListener(OnItemClickListener)`,回调签名 `void onItemClick(int position)`;`FilterAdapter` 保留 `getSelectFilter()`/`setSelectFilter(int)`。 + +> 观感微调:放弃 `hlv_dividerWidth` 的 15px 分隔(功能优先,可接受)。 + +- [ ] **Step 1: 布局替换** + +`activity_image_process.xml` 把 `it.sephiroth.android.library.widget.HListView`(id `list_tools`)替换为: + +```xml + +``` + +(删除 `app:hlv_dividerWidth` 与 `android:gravity`。) + +- [ ] **Step 2: 重写 `FilterAdapter.java`** + +```java +package com.stickercamera.app.camera.adapter; + +import android.content.Context; +import android.graphics.Bitmap; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.github.skykai.stickercamera.R; +import com.stickercamera.app.camera.effect.FilterEffect; +import com.stickercamera.app.camera.util.GPUImageFilterTools; + +import java.util.List; + +import jp.co.cyberagent.android.gpuimage.GPUImageFilter; +import jp.co.cyberagent.android.gpuimage.GPUImageView; + +public class FilterAdapter extends RecyclerView.Adapter { + + public interface OnItemClickListener { + void onItemClick(int position); + } + + private final List filterUris; + private final Context mContext; + private final Bitmap background; + private int selectFilter = 0; + private OnItemClickListener onItemClickListener; + + public FilterAdapter(Context context, List effects, Bitmap background) { + this.mContext = context; + this.filterUris = effects; + this.background = background; + } + + public void setOnItemClickListener(OnItemClickListener l) { + this.onItemClickListener = l; + } + + public void setSelectFilter(int selectFilter) { + this.selectFilter = selectFilter; + } + + public int getSelectFilter() { + return selectFilter; + } + + public FilterEffect getItem(int position) { + return filterUris.get(position); + } + + @NonNull + @Override + public EffectHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View v = LayoutInflater.from(mContext).inflate(R.layout.item_bottom_filter, parent, false); + return new EffectHolder(v); + } + + @Override + public void onBindViewHolder(@NonNull EffectHolder holder, int position) { + final FilterEffect effect = getItem(position); + holder.filteredImg.setImage(background); + holder.filterName.setText(effect.getTitle()); + GPUImageFilter filter = GPUImageFilterTools.createFilterForType(mContext, effect.getType()); + holder.filteredImg.setFilter(filter); + holder.itemView.setOnClickListener(v -> { + if (onItemClickListener != null) { + onItemClickListener.onItemClick(holder.getAdapterPosition()); + } + }); + } + + @Override + public int getItemCount() { + return filterUris.size(); + } + + static class EffectHolder extends RecyclerView.ViewHolder { + GPUImageView filteredImg; + TextView filterName; + + EffectHolder(View itemView) { + super(itemView); + filteredImg = itemView.findViewById(R.id.small_filter); + filterName = itemView.findViewById(R.id.filter_name); + } + } +} +``` + +- [ ] **Step 3: 重写 `StickerToolAdapter.java`** + +```java +package com.stickercamera.app.camera.adapter; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.common.util.ImageLoaderUtils; +import com.github.skykai.stickercamera.R; +import com.stickercamera.app.model.Addon; + +import java.util.List; + +public class StickerToolAdapter extends RecyclerView.Adapter { + + public interface OnItemClickListener { + void onItemClick(int position); + } + + private final List filterUris; + private final Context mContext; + private OnItemClickListener onItemClickListener; + + public StickerToolAdapter(Context context, List effects) { + this.mContext = context; + this.filterUris = effects; + } + + public void setOnItemClickListener(OnItemClickListener l) { + this.onItemClickListener = l; + } + + public Addon getItem(int position) { + return filterUris.get(position); + } + + @NonNull + @Override + public EffectHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View v = LayoutInflater.from(mContext).inflate(R.layout.item_bottom_tool, parent, false); + return new EffectHolder(v); + } + + @Override + public void onBindViewHolder(@NonNull EffectHolder holder, int position) { + final Addon sticker = getItem(position); + holder.container.setVisibility(View.GONE); + ImageLoaderUtils.displayDrawableImage(sticker.getId() + "", holder.logo, null); + holder.itemView.setOnClickListener(v -> { + if (onItemClickListener != null) { + onItemClickListener.onItemClick(holder.getAdapterPosition()); + } + }); + } + + @Override + public int getItemCount() { + return filterUris.size(); + } + + static class EffectHolder extends RecyclerView.ViewHolder { + ImageView logo; + ImageView container; + + EffectHolder(View itemView) { + super(itemView); + logo = itemView.findViewById(R.id.effect_image); + container = itemView.findViewById(R.id.effect_background); + } + } +} +``` + +- [ ] **Step 4: 改 PhotoProcessActivity** + +字段与 import:删 `import it.sephiroth.android.library.widget.HListView;`,新增 `import androidx.recyclerview.widget.RecyclerView;` 和 `import androidx.recyclerview.widget.LinearLayoutManager;`(PhotoProcessActivity 原本用的是 HListView,Task 5 未给它引入 RecyclerView);字段 `@BindView(R.id.list_tools) HListView bottomToolBar;` 的类型 `HListView` → `RecyclerView`(注解不变)。同时删除文件里残留的 `import android.widget.GridView;` 若未被使用(由编译器报未用 import 时清理,非必须)。 + +`initStickerToolBar()` 改为: + +```java +private void initStickerToolBar() { + bottomToolBar.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)); + StickerToolAdapter adapter = new StickerToolAdapter(PhotoProcessActivity.this, EffectUtil.addonList); + adapter.setOnItemClickListener(position -> { + labelSelector.hide(); + Addon sticker = EffectUtil.addonList.get(position); + EffectUtil.addStickerImage(mImageView, PhotoProcessActivity.this, sticker, + new EffectUtil.StickerCallback() { + @Override + public void onRemoveSticker(Addon sticker) { + labelSelector.hide(); + } + }); + }); + bottomToolBar.setAdapter(adapter); + setCurrentBtn(stickerBtn); +} +``` + +`initFilterToolBar()` 改为: + +```java +private void initFilterToolBar() { + final List filters = EffectService.getInst().getLocalFilters(); + bottomToolBar.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)); + final FilterAdapter adapter = new FilterAdapter(PhotoProcessActivity.this, filters, smallImageBackgroud); + adapter.setOnItemClickListener(position -> { + labelSelector.hide(); + if (adapter.getSelectFilter() != position) { + adapter.setSelectFilter(position); + GPUImageFilter filter = GPUImageFilterTools.createFilterForType( + PhotoProcessActivity.this, filters.get(position).getType()); + mGPUImageView.setFilter(filter); + GPUImageFilterTools.FilterAdjuster mFilterAdjuster = new GPUImageFilterTools.FilterAdjuster(filter); + if (mFilterAdjuster.canAdjust()) { + //mFilterAdjuster.adjust(100); + } + } + }); + bottomToolBar.setAdapter(adapter); +} +``` + +- [ ] **Step 5: 验证无残留** + +Run: `grep -rn "sephiroth\|HListView" app/src && echo "STILL OLD" || echo "CLEAN"` +Expected: `CLEAN` + +- [ ] **Step 6: Commit** + +```bash +git add app/src +git commit -m "refactor(app): HListView -> 水平 RecyclerView,适配器改 RecyclerView.Adapter" +``` + +--- + +### Task 10: systembartint 移除 + edge-to-edge 适配 + +**Files:** `app/src/main/java/com/stickercamera/base/BaseActivity.java` + +- [ ] **Step 1: 重写 BaseActivity 的窗口/状态栏处理** + +删除 import:`android.annotation.TargetApi`、`android.os.Build`、`android.util.TypedValue`、`android.view.WindowManager`、`com.readystatesoftware.systembartint.SystemBarTintManager`。 +新增 import(`android.view.View` 原文件已有,勿重复): + +```java +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowCompat; +import androidx.core.view.WindowInsetsCompat; +``` + +`onCreate` 里把 `initWindow();` 保留;`initWindow()` 改为: + +```java +private void initWindow() { + WindowCompat.setDecorFitsSystemWindows(getWindow(), false); +} +``` + +删除 `getStatusBarColor()` 方法(原仅供 tint 使用);`getColorPrimary()` 保留。 + +`setContentView(int)` 改为(在 super 之后、titleBar 绑定之前插入 inset 处理): + +```java +@Override +public void setContentView(int layoutResID) { + super.setContentView(layoutResID); + final View content = findViewById(android.R.id.content); + if (content != null) { + ViewCompat.setOnApplyWindowInsetsListener(content, (v, insets) -> { + Insets bars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); + v.setPadding(bars.left, bars.top, bars.right, bars.bottom); + return insets; + }); + } + titleBar = (CommonTitleBar) findViewById(R.id.title_layout); + if (titleBar != null) + titleBar.setLeftBtnOnclickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); +} +``` + +- [ ] **Step 2: 验证无残留** + +Run: `grep -rn "systembartint\|SystemBarTint" app/src && echo "STILL OLD" || echo "CLEAN"` +Expected: `CLEAN` + +- [ ] **Step 3: Commit** + +```bash +git add app/src +git commit -m "refactor(app): 移除 systembartint,改 edge-to-edge + WindowInsets 适配" +``` + +--- + +### Task 11: 全量构建绿灯 + +- [ ] **Step 1: clean + assembleDebug** + +Run: `JAVA_HOME=$(/usr/libexec/java_home -v 17) ./gradlew clean assembleDebug` +Expected: `BUILD SUCCESSFUL`,产出 `app/build/outputs/apk/debug/app-debug.apk` + +- [ ] **Step 2: 迭代修编译错误** + +若有报错(常见:遗漏的 import、ButterKnife 与 AGP 8 注解处理冲突、个别 androidx 类名),逐个修复后重跑 Step 1。 +**ButterKnife 兜底:** 若 ButterKnife 10.2.3 与 AGP 8/Java 17 注解处理无法通过,停止并与用户确认改用 ViewBinding(见 spec 风险 1),不要私自大改。 + +- [ ] **Step 3: Commit(若有修复)** + +```bash +git add -A +git commit -m "fix: 修复 AGP 8 全量构建编译问题" +``` + +--- + +### Task 12: 模拟器冒烟测试 + +- [ ] **Step 1: 启动模拟器并安装** + +```bash +adb devices +JAVA_HOME=$(/usr/libexec/java_home -v 17) ./gradlew installDebug +adb shell am start -n com.github.skykai.stickercamera/com.stickercamera.app.ui.MainActivity +``` + +- [ ] **Step 2: 走主流程并观察** + +拍照 → 裁剪 → 进入图片处理 → 切滤镜(验证 GPU `.so` 加载、滤镜生效)→ 加贴纸(工具条横向滚动+点击)→ 加标签 → 保存 → 返回主界面展示。 +用 `adb logcat` 观察有无崩溃 / `UnsatisfiedLinkError`(.so)/ inset 遮挡。 + +- [ ] **Step 3: 修正 edge-to-edge 遮挡(如有)** + +若某全屏界面(相机/裁剪/处理)控件被状态栏或导航栏遮挡或留白异常,针对该界面根布局微调 inset 应用(只动受影响界面)。重装验证。 + +- [ ] **Step 4: Commit(若有修复)** + +```bash +git add -A +git commit -m "fix: 模拟器冒烟回归修正" +``` + +--- + +## 验收标准 + +- `./gradlew clean assembleDebug` 成功产出 APK。 +- 模拟器主流程跑通,GPU 滤镜生效,无崩溃。 +- `grep -rn "android.support\|de.greenrobot\|sephiroth\|melnykov\|systembartint\|InjectView" app/src` 为空。 +- 全程在 `modernize-build-toolchain` 分支。 From 98a102b2c9e321654cb05b7a558caf9a9caa156b Mon Sep 17 00:00:00 2001 From: SkyKai <1132234509@qq.com> Date: Thu, 18 Jun 2026 18:41:57 +0800 Subject: [PATCH 04/16] =?UTF-8?q?build:=20=E5=8D=87=E7=BA=A7=20Gradle=208.?= =?UTF-8?q?13=20+=20AGP=208.11=20=E9=AA=A8=E6=9E=B6,=E4=BB=93=E5=BA=93?= =?UTF-8?q?=E5=88=87=E6=8D=A2=E5=88=B0=20google/mavenCentral?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 16 +++------------- gradle.properties | 6 +++++- gradle/wrapper/gradle-wrapper.properties | 2 +- settings.gradle | 14 ++++++++++++++ 4 files changed, 23 insertions(+), 15 deletions(-) diff --git a/build.gradle b/build.gradle index 6b77860..7ac1d6d 100644 --- a/build.gradle +++ b/build.gradle @@ -2,23 +2,13 @@ buildscript { repositories { - jcenter() - + google() + mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:1.2.3' - classpath 'me.tatarka:gradle-retrolambda:3.1.0' + classpath 'com.android.tools.build:gradle:8.11.1' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } - - -} - -allprojects { - repositories { - jcenter() - maven { url("https://oss.sonatype.org/content/repositories/snapshots/") } - } } diff --git a/gradle.properties b/gradle.properties index 1d3591c..7103d64 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,4 +15,8 @@ # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true \ No newline at end of file +# org.gradle.parallel=true + +android.useAndroidX=true +android.nonTransitiveRClass=false +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 5ee4adf..e16eca7 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip diff --git a/settings.gradle b/settings.gradle index 6d6a821..28f9a1b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,15 @@ +pluginManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} +dependencyResolutionManagement { + repositories { + google() + mavenCentral() + } +} +rootProject.name = "StickerCamera" include ':app', ':Gpu-Image', ':ImageViewTouch' From 4579aa397ce170b83186007755d0d7bf570ae270 Mon Sep 17 00:00:00 2001 From: SkyKai <1132234509@qq.com> Date: Thu, 18 Jun 2026 18:45:20 +0800 Subject: [PATCH 05/16] build(ImageViewTouch): AGP 8 + AndroidX + namespace --- Gpu-Image/libs/armeabi/libgpuimage-library.so | Bin 13404 -> 0 bytes Gpu-Image/libs/mips/libgpuimage-library.so | Bin 5392 -> 0 bytes Gpu-Image/libs/mips64/libgpuimage-library.so | Bin 5912 -> 0 bytes ImageViewTouch/build.gradle | 22 +++++++++++------- ImageViewTouch/src/main/AndroidManifest.xml | 8 ++----- app/libs/fastjson-1.2.5.jar | Bin 411161 -> 0 bytes app/libs/universal-image-loader-1.9.4.jar | Bin 160341 -> 0 bytes 7 files changed, 16 insertions(+), 14 deletions(-) delete mode 100755 Gpu-Image/libs/armeabi/libgpuimage-library.so delete mode 100755 Gpu-Image/libs/mips/libgpuimage-library.so delete mode 100755 Gpu-Image/libs/mips64/libgpuimage-library.so delete mode 100644 app/libs/fastjson-1.2.5.jar delete mode 100644 app/libs/universal-image-loader-1.9.4.jar diff --git a/Gpu-Image/libs/armeabi/libgpuimage-library.so b/Gpu-Image/libs/armeabi/libgpuimage-library.so deleted file mode 100755 index 65a3f12c5f079c7e403dd50b3c72c3eb8fae1bbc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13404 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 diff --git a/Gpu-Image/libs/mips/libgpuimage-library.so b/Gpu-Image/libs/mips/libgpuimage-library.so deleted file mode 100755 index 81c52ef1d3e6db3de06e2116d759703707147767..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5392 zcmeHLeQaA-6+h3fSsi{QMJ+m^N|d;4f!}Jbu6D zcQZE|2oQf&J@WB6_nzN5_v_sI-hIbEcIU@6O%p}B1cjy4I+1b6mCYjSBQiBEG3l4M z+#p*-7qJfkq&Ny387}bl$hKiu+-oO>@q4M$FGB9~DmBl3VWY@}jhe>?;BYti8s8p( zY{A}wog9OW%-H0q-#OVS#8W(gIrIT5xF9c)7x{6T1n#9?bSQ=NPVFN+b;CIJ$EQWeuhL4(jlp zgRKQ{3PG2`nx~;}r0eA^cQe%Fsy*UCd&_SCr{YHt?-I)K9{l@IUPAk- zy@56H{&*RFlZ4mU`%vzUw-xv#2M)Rp%sGqol*OF2&1|7!i)l_*Epw(YZxsvo<@}=M ze)3Ry%rT9`wXxqIs19aQ#NPT}6%orO%< zDleFa4}RJy?Z18ZVX+rNxw4#Ri0q7hQ!>-ar>@VgU7u%DomaYk6hzEn=+HkfSlrJt!?t((k12XT)m~t$nc`^Zf^U{G0Bx zJ9f$QjdA&5BPr(^H_Hziae1mSEN2@r`F>+So@_+rdyNTst|9V;QwQW+eM-*OtNP(n z#^W_HYE3cX&47^Ed{Fj!YLyzo}D)1>69Fnd$t*;Q&OvL z79-gT7!xTmQt+Pw$3P?42XENlEq9 z+~7#f-8-_}92BEHsHe9==9l&5OOVm$wV_U4mh(Z_@{+cLl3EFgejeqOA>HV_sT=JV z^%Gk|V%Rt7MwE3OJ)I9pnwa)QoG=UVA>fu#7mA+I=p)*TW1;pUY?sDFs_{_gj24da z6n*;QNn)oF{Y+rRZQc;>JcHetubp=_@95$9&%2X-$0az@bR}|J_Ks-s z?O`MNl0502-C|6M9IZ;Or)Qw~+fSjls@MpfIwEa9_k0gP4j}%2>r4Nubae)< z&cM|fxDsbT-9zy3lBd9w&-wDFzI?@(zlP+2It-9Hqj|UB{c}4cuT0y(d>7_DlJ_mv zodljQJFnr~=AG*`lz9ia4KfVLSbW)y;N2P5XolJUr{~%bc(OQhMS2+RiLCU`5+1=*b zuInmT3W~DxZi~0|e`%lG1oQ0tQPI4cG+t*b`HE9^tc)b?x?}272`f{WDO$4?NtAQ5 zh54D1B=S}zFNy5Jd}U#-E1fdUMb=5eyNq?6E6&jjJac(-rfkjS%zPF=Rgy$uzJOb1 zxoj;+0vFSQ(h&`uRp?At z;&={SgcHZ7NX5G!6&x%3*Zn?*v7p18XA*Jr`!bm0U_9?b4kkj)g;&Kt(1Tzf7vVV; z0jM_*=);)b05dM*@taV*HyG+v@mtUtF9{|QH{Mmff7-~8`O>Sz-`&71sRE=L?-S7f ff-_K=-Ubf8Rbng>r8icugl}v(SbyZ}6bkoG7^ur- diff --git a/Gpu-Image/libs/mips64/libgpuimage-library.so b/Gpu-Image/libs/mips64/libgpuimage-library.so deleted file mode 100755 index 37590a25b3066cbe404ee559d49b162b52303edd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5912 zcmd5=eQaA-6+h2*leFtnx9f)cL1(KmyfB{SRBesdMGRQwD=~{T4bKgCQ z_u6Qa0ErX5obP+?$L~Jh`wp}}aGym{fXNC?AhagK5|ECG<%ZB`gMk3FVN?L_gq2_g z=&_N@A_Gm_AAMyCWV2yq4o0uU{|0nTNdH8$(Rb!)ITYrcN8O@+R%HLo z+$-(Oxu4;;O9{%e%X((M7JWp_#ay7i3-hR-AC~MgaJQ_t(D+n2KIT&Wuw~}rczghX z28%^bE_%5=MKwZu0M5)M)e99PlH+dZ`kQs`WplDAZq9BNI8NG6OV0gy*`&W}(l40w z*QG9(4c5qpc%G#jR!QN?G9zG()Oj6OOMP1Ud7YP<;;J%%G2JT{pD|#UjwLd0qwLRZ zQs@1F`$>@9ZUo3}2g8kqeTDRUCBH**9v5celFhFpmKC~$H(-B+F4F+}BXk}w))P7} zAl4H)j~nX={dU;^_nX_huIqV{0NZE6})IF60q8(SJg_ohr(8$dr_?zq6(N5T$W?-O9gv|*1l*tZ} zNM~;>(v|6sWi$JeQjL|8y_pj1h&>XEJlqrM%tt!=;>kiRmFzA>V%>>CK9h)~diG^< zXo_qL@426Z2V1>QNj=nA;!t>amm;+t<`GILnXE)lnCy(}VrfRHu^0 z{%nUI>Dn+TZSa!rg%@@0XcbgAqaUqY0VlkmYlo-60mHi17O)(KS7x+w8Om^O1}>cp z^}^X1%}Xz@kr@~}5sJdk^f3Hb55UVhK>uZc@9WbIeV1v>F!5XnH~OUJ1dFCdEtEIi zu0cBP@z`;A!k#uQq!Gx8R>!0OGAWB-}nn zT=A<1!R`m0D|FV5L}LV-dAy>pKo37{F*YVVqEkqs9#Y1>GO)Oqh@v6 zPb>ae{DsC=e9jA2cls@>U+u?N!w%IK9kse0KfwO%z&RLf1?W z8scdju{4f28b=I`&k`OG?-jWp>Tx=c&+@JDS+2rify?JYWyB?n5k5y|7?Xr^1D6L8 zmqUoly#kknLx2?G5;3WQ#N{;uvxrN4+t(6Mb_i?^AvVi|P1S_WyAYe}wrC?x#AX>7 zmjaWspt!1MK=Td=Tv9c}WqBT#Z+o>c<1&Z1jJy5Lo#1oi6t|-v@%PKbsND*|j1^q= zAmMW5br-z~KKGac?T-QcRp1fvsh0Jt?gMbVrK~^S;_JvNKJ^{NAN`f$4?m2!%qs5Q zQ`p8%7)=u{LlAT#E;|sDQGD!&6jwN>Y;HBM>FQ`#`d1+qqli7V9fG?s$9Y_F*-ydx zbXFO4;0Zx_LM7~gvQq`6z15Fx`y8)X{LUx97rkilhual*#}V+Qe_?T}LF{w3)$Q1c z7#&o7;Vkl;>gyP!v0{xcD$s)XjGn+BH!I>&Pr1Se5tlQB%jX3yhh8vnDSlYLB-V`Z zW?*vD%NGnHVr+01dl$Gi= zgCkL|-;TNwHUD2(W8M67TuBR>D(~s~6v}P?)b(iH9dSPT|5sWmyJp?L8HtVz3Z2L{rYcy`@1*BFHhD)cr%nR`xri#t{e6F zyf|N<+J9!rEecaND(j50M)k8cn*)s_4OI526#J(uLvwtgHB2wM^Kxst5rhuoI zE|v}KHvYDdu1Svk%;T_ z_-TC9CeP1YfDD}CL`p{DJVOI`2!;B5-tWx0KF4!?*5fjt`@hh4GmhtZXT3+}(;O1< z_dWhDX1YGl4bO-M*pC9;_c@=x?_8mMj%2Q9)*r_h3gvvhXHCm|`jx0B^Z1`cC(R${ z^Lvyh+C1N8{pftYaPjvbyA1T!7e|@%xgXy}8_8T>979kKa3IR{WHt|?llpJ2!};#| zWEo2)${{+956i+J|D|Q2fqEm#=J_8++dt&Dr25b%Jkk=G`)jU6I*(l>$bSx*U#&Ny HY|j5Tc7 - - - - - + + diff --git a/app/libs/fastjson-1.2.5.jar b/app/libs/fastjson-1.2.5.jar deleted file mode 100644 index d4a3f7d7cb4db233ce409a27418a5552a94b26df..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 411161 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
  • G}uMN%!)sE`4zT2AD?u5K7xu&ZPRQ1$#0OyQV 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

    -Pv2)Sz4;{|9HQr|7Pq#bqH%0 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 D*uaN> diff --git a/app/libs/universal-image-loader-1.9.4.jar b/app/libs/universal-image-loader-1.9.4.jar deleted file mode 100644 index 871d0e8f9ca271cfc8ed83752c519bdd8ef5b687..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 160341 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

    u>^hMXCx|Tu;|-*c;vvbu4ateru%bS|PRR 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 ADF6Tf From 2fe2e3cbe0ef904458f2cc52d6fef59fd478cf2e Mon Sep 17 00:00:00 2001 From: SkyKai <1132234509@qq.com> Date: Thu, 18 Jun 2026 18:45:20 +0800 Subject: [PATCH 06/16] =?UTF-8?q?build(Gpu-Image):=20AGP=208=20+=20namespa?= =?UTF-8?q?ce,=20.so=20=E8=BF=81=20jniLibs=20=E5=B9=B6=E8=A3=81=E5=BA=9F?= =?UTF-8?q?=E5=BC=83=20ABI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Gpu-Image/AndroidManifest.xml | 5 ++--- Gpu-Image/build.gradle | 27 ++++++++++----------------- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/Gpu-Image/AndroidManifest.xml b/Gpu-Image/AndroidManifest.xml index ee0e775..9a40236 100755 --- a/Gpu-Image/AndroidManifest.xml +++ b/Gpu-Image/AndroidManifest.xml @@ -1,4 +1,3 @@ - - \ No newline at end of file + + diff --git a/Gpu-Image/build.gradle b/Gpu-Image/build.gradle index fd9c608..9c3a172 100755 --- a/Gpu-Image/build.gradle +++ b/Gpu-Image/build.gradle @@ -1,16 +1,11 @@ apply plugin: 'com.android.library' android { - compileSdkVersion 22 - buildToolsVersion "22.0.1" + namespace 'jp.co.cyberagent.android.gpuimage' + compileSdk 36 defaultConfig { - minSdkVersion 15 - targetSdkVersion 22 - - versionCode = 1 - versionName = "1.0" - + minSdk 26 } sourceSets { @@ -18,18 +13,16 @@ android { manifest.srcFile 'AndroidManifest.xml' java.srcDirs = ['src'] resources.srcDirs = ['src'] - aidl.srcDirs = ['src'] - renderscript.srcDirs = ['src'] - res.srcDirs = ['res'] - assets.srcDirs = ['assets'] - jni.srcDirs = ['jni'] + jniLibs.srcDirs = ['libs'] } + } - instrumentTest.setRoot('tests') + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } - lintOptions { + lint { abortOnError false } - -} \ No newline at end of file +} From bdd30dbe933d1915da313466b31d23344c828fc6 Mon Sep 17 00:00:00 2001 From: SkyKai <1132234509@qq.com> Date: Thu, 18 Jun 2026 18:45:30 +0800 Subject: [PATCH 07/16] =?UTF-8?q?build(app):=20AGP=208=20=E4=BE=9D?= =?UTF-8?q?=E8=B5=96=E6=98=A0=E5=B0=84=E5=88=B0=20AndroidX/Material,?= =?UTF-8?q?=E7=A7=BB=E9=99=A4=E6=AD=BB=E5=BA=93=E4=B8=8E=E6=9C=AC=E5=9C=B0?= =?UTF-8?q?=20jar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 43 ++++++++++++++++---------------- app/src/main/AndroidManifest.xml | 3 +-- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index a2f362d..9c6c875 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,14 +1,13 @@ apply plugin: 'com.android.application' -apply plugin: 'me.tatarka.retrolambda' android { - compileSdkVersion 22 - buildToolsVersion "22.0.1" + namespace 'com.github.skykai.stickercamera' + compileSdk 36 defaultConfig { applicationId "com.github.skykai.stickercamera" - minSdkVersion 15 - targetSdkVersion 22 + minSdk 26 + targetSdk 36 versionCode 1 versionName "1.0" } @@ -18,26 +17,26 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } } dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - compile 'com.android.support:appcompat-v7:22.2.0' - compile 'com.android.support:recyclerview-v7:22.2.0' - compile 'com.android.support:cardview-v7:22.2.0' - compile 'com.jakewharton:butterknife:6.1.0' - compile 'com.readystatesoftware.systembartint:systembartint:1.0.3' - compile 'com.melnykov:floatingactionbutton:1.3.0' - compile 'com.rengwuxian.materialedittext:library:2.1.3' - compile files('libs/fastjson-1.2.5.jar') - compile files('universal-image-loader-1.9.4.jar') - compile 'it.sephiroth.android.library.horizontallistview:hlistview:1.2.2' - compile project(":Gpu-Image") - compile project(":ImageViewTouch") - compile 'de.greenrobot:eventbus:2.4.0' + implementation 'androidx.appcompat:appcompat:1.7.0' + implementation 'androidx.recyclerview:recyclerview:1.3.2' + implementation 'androidx.cardview:cardview:1.0.0' + implementation 'androidx.core:core:1.13.1' + implementation 'androidx.fragment:fragment:1.8.5' + implementation 'androidx.viewpager:viewpager:1.0.0' + implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' + implementation 'com.google.android.material:material:1.12.0' + implementation 'com.jakewharton:butterknife:10.2.3' + annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.3' + implementation 'com.alibaba:fastjson:1.2.83' + implementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.5' + implementation 'org.greenrobot:eventbus:3.3.1' + implementation project(':Gpu-Image') + implementation project(':ImageViewTouch') } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index cd4afe6..3c49e3d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,5 @@ - + From 50bee0d468445604f916a8c8e9c4cd1bd7fca885 Mon Sep 17 00:00:00 2001 From: SkyKai <1132234509@qq.com> Date: Thu, 18 Jun 2026 18:46:34 +0800 Subject: [PATCH 08/16] =?UTF-8?q?refactor(app):=20android.support.*=20?= =?UTF-8?q?=E5=85=A8=E9=87=8F=E8=BF=81=E7=A7=BB=E5=88=B0=20androidx?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/customview/PagerSlidingTabStrip.java | 4 ++-- .../app/camera/fragment/AlbumFragment.java | 2 +- .../com/stickercamera/app/camera/ui/AlbumActivity.java | 8 ++++---- .../app/camera/ui/PhotoProcessActivity.java | 2 +- .../java/com/stickercamera/app/ui/MainActivity.java | 10 +++++----- .../main/java/com/stickercamera/base/BaseActivity.java | 2 +- .../com/stickercamera/base/BaseFragmentActivity.java | 2 +- app/src/main/res/layout/activity_album.xml | 2 +- app/src/main/res/layout/activity_main.xml | 2 +- app/src/main/res/layout/item_picture.xml | 4 ++-- 10 files changed, 19 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/com/customview/PagerSlidingTabStrip.java b/app/src/main/java/com/customview/PagerSlidingTabStrip.java index bae07ca..773e31a 100644 --- a/app/src/main/java/com/customview/PagerSlidingTabStrip.java +++ b/app/src/main/java/com/customview/PagerSlidingTabStrip.java @@ -26,8 +26,8 @@ import android.os.Build; import android.os.Parcel; import android.os.Parcelable; -import android.support.v4.view.ViewPager; -import android.support.v4.view.ViewPager.OnPageChangeListener; +import androidx.viewpager.widget.ViewPager; +import androidx.viewpager.widget.ViewPager.OnPageChangeListener; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.TypedValue; diff --git a/app/src/main/java/com/stickercamera/app/camera/fragment/AlbumFragment.java b/app/src/main/java/com/stickercamera/app/camera/fragment/AlbumFragment.java index a2d1d85..edca28d 100644 --- a/app/src/main/java/com/stickercamera/app/camera/fragment/AlbumFragment.java +++ b/app/src/main/java/com/stickercamera/app/camera/fragment/AlbumFragment.java @@ -1,7 +1,7 @@ package com.stickercamera.app.camera.fragment; import android.os.Bundle; -import android.support.v4.app.Fragment; +import androidx.fragment.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/app/src/main/java/com/stickercamera/app/camera/ui/AlbumActivity.java b/app/src/main/java/com/stickercamera/app/camera/ui/AlbumActivity.java index 370a5ba..a8dac1e 100644 --- a/app/src/main/java/com/stickercamera/app/camera/ui/AlbumActivity.java +++ b/app/src/main/java/com/stickercamera/app/camera/ui/AlbumActivity.java @@ -2,10 +2,10 @@ import android.content.Intent; import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentPagerAdapter; -import android.support.v4.view.ViewPager; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentPagerAdapter; +import androidx.viewpager.widget.ViewPager; import com.common.util.FileUtils; import com.common.util.ImageUtils; diff --git a/app/src/main/java/com/stickercamera/app/camera/ui/PhotoProcessActivity.java b/app/src/main/java/com/stickercamera/app/camera/ui/PhotoProcessActivity.java index 810f94a..a0c7799 100644 --- a/app/src/main/java/com/stickercamera/app/camera/ui/PhotoProcessActivity.java +++ b/app/src/main/java/com/stickercamera/app/camera/ui/PhotoProcessActivity.java @@ -9,7 +9,7 @@ import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.os.Bundle; -import android.support.annotation.Nullable; +import androidx.annotation.Nullable; import android.util.Log; import android.view.LayoutInflater; import android.view.View; diff --git a/app/src/main/java/com/stickercamera/app/ui/MainActivity.java b/app/src/main/java/com/stickercamera/app/ui/MainActivity.java index fc6c585..e42e912 100644 --- a/app/src/main/java/com/stickercamera/app/ui/MainActivity.java +++ b/app/src/main/java/com/stickercamera/app/ui/MainActivity.java @@ -1,12 +1,12 @@ package com.stickercamera.app.ui; import android.graphics.BitmapFactory; -import android.support.v4.widget.SwipeRefreshLayout; -import android.support.v7.app.AppCompatActivity; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; +import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; -import android.support.v7.widget.CardView; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; +import androidx.cardview.widget.CardView; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; diff --git a/app/src/main/java/com/stickercamera/base/BaseActivity.java b/app/src/main/java/com/stickercamera/base/BaseActivity.java index 74d5328..32658db 100644 --- a/app/src/main/java/com/stickercamera/base/BaseActivity.java +++ b/app/src/main/java/com/stickercamera/base/BaseActivity.java @@ -5,7 +5,7 @@ import android.content.DialogInterface; import android.os.Build; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import android.util.TypedValue; import android.view.Menu; import android.view.View; diff --git a/app/src/main/java/com/stickercamera/base/BaseFragmentActivity.java b/app/src/main/java/com/stickercamera/base/BaseFragmentActivity.java index d973f10..1e00598 100644 --- a/app/src/main/java/com/stickercamera/base/BaseFragmentActivity.java +++ b/app/src/main/java/com/stickercamera/base/BaseFragmentActivity.java @@ -1,6 +1,6 @@ package com.stickercamera.base; -import android.support.v4.app.FragmentActivity; +import androidx.fragment.app.FragmentActivity; import android.view.View; import com.customview.CommonTitleBar; diff --git a/app/src/main/res/layout/activity_album.xml b/app/src/main/res/layout/activity_album.xml index 471a0a4..ced9b27 100644 --- a/app/src/main/res/layout/activity_album.xml +++ b/app/src/main/res/layout/activity_album.xml @@ -19,7 +19,7 @@ app:pstsIndicatorHeight="2dp" app:pstsIndicatorColor="@color/pink"/> - - - - \ No newline at end of file + \ No newline at end of file From 32841ccf1b4ace2b4b7da9a18587e3692941a985 Mon Sep 17 00:00:00 2001 From: SkyKai <1132234509@qq.com> Date: Thu, 18 Jun 2026 18:46:57 +0800 Subject: [PATCH 09/16] refactor(app): ButterKnife 6 -> 10 (@BindView/bind) --- .../app/camera/ui/AlbumActivity.java | 8 +++---- .../app/camera/ui/CameraActivity.java | 24 +++++++++---------- .../app/camera/ui/CropPhotoActivity.java | 14 +++++------ .../app/camera/ui/PhotoProcessActivity.java | 18 +++++++------- .../app/ui/EditTextActivity.java | 8 +++---- .../stickercamera/app/ui/MainActivity.java | 14 +++++------ .../com/stickercamera/base/BaseActivity.java | 2 -- 7 files changed, 43 insertions(+), 45 deletions(-) diff --git a/app/src/main/java/com/stickercamera/app/camera/ui/AlbumActivity.java b/app/src/main/java/com/stickercamera/app/camera/ui/AlbumActivity.java index a8dac1e..3cfb854 100644 --- a/app/src/main/java/com/stickercamera/app/camera/ui/AlbumActivity.java +++ b/app/src/main/java/com/stickercamera/app/camera/ui/AlbumActivity.java @@ -22,7 +22,7 @@ import java.util.Map; import butterknife.ButterKnife; -import butterknife.InjectView; +import butterknife.BindView; /** * 相册界面 @@ -35,16 +35,16 @@ public class AlbumActivity extends CameraBaseActivity { private Map albums; private List paths = new ArrayList(); - @InjectView(R.id.indicator) + @BindView(R.id.indicator) PagerSlidingTabStrip tab; - @InjectView(R.id.pager) + @BindView(R.id.pager) ViewPager pager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_album); - ButterKnife.inject(this); + ButterKnife.bind(this); albums = ImageUtils.findGalleries(this, paths, 0); //ViewPager的adapter FragmentPagerAdapter adapter = new TabPageIndicatorAdapter(getSupportFragmentManager()); diff --git a/app/src/main/java/com/stickercamera/app/camera/ui/CameraActivity.java b/app/src/main/java/com/stickercamera/app/camera/ui/CameraActivity.java index 28e7a81..b5f4fc6 100644 --- a/app/src/main/java/com/stickercamera/app/camera/ui/CameraActivity.java +++ b/app/src/main/java/com/stickercamera/app/camera/ui/CameraActivity.java @@ -54,7 +54,7 @@ import java.util.List; import butterknife.ButterKnife; -import butterknife.InjectView; +import butterknife.BindView; /** * 相机界面 @@ -78,25 +78,25 @@ public class CameraActivity extends CameraBaseActivity { private int mCurrentCameraId = 0; //1是前置 0是后置 private Handler handler = new Handler(); - @InjectView(R.id.masking) + @BindView(R.id.masking) CameraGrid cameraGrid; - @InjectView(R.id.photo_area) + @BindView(R.id.photo_area) LinearLayout photoArea; - @InjectView(R.id.panel_take_photo) + @BindView(R.id.panel_take_photo) View takePhotoPanel; - @InjectView(R.id.takepicture) + @BindView(R.id.takepicture) Button takePicture; - @InjectView(R.id.flashBtn) + @BindView(R.id.flashBtn) ImageView flashBtn; - @InjectView(R.id.change) + @BindView(R.id.change) ImageView changeBtn; - @InjectView(R.id.back) + @BindView(R.id.back) ImageView backBtn; - @InjectView(R.id.next) + @BindView(R.id.next) ImageView galleryBtn; - @InjectView(R.id.focus_index) + @BindView(R.id.focus_index) View focusIndex; - @InjectView(R.id.surfaceView) + @BindView(R.id.surfaceView) SurfaceView surfaceView; @@ -105,7 +105,7 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_camera); mCameraHelper = new CameraHelper(this); - ButterKnife.inject(this); + ButterKnife.bind(this); initView(); initEvent(); } diff --git a/app/src/main/java/com/stickercamera/app/camera/ui/CropPhotoActivity.java b/app/src/main/java/com/stickercamera/app/camera/ui/CropPhotoActivity.java index 85e4f6a..968d2be 100644 --- a/app/src/main/java/com/stickercamera/app/camera/ui/CropPhotoActivity.java +++ b/app/src/main/java/com/stickercamera/app/camera/ui/CropPhotoActivity.java @@ -33,7 +33,7 @@ import java.io.InputStream; import butterknife.ButterKnife; -import butterknife.InjectView; +import butterknife.BindView; /** * 裁剪图片界面 @@ -49,15 +49,15 @@ public class CropPhotoActivity extends CameraBaseActivity { private int initWidth, initHeight; private static final int MAX_WRAP_SIZE = 2048; - @InjectView(R.id.crop_image) + @BindView(R.id.crop_image) ImageViewTouch cropImage; - @InjectView(R.id.draw_area) + @BindView(R.id.draw_area) ViewGroup drawArea; - @InjectView(R.id.wrap_image) + @BindView(R.id.wrap_image) View wrapImage; - @InjectView(R.id.btn_crop_type) + @BindView(R.id.btn_crop_type) View btnCropType; - @InjectView(R.id.image_center) + @BindView(R.id.image_center) ImageView imageCenter; @Override @@ -65,7 +65,7 @@ public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 显示界面 setContentView(R.layout.activity_new_crop); - ButterKnife.inject(this); + ButterKnife.bind(this); fileUri = getIntent().getData(); initView(); initEvent(); diff --git a/app/src/main/java/com/stickercamera/app/camera/ui/PhotoProcessActivity.java b/app/src/main/java/com/stickercamera/app/camera/ui/PhotoProcessActivity.java index a0c7799..318c0e8 100644 --- a/app/src/main/java/com/stickercamera/app/camera/ui/PhotoProcessActivity.java +++ b/app/src/main/java/com/stickercamera/app/camera/ui/PhotoProcessActivity.java @@ -50,7 +50,7 @@ import java.util.List; import butterknife.ButterKnife; -import butterknife.InjectView; +import butterknife.BindView; import de.greenrobot.event.EventBus; import it.sephiroth.android.library.widget.HListView; import jp.co.cyberagent.android.gpuimage.GPUImageFilter; @@ -65,22 +65,22 @@ public class PhotoProcessActivity extends CameraBaseActivity { //滤镜图片 - @InjectView(R.id.gpuimage) + @BindView(R.id.gpuimage) GPUImageView mGPUImageView; //绘图区域 - @InjectView(R.id.drawing_view_container) + @BindView(R.id.drawing_view_container) ViewGroup drawArea; //底部按钮 - @InjectView(R.id.sticker_btn) + @BindView(R.id.sticker_btn) TextView stickerBtn; - @InjectView(R.id.filter_btn) + @BindView(R.id.filter_btn) TextView filterBtn; - @InjectView(R.id.text_btn) + @BindView(R.id.text_btn) TextView labelBtn; //工具区 - @InjectView(R.id.list_tools) + @BindView(R.id.list_tools) HListView bottomToolBar; - @InjectView(R.id.toolbar_area) + @BindView(R.id.toolbar_area) ViewGroup toolArea; private MyImageViewDrawableOverlay mImageView; private LabelSelector labelSelector; @@ -103,7 +103,7 @@ public class PhotoProcessActivity extends CameraBaseActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_image_process); - ButterKnife.inject(this); + ButterKnife.bind(this); EffectUtil.clear(); initView(); initEvent(); diff --git a/app/src/main/java/com/stickercamera/app/ui/EditTextActivity.java b/app/src/main/java/com/stickercamera/app/ui/EditTextActivity.java index 0325333..d7b0a8a 100755 --- a/app/src/main/java/com/stickercamera/app/ui/EditTextActivity.java +++ b/app/src/main/java/com/stickercamera/app/ui/EditTextActivity.java @@ -17,7 +17,7 @@ import com.stickercamera.base.BaseActivity; import butterknife.ButterKnife; -import butterknife.InjectView; +import butterknife.BindView; /** @@ -30,9 +30,9 @@ public class EditTextActivity extends BaseActivity { private final static int MAX = 10; private int maxlength = MAX; - @InjectView(R.id.text_input) + @BindView(R.id.text_input) EditText contentView; - @InjectView(R.id.tag_input_tips) + @BindView(R.id.tag_input_tips) TextView numberTips; public static void openTextEdit(Activity mContext, String defaultStr,int maxLength, int reqCode) { @@ -48,7 +48,7 @@ public static void openTextEdit(Activity mContext, String defaultStr,int maxLeng public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_edit_text); - ButterKnife.inject(this); + ButterKnife.bind(this); maxlength = getIntent().getIntExtra(AppConstants.PARAM_MAX_SIZE, MAX); String defaultStr = getIntent().getStringExtra(AppConstants.PARAM_EDIT_TEXT); diff --git a/app/src/main/java/com/stickercamera/app/ui/MainActivity.java b/app/src/main/java/com/stickercamera/app/ui/MainActivity.java index e42e912..e9a41e8 100644 --- a/app/src/main/java/com/stickercamera/app/ui/MainActivity.java +++ b/app/src/main/java/com/stickercamera/app/ui/MainActivity.java @@ -38,7 +38,7 @@ import java.util.List; import butterknife.ButterKnife; -import butterknife.InjectView; +import butterknife.BindView; import de.greenrobot.event.EventBus; /** @@ -49,9 +49,9 @@ */ public class MainActivity extends BaseActivity { - @InjectView(R.id.fab) + @BindView(R.id.fab) FloatingActionButton fab; - @InjectView(R.id.recycler_view) + @BindView(R.id.recycler_view) RecyclerView mRecyclerView; private List feedList; private PictureAdapter mAdapter; @@ -61,7 +61,7 @@ public class MainActivity extends BaseActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - ButterKnife.inject(this); + ButterKnife.bind(this); EventBus.getDefault().register(this); initView(); @@ -186,9 +186,9 @@ public void run() { } public static class ViewHolder extends RecyclerView.ViewHolder { - @InjectView(R.id.pictureLayout) + @BindView(R.id.pictureLayout) RelativeLayout pictureLayout; - @InjectView(R.id.picture) + @BindView(R.id.picture) ImageView picture; private List tagList = new ArrayList<>(); @@ -206,7 +206,7 @@ public void setTagList(List tagList) { public ViewHolder(View itemView) { super(itemView); - ButterKnife.inject(this, itemView); + ButterKnife.bind(this, itemView); } } diff --git a/app/src/main/java/com/stickercamera/base/BaseActivity.java b/app/src/main/java/com/stickercamera/base/BaseActivity.java index 32658db..5c80eb4 100644 --- a/app/src/main/java/com/stickercamera/base/BaseActivity.java +++ b/app/src/main/java/com/stickercamera/base/BaseActivity.java @@ -15,8 +15,6 @@ import com.customview.CommonTitleBar; import com.readystatesoftware.systembartint.SystemBarTintManager; -import butterknife.ButterKnife; - /** * Created by sky on 15/7/6. */ From e4917bb209ae6ffdadf6044a3e4d586a76b09bf8 Mon Sep 17 00:00:00 2001 From: SkyKai <1132234509@qq.com> Date: Thu, 18 Jun 2026 18:47:25 +0800 Subject: [PATCH 10/16] refactor(app): EventBus 2.4 -> 3.3.1 (@Subscribe) --- .../stickercamera/app/camera/ui/PhotoProcessActivity.java | 2 +- .../main/java/com/stickercamera/app/ui/MainActivity.java | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/stickercamera/app/camera/ui/PhotoProcessActivity.java b/app/src/main/java/com/stickercamera/app/camera/ui/PhotoProcessActivity.java index 318c0e8..3668044 100644 --- a/app/src/main/java/com/stickercamera/app/camera/ui/PhotoProcessActivity.java +++ b/app/src/main/java/com/stickercamera/app/camera/ui/PhotoProcessActivity.java @@ -51,7 +51,7 @@ import butterknife.ButterKnife; import butterknife.BindView; -import de.greenrobot.event.EventBus; +import org.greenrobot.eventbus.EventBus; import it.sephiroth.android.library.widget.HListView; import jp.co.cyberagent.android.gpuimage.GPUImageFilter; import jp.co.cyberagent.android.gpuimage.GPUImageView; diff --git a/app/src/main/java/com/stickercamera/app/ui/MainActivity.java b/app/src/main/java/com/stickercamera/app/ui/MainActivity.java index e9a41e8..af4f51c 100644 --- a/app/src/main/java/com/stickercamera/app/ui/MainActivity.java +++ b/app/src/main/java/com/stickercamera/app/ui/MainActivity.java @@ -39,7 +39,9 @@ import butterknife.ButterKnife; import butterknife.BindView; -import de.greenrobot.event.EventBus; +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.greenrobot.eventbus.ThreadMode; /** * 主界面 @@ -79,7 +81,8 @@ protected void onCreate(Bundle savedInstanceState) { } - public void onEventMainThread(FeedItem feedItem) { + @Subscribe(threadMode = ThreadMode.MAIN) + public void onEvent(FeedItem feedItem) { if (feedList == null) { feedList = new ArrayList(); } From 68a9ce81dad5636fc3fd87ff99865309afec5055 Mon Sep 17 00:00:00 2001 From: SkyKai <1132234509@qq.com> Date: Thu, 18 Jun 2026 18:48:04 +0800 Subject: [PATCH 11/16] refactor(app): melnykov FAB -> Material FloatingActionButton --- .../main/java/com/stickercamera/app/ui/MainActivity.java | 2 +- app/src/main/res/layout/activity_main.xml | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/stickercamera/app/ui/MainActivity.java b/app/src/main/java/com/stickercamera/app/ui/MainActivity.java index af4f51c..3941674 100644 --- a/app/src/main/java/com/stickercamera/app/ui/MainActivity.java +++ b/app/src/main/java/com/stickercamera/app/ui/MainActivity.java @@ -24,7 +24,7 @@ import com.common.util.StringUtils; import com.customview.LabelView; import com.github.skykai.stickercamera.R; -import com.melnykov.fab.FloatingActionButton; +import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.stickercamera.App; import com.stickercamera.AppConstants; import com.stickercamera.app.camera.CameraManager; diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 7fc5d65..a17c35b 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -17,18 +17,17 @@ android:scrollbars="vertical" /> - + app:backgroundTint="?attr/colorPrimary" + app:rippleColor="?attr/colorPrimaryDark" + app:tint="@android:color/white" /> From 28421381ee333df06a1e8112f7225016d82d7237 Mon Sep 17 00:00:00 2001 From: SkyKai <1132234509@qq.com> Date: Thu, 18 Jun 2026 18:49:28 +0800 Subject: [PATCH 12/16] =?UTF-8?q?refactor(app):=20HListView=20->=20?= =?UTF-8?q?=E6=B0=B4=E5=B9=B3=20RecyclerView,=E9=80=82=E9=85=8D=E5=99=A8?= =?UTF-8?q?=E6=94=B9=20RecyclerView.Adapter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/camera/adapter/FilterAdapter.java | 86 ++++++++++--------- .../camera/adapter/StickerToolAdapter.java | 77 ++++++++--------- .../app/camera/ui/PhotoProcessActivity.java | 65 +++++++------- .../res/layout/activity_image_process.xml | 6 +- 4 files changed, 116 insertions(+), 118 deletions(-) diff --git a/app/src/main/java/com/stickercamera/app/camera/adapter/FilterAdapter.java b/app/src/main/java/com/stickercamera/app/camera/adapter/FilterAdapter.java index 161c108..7deddde 100755 --- a/app/src/main/java/com/stickercamera/app/camera/adapter/FilterAdapter.java +++ b/app/src/main/java/com/stickercamera/app/camera/adapter/FilterAdapter.java @@ -5,9 +5,10 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.BaseAdapter; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; import com.github.skykai.stickercamera.R; import com.stickercamera.app.camera.effect.FilterEffect; @@ -20,73 +21,76 @@ /** * @author tongqian.ni - * */ -public class FilterAdapter extends BaseAdapter { +public class FilterAdapter extends RecyclerView.Adapter { - List filterUris; - Context mContext; - private Bitmap background; + public interface OnItemClickListener { + void onItemClick(int position); + } - private int selectFilter = 0; + private final List filterUris; + private final Context mContext; + private final Bitmap background; - public void setSelectFilter(int selectFilter) { - this.selectFilter = selectFilter; + private int selectFilter = 0; + private OnItemClickListener onItemClickListener; + + public FilterAdapter(Context context, List effects, Bitmap background) { + this.mContext = context; + this.filterUris = effects; + this.background = background; } - public int getSelectFilter() { - return selectFilter; + public void setOnItemClickListener(OnItemClickListener l) { + this.onItemClickListener = l; } - public FilterAdapter(Context context, List effects, Bitmap backgroud) { - filterUris = effects; - mContext = context; - this.background = backgroud; + public void setSelectFilter(int selectFilter) { + this.selectFilter = selectFilter; } - @Override - public int getCount() { - return filterUris.size(); + public int getSelectFilter() { + return selectFilter; } - @Override - public Object getItem(int position) { + public FilterEffect getItem(int position) { return filterUris.get(position); } + @NonNull @Override - public long getItemId(int position) { - return position; + public EffectHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View v = LayoutInflater.from(mContext).inflate(R.layout.item_bottom_filter, parent, false); + return new EffectHolder(v); } @Override - public View getView(int position, View convertView, ViewGroup parent) { - EffectHolder holder = null; - if (convertView == null) { - LayoutInflater layoutInflater = LayoutInflater.from(mContext); - convertView = layoutInflater.inflate(R.layout.item_bottom_filter, null); - holder = new EffectHolder(); - holder.filteredImg = (GPUImageView) convertView.findViewById(R.id.small_filter); - holder.filterName = (TextView) convertView.findViewById(R.id.filter_name); - convertView.setTag(holder); - } else { - holder = (EffectHolder) convertView.getTag(); - } - - final FilterEffect effect = (FilterEffect) getItem(position); - + public void onBindViewHolder(@NonNull EffectHolder holder, int position) { + final FilterEffect effect = getItem(position); holder.filteredImg.setImage(background); holder.filterName.setText(effect.getTitle()); - //if (!effect.isOri() && effect.getType() != null) { GPUImageFilter filter = GPUImageFilterTools.createFilterForType(mContext, effect.getType()); holder.filteredImg.setFilter(filter); + holder.itemView.setOnClickListener(v -> { + if (onItemClickListener != null) { + onItemClickListener.onItemClick(holder.getAdapterPosition()); + } + }); + } - return convertView; + @Override + public int getItemCount() { + return filterUris.size(); } - class EffectHolder { + static class EffectHolder extends RecyclerView.ViewHolder { GPUImageView filteredImg; TextView filterName; - } + EffectHolder(View itemView) { + super(itemView); + filteredImg = itemView.findViewById(R.id.small_filter); + filterName = itemView.findViewById(R.id.filter_name); + } + } } diff --git a/app/src/main/java/com/stickercamera/app/camera/adapter/StickerToolAdapter.java b/app/src/main/java/com/stickercamera/app/camera/adapter/StickerToolAdapter.java index 85e8c9a..c7a78c8 100644 --- a/app/src/main/java/com/stickercamera/app/camera/adapter/StickerToolAdapter.java +++ b/app/src/main/java/com/stickercamera/app/camera/adapter/StickerToolAdapter.java @@ -4,78 +4,77 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.BaseAdapter; import android.widget.ImageView; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; import com.common.util.ImageLoaderUtils; import com.github.skykai.stickercamera.R; -import com.nostra13.universalimageloader.core.ImageLoader; import com.stickercamera.app.model.Addon; import java.util.List; /** - * * 贴纸适配器 + * * @author tongqian.ni */ -public class StickerToolAdapter extends BaseAdapter { +public class StickerToolAdapter extends RecyclerView.Adapter { - List filterUris; - Context mContext; + public interface OnItemClickListener { + void onItemClick(int position); + } + + private final List filterUris; + private final Context mContext; + private OnItemClickListener onItemClickListener; public StickerToolAdapter(Context context, List effects) { - filterUris = effects; - mContext = context; + this.mContext = context; + this.filterUris = effects; } - @Override - public int getCount() { - return filterUris.size(); + public void setOnItemClickListener(OnItemClickListener l) { + this.onItemClickListener = l; } - @Override - public Object getItem(int position) { + public Addon getItem(int position) { return filterUris.get(position); } + @NonNull @Override - public long getItemId(int position) { - return position; + public EffectHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View v = LayoutInflater.from(mContext).inflate(R.layout.item_bottom_tool, parent, false); + return new EffectHolder(v); } @Override - public View getView(int position, View convertView, ViewGroup parent) { - EffectHolder holder = null; - if (convertView == null) { - LayoutInflater layoutInflater = LayoutInflater.from(mContext); - convertView = layoutInflater.inflate(R.layout.item_bottom_tool, null); - holder = new EffectHolder(); - holder.logo = (ImageView) convertView.findViewById(R.id.effect_image); - holder.container = (ImageView) convertView.findViewById(R.id.effect_background); - //holder.navImage.setOnClickListener(holder.clickListener); - convertView.setTag(holder); - } else { - holder = (EffectHolder) convertView.getTag(); - } - - final Addon effect = (Addon) getItem(position); - - return showItem(convertView, holder, effect); - } - - private View showItem(View convertView, EffectHolder holder, final Addon sticker) { - + public void onBindViewHolder(@NonNull EffectHolder holder, int position) { + final Addon sticker = getItem(position); holder.container.setVisibility(View.GONE); ImageLoaderUtils.displayDrawableImage(sticker.getId() + "", holder.logo, null); + holder.itemView.setOnClickListener(v -> { + if (onItemClickListener != null) { + onItemClickListener.onItemClick(holder.getAdapterPosition()); + } + }); + } - return convertView; + @Override + public int getItemCount() { + return filterUris.size(); } - class EffectHolder { + static class EffectHolder extends RecyclerView.ViewHolder { ImageView logo; ImageView container; - } + EffectHolder(View itemView) { + super(itemView); + logo = itemView.findViewById(R.id.effect_image); + container = itemView.findViewById(R.id.effect_background); + } + } } diff --git a/app/src/main/java/com/stickercamera/app/camera/ui/PhotoProcessActivity.java b/app/src/main/java/com/stickercamera/app/camera/ui/PhotoProcessActivity.java index 3668044..664b317 100644 --- a/app/src/main/java/com/stickercamera/app/camera/ui/PhotoProcessActivity.java +++ b/app/src/main/java/com/stickercamera/app/camera/ui/PhotoProcessActivity.java @@ -49,10 +49,12 @@ import java.util.Date; import java.util.List; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + import butterknife.ButterKnife; import butterknife.BindView; import org.greenrobot.eventbus.EventBus; -import it.sephiroth.android.library.widget.HListView; import jp.co.cyberagent.android.gpuimage.GPUImageFilter; import jp.co.cyberagent.android.gpuimage.GPUImageView; @@ -79,7 +81,7 @@ public class PhotoProcessActivity extends CameraBaseActivity { TextView labelBtn; //工具区 @BindView(R.id.list_tools) - HListView bottomToolBar; + RecyclerView bottomToolBar; @BindView(R.id.toolbar_area) ViewGroup toolArea; private MyImageViewDrawableOverlay mImageView; @@ -346,23 +348,20 @@ private boolean setCurrentBtn(TextView btn) { //初始化贴图 private void initStickerToolBar(){ - bottomToolBar.setAdapter(new StickerToolAdapter(PhotoProcessActivity.this, EffectUtil.addonList)); - bottomToolBar.setOnItemClickListener(new it.sephiroth.android.library.widget.AdapterView.OnItemClickListener() { - - @Override - public void onItemClick(it.sephiroth.android.library.widget.AdapterView arg0, - View arg1, int arg2, long arg3) { - labelSelector.hide(); - Addon sticker = EffectUtil.addonList.get(arg2); - EffectUtil.addStickerImage(mImageView, PhotoProcessActivity.this, sticker, - new EffectUtil.StickerCallback() { - @Override - public void onRemoveSticker(Addon sticker) { - labelSelector.hide(); - } - }); - } + bottomToolBar.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)); + StickerToolAdapter adapter = new StickerToolAdapter(PhotoProcessActivity.this, EffectUtil.addonList); + adapter.setOnItemClickListener(position -> { + labelSelector.hide(); + Addon sticker = EffectUtil.addonList.get(position); + EffectUtil.addStickerImage(mImageView, PhotoProcessActivity.this, sticker, + new EffectUtil.StickerCallback() { + @Override + public void onRemoveSticker(Addon sticker) { + labelSelector.hide(); + } + }); }); + bottomToolBar.setAdapter(adapter); setCurrentBtn(stickerBtn); } @@ -370,25 +369,23 @@ public void onRemoveSticker(Addon sticker) { //初始化滤镜 private void initFilterToolBar(){ final List filters = EffectService.getInst().getLocalFilters(); - final FilterAdapter adapter = new FilterAdapter(PhotoProcessActivity.this, filters,smallImageBackgroud); - bottomToolBar.setAdapter(adapter); - bottomToolBar.setOnItemClickListener(new it.sephiroth.android.library.widget.AdapterView.OnItemClickListener() { - @Override - public void onItemClick(it.sephiroth.android.library.widget.AdapterView arg0, View arg1, int arg2, long arg3) { - labelSelector.hide(); - if (adapter.getSelectFilter() != arg2) { - adapter.setSelectFilter(arg2); - GPUImageFilter filter = GPUImageFilterTools.createFilterForType( - PhotoProcessActivity.this, filters.get(arg2).getType()); - mGPUImageView.setFilter(filter); - GPUImageFilterTools.FilterAdjuster mFilterAdjuster = new GPUImageFilterTools.FilterAdjuster(filter); - //可调节颜色的滤镜 - if (mFilterAdjuster.canAdjust()) { - //mFilterAdjuster.adjust(100); 给可调节的滤镜选一个合适的值 - } + bottomToolBar.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)); + final FilterAdapter adapter = new FilterAdapter(PhotoProcessActivity.this, filters, smallImageBackgroud); + adapter.setOnItemClickListener(position -> { + labelSelector.hide(); + if (adapter.getSelectFilter() != position) { + adapter.setSelectFilter(position); + GPUImageFilter filter = GPUImageFilterTools.createFilterForType( + PhotoProcessActivity.this, filters.get(position).getType()); + mGPUImageView.setFilter(filter); + GPUImageFilterTools.FilterAdjuster mFilterAdjuster = new GPUImageFilterTools.FilterAdjuster(filter); + //可调节颜色的滤镜 + if (mFilterAdjuster.canAdjust()) { + //mFilterAdjuster.adjust(100); 给可调节的滤镜选一个合适的值 } } }); + bottomToolBar.setAdapter(adapter); } //添加标签 diff --git a/app/src/main/res/layout/activity_image_process.xml b/app/src/main/res/layout/activity_image_process.xml index cbd7a5f..405290e 100755 --- a/app/src/main/res/layout/activity_image_process.xml +++ b/app/src/main/res/layout/activity_image_process.xml @@ -41,14 +41,12 @@ android:layout_height="fill_parent" android:orientation="vertical" > - + android:overScrollMode="always"/> From 61ec66d16a94d8b330aaf2aaade620c000baf1ea Mon Sep 17 00:00:00 2001 From: SkyKai <1132234509@qq.com> Date: Thu, 18 Jun 2026 18:50:12 +0800 Subject: [PATCH 13/16] =?UTF-8?q?refactor(app):=20=E7=A7=BB=E9=99=A4=20sys?= =?UTF-8?q?tembartint,=E6=94=B9=20edge-to-edge=20+=20WindowInsets=20?= =?UTF-8?q?=E9=80=82=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/stickercamera/base/BaseActivity.java | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/stickercamera/base/BaseActivity.java b/app/src/main/java/com/stickercamera/base/BaseActivity.java index 5c80eb4..35d0a02 100644 --- a/app/src/main/java/com/stickercamera/base/BaseActivity.java +++ b/app/src/main/java/com/stickercamera/base/BaseActivity.java @@ -1,19 +1,20 @@ package com.stickercamera.base; -import android.annotation.TargetApi; import android.app.Activity; import android.content.DialogInterface; -import android.os.Build; import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; import android.util.TypedValue; import android.view.Menu; import android.view.View; -import android.view.WindowManager; + +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowCompat; +import androidx.core.view.WindowInsetsCompat; import com.github.skykai.stickercamera.R; import com.customview.CommonTitleBar; -import com.readystatesoftware.systembartint.SystemBarTintManager; /** * Created by sky on 15/7/6. @@ -33,19 +34,8 @@ protected void onCreate(Bundle savedInstanceState) { } - @TargetApi(19) private void initWindow() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); - getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); - SystemBarTintManager tintManager = new SystemBarTintManager(this); - tintManager.setStatusBarTintColor(getStatusBarColor()); - tintManager.setStatusBarTintEnabled(true); - } - } - - public int getStatusBarColor() { - return getColorPrimary(); + WindowCompat.setDecorFitsSystemWindows(getWindow(), false); } public int getColorPrimary() { @@ -57,6 +47,14 @@ public int getColorPrimary() { @Override public void setContentView(int layoutResID) { super.setContentView(layoutResID); + final View content = findViewById(android.R.id.content); + if (content != null) { + ViewCompat.setOnApplyWindowInsetsListener(content, (v, insets) -> { + Insets bars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); + v.setPadding(bars.left, bars.top, bars.right, bars.bottom); + return insets; + }); + } titleBar = (CommonTitleBar) findViewById(R.id.title_layout); if (titleBar != null) titleBar.setLeftBtnOnclickListener(new View.OnClickListener() { From 365aa324e465e2b75b4b9d21b4285dd3a5a038f2 Mon Sep 17 00:00:00 2001 From: SkyKai <1132234509@qq.com> Date: Thu, 18 Jun 2026 18:53:04 +0800 Subject: [PATCH 14/16] =?UTF-8?q?fix:=20AGP=208=20=E5=85=A8=E9=87=8F?= =?UTF-8?q?=E6=9E=84=E5=BB=BA=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - manifest 启动 Activity 加 android:exported - ButterKnife 注解处理器 JDK17 放行 (--add-exports) - nonFinalResIds=false 使 R 字段 final 以兼容 @BindView - 替换已移除 API: Canvas.MATRIX_SAVE_FLAG -> save(), FloatMath -> Math --- app/build.gradle | 15 +++++++++++++++ app/src/main/AndroidManifest.xml | 1 + .../customview/MyImageViewDrawableOverlay.java | 4 ++-- .../app/camera/ui/CameraActivity.java | 3 +-- .../stickercamera/app/camera/util/EffectUtil.java | 2 +- gradle.properties | 1 + 6 files changed, 21 insertions(+), 5 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 9c6c875..b8636b6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -23,6 +23,21 @@ android { } } +// ButterKnife 10.x 的注解处理器需访问 JDK 内部 javac API;JDK 16+ 默认封装, +// 通过 --add-exports/--add-opens 放行(保留 ButterKnife 所需的标准解法)。 +tasks.withType(JavaCompile).configureEach { + options.fork = true + options.forkOptions.jvmArgs += [ + '--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED', + '--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED', + '--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED', + '--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED', + '--add-exports=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED', + '--add-opens=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED', + '--add-opens=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED' + ] +} + dependencies { implementation 'androidx.appcompat:appcompat:1.7.0' implementation 'androidx.recyclerview:recyclerview:1.3.2' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3c49e3d..c1e7789 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -18,6 +18,7 @@ android:theme="@style/BlueTheme"> diff --git a/app/src/main/java/com/customview/MyImageViewDrawableOverlay.java b/app/src/main/java/com/customview/MyImageViewDrawableOverlay.java index d014871..489540e 100755 --- a/app/src/main/java/com/customview/MyImageViewDrawableOverlay.java +++ b/app/src/main/java/com/customview/MyImageViewDrawableOverlay.java @@ -485,7 +485,7 @@ public void onDraw(Canvas canvas) { boolean shouldInvalidateAfter = false; for (int i = 0; i < mOverlayViews.size(); i++) { - canvas.save(Canvas.MATRIX_SAVE_FLAG); + canvas.save(); MyHighlightView current = mOverlayViews.get(i); current.draw(canvas); @@ -589,7 +589,7 @@ public void commit(Canvas canvas) { Matrix rotateMatrix = hv.getCropRotationMatrix(); Rect rect = hv.getCropRect(); - int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG); + int saveCount = canvas.save(); canvas.concat(rotateMatrix); content.setBounds(rect); content.draw(canvas); diff --git a/app/src/main/java/com/stickercamera/app/camera/ui/CameraActivity.java b/app/src/main/java/com/stickercamera/app/camera/ui/CameraActivity.java index b5f4fc6..9106f52 100644 --- a/app/src/main/java/com/stickercamera/app/camera/ui/CameraActivity.java +++ b/app/src/main/java/com/stickercamera/app/camera/ui/CameraActivity.java @@ -13,7 +13,6 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; -import android.util.FloatMath; import android.util.Log; import android.view.Gravity; import android.view.MotionEvent; @@ -286,7 +285,7 @@ private float spacing(MotionEvent event) { } float x = event.getX(0) - event.getX(1); float y = event.getY(0) - event.getY(1); - return FloatMath.sqrt(x * x + y * y); + return (float) Math.sqrt(x * x + y * y); } //放大缩小 diff --git a/app/src/main/java/com/stickercamera/app/camera/util/EffectUtil.java b/app/src/main/java/com/stickercamera/app/camera/util/EffectUtil.java index 2f3ab57..7e631c8 100644 --- a/app/src/main/java/com/stickercamera/app/camera/util/EffectUtil.java +++ b/app/src/main/java/com/stickercamera/app/camera/util/EffectUtil.java @@ -218,7 +218,7 @@ private static void applyOnSave(Canvas mCanvas, ImageViewTouch processImage,MyHi Matrix matrix = new Matrix(processImage.getImageMatrix()); if (!matrix.invert(matrix)) { } - int saveCount = mCanvas.save(Canvas.MATRIX_SAVE_FLAG); + int saveCount = mCanvas.save(); mCanvas.concat(rotateMatrix); stickerDrawable.setDropShadow(false); diff --git a/gradle.properties b/gradle.properties index 7103d64..ce29e0e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -19,4 +19,5 @@ android.useAndroidX=true android.nonTransitiveRClass=false +android.nonFinalResIds=false org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 \ No newline at end of file From 23292afccb9a5ff8b4ede899bfdcaa05795a756d Mon Sep 17 00:00:00 2001 From: SkyKai <1132234509@qq.com> Date: Thu, 18 Jun 2026 19:55:16 +0800 Subject: [PATCH 15/16] =?UTF-8?q?refactor(app):=20Gpu-Image=20=E6=94=B9=20?= =?UTF-8?q?Maven=20=E4=BE=9D=E8=B5=96=20+=20=E5=88=A0=E9=99=A4=E6=97=A0?= =?UTF-8?q?=E7=94=A8=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Gpu-Image vendored 模块改为 implementation 'jp.co.cyberagent.android:gpuimage:2.1.0',删除整个模块(含 4 个 .so);滤镜 import 迁到 .filter 子包 - 删除 13 个未被业务使用的 Trinea 工具类 + CameraBaseFragmentActivity + BaseFragmentActivity - GPUImageFilterTools 精简到实际使用的 NORMAL + ACV 曲线滤镜(668→81 行),并移除 PhotoProcessActivity 中已注释失效的 FilterAdjuster 调用 - 清理孤儿资源 tone_cuver_sample.acv / lookup_amatorka.png - 更新 CLAUDE.md 到当前工具链(AGP 8 / AndroidX / Java 17) ImageViewTouch 因深度耦合其 protected API 且已重打包,保留 vendored。 Co-Authored-By: Claude Opus 4.8 (1M context) --- CLAUDE.md | 62 ++ Gpu-Image/.gitignore | 32 - Gpu-Image/AndroidManifest.xml | 3 - Gpu-Image/build.gradle | 28 - Gpu-Image/gradle.properties | 3 - .../libs/arm64-v8a/libgpuimage-library.so | Bin 5440 -> 0 bytes .../libs/armeabi-v7a/libgpuimage-library.so | Bin 9316 -> 0 bytes Gpu-Image/libs/x86/libgpuimage-library.so | Bin 5116 -> 0 bytes Gpu-Image/libs/x86_64/libgpuimage-library.so | Bin 5632 -> 0 bytes Gpu-Image/proguard-project.txt | 20 - Gpu-Image/project.properties | 15 - .../cyberagent/android/gpuimage/GPUImage.java | 697 ---------------- .../GPUImage3x3ConvolutionFilter.java | 104 --- .../GPUImage3x3TextureSamplingFilter.java | 120 --- .../gpuimage/GPUImageAddBlendFilter.java | 60 -- .../gpuimage/GPUImageAlphaBlendFilter.java | 46 -- .../gpuimage/GPUImageBoxBlurFilter.java | 113 --- .../gpuimage/GPUImageBrightnessFilter.java | 66 -- .../GPUImageBulgeDistortionFilter.java | 130 --- .../gpuimage/GPUImageCGAColorspaceFilter.java | 67 -- .../GPUImageChromaKeyBlendFilter.java | 110 --- .../gpuimage/GPUImageColorBalanceFilter.java | 197 ----- .../gpuimage/GPUImageColorBlendFilter.java | 66 -- .../GPUImageColorBurnBlendFilter.java | 37 - .../GPUImageColorDodgeBlendFilter.java | 49 -- .../gpuimage/GPUImageColorInvertFilter.java | 38 - .../gpuimage/GPUImageColorMatrixFilter.java | 84 -- .../gpuimage/GPUImageContrastFilter.java | 68 -- .../gpuimage/GPUImageCrosshatchFilter.java | 130 --- .../gpuimage/GPUImageDarkenBlendFilter.java | 37 - .../GPUImageDifferenceBlendFilter.java | 36 - .../gpuimage/GPUImageDilationFilter.java | 305 ------- ...geDirectionalSobelEdgeDetectionFilter.java | 64 -- .../gpuimage/GPUImageDissolveBlendFilter.java | 47 -- .../gpuimage/GPUImageDivideBlendFilter.java | 59 -- .../gpuimage/GPUImageEmbossFilter.java | 54 -- .../GPUImageExclusionBlendFilter.java | 39 - .../gpuimage/GPUImageExposureFilter.java | 66 -- .../gpuimage/GPUImageFalseColorFilter.java | 84 -- .../android/gpuimage/GPUImageFilter.java | 278 ------- .../android/gpuimage/GPUImageFilterGroup.java | 253 ------ .../android/gpuimage/GPUImageGammaFilter.java | 66 -- .../gpuimage/GPUImageGaussianBlurFilter.java | 116 --- .../gpuimage/GPUImageGlassSphereFilter.java | 127 --- .../gpuimage/GPUImageGrayscaleFilter.java | 43 - .../GPUImageHardLightBlendFilter.java | 60 -- .../android/gpuimage/GPUImageHazeFilter.java | 97 --- .../GPUImageHighlightShadowFilter.java | 86 -- .../gpuimage/GPUImageHueBlendFilter.java | 116 --- .../android/gpuimage/GPUImageHueFilter.java | 96 --- .../gpuimage/GPUImageKuwaharaFilter.java | 151 ---- .../gpuimage/GPUImageLaplacianFilter.java | 90 -- .../gpuimage/GPUImageLevelsFilter.java | 130 --- .../gpuimage/GPUImageLightenBlendFilter.java | 37 - .../GPUImageLinearBurnBlendFilter.java | 37 - .../gpuimage/GPUImageLookupFilter.java | 60 -- .../GPUImageLuminosityBlendFilter.java | 66 -- .../gpuimage/GPUImageMixBlendFilter.java | 54 -- .../gpuimage/GPUImageMonochromeFilter.java | 101 --- .../gpuimage/GPUImageMultiplyBlendFilter.java | 37 - .../gpuimage/GPUImageNativeLibrary.java | 27 - .../GPUImageNonMaximumSuppressionFilter.java | 64 -- .../gpuimage/GPUImageNormalBlendFilter.java | 61 -- .../gpuimage/GPUImageOpacityFilter.java | 67 -- .../gpuimage/GPUImageOverlayBlendFilter.java | 58 -- .../gpuimage/GPUImagePixelationFilter.java | 74 -- .../gpuimage/GPUImagePosterizeFilter.java | 63 -- .../gpuimage/GPUImageRGBDilationFilter.java | 301 ------- .../android/gpuimage/GPUImageRGBFilter.java | 94 --- .../android/gpuimage/GPUImageRenderer.java | 340 -------- .../GPUImageSaturationBlendFilter.java | 116 --- .../gpuimage/GPUImageSaturationFilter.java | 72 -- .../gpuimage/GPUImageScreenBlendFilter.java | 37 - .../android/gpuimage/GPUImageSepiaFilter.java | 36 - .../gpuimage/GPUImageSharpenFilter.java | 120 --- .../gpuimage/GPUImageSketchFilter.java | 67 -- .../gpuimage/GPUImageSmoothToonFilter.java | 71 -- .../gpuimage/GPUImageSobelEdgeDetection.java | 70 -- .../GPUImageSobelThresholdFilter.java | 74 -- .../GPUImageSoftLightBlendFilter.java | 37 - .../GPUImageSourceOverBlendFilter.java | 37 - .../GPUImageSphereRefractionFilter.java | 127 --- .../gpuimage/GPUImageSubtractBlendFilter.java | 37 - .../android/gpuimage/GPUImageSwirlFilter.java | 117 --- .../GPUImageThresholdEdgeDetection.java | 20 - .../gpuimage/GPUImageToneCurveFilter.java | 364 --------- .../android/gpuimage/GPUImageToonFilter.java | 121 --- .../gpuimage/GPUImageTwoInputFilter.java | 131 --- .../gpuimage/GPUImageTwoPassFilter.java | 26 - .../GPUImageTwoPassTextureSamplingFilter.java | 63 -- .../android/gpuimage/GPUImageView.java | 456 ----------- .../gpuimage/GPUImageVignetteFilter.java | 108 --- .../GPUImageWeakPixelInclusionFilter.java | 59 -- .../gpuimage/GPUImageWhiteBalanceFilter.java | 91 --- .../android/gpuimage/OpenGlUtils.java | 141 ---- .../android/gpuimage/PixelBuffer.java | 209 ----- .../cyberagent/android/gpuimage/Rotation.java | 54 -- .../gpuimage/util/TextureRotationUtil.java | 96 --- app/build.gradle | 2 +- .../main/java/com/common/util/AppUtils.java | 79 -- .../main/java/com/common/util/ArrayUtils.java | 179 ---- .../java/com/common/util/CollectionUtils.java | 54 -- .../main/java/com/common/util/ListUtils.java | 253 ------ .../main/java/com/common/util/MapUtils.java | 289 ------- .../java/com/common/util/NetWorkUtils.java | 118 --- .../java/com/common/util/ObjectUtils.java | 124 --- .../java/com/common/util/PackageUtils.java | 770 ------------------ .../com/common/util/PreferencesUtils.java | 248 ------ .../java/com/common/util/RandomUtils.java | 247 ------ .../java/com/common/util/ResourceUtils.java | 135 --- .../main/java/com/common/util/ShellUtils.java | 222 ----- .../java/com/common/util/SystemUtils.java | 37 - .../camera/CameraBaseFragmentActivity.java | 21 - .../app/camera/adapter/FilterAdapter.java | 2 +- .../app/camera/ui/PhotoProcessActivity.java | 7 +- .../app/camera/util/GPUImageFilterTools.java | 645 +-------------- .../base/BaseFragmentActivity.java | 28 - .../res/drawable-hdpi/lookup_amatorka.png | Bin 36390 -> 0 bytes app/src/main/res/raw/tone_cuver_sample.acv | Bin 62 -> 0 bytes settings.gradle | 2 +- 120 files changed, 95 insertions(+), 12710 deletions(-) create mode 100644 CLAUDE.md delete mode 100755 Gpu-Image/.gitignore delete mode 100755 Gpu-Image/AndroidManifest.xml delete mode 100755 Gpu-Image/build.gradle delete mode 100755 Gpu-Image/gradle.properties delete mode 100755 Gpu-Image/libs/arm64-v8a/libgpuimage-library.so delete mode 100755 Gpu-Image/libs/armeabi-v7a/libgpuimage-library.so delete mode 100755 Gpu-Image/libs/x86/libgpuimage-library.so delete mode 100755 Gpu-Image/libs/x86_64/libgpuimage-library.so delete mode 100755 Gpu-Image/proguard-project.txt delete mode 100755 Gpu-Image/project.properties delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImage.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImage3x3ConvolutionFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImage3x3TextureSamplingFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageAddBlendFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageAlphaBlendFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageBoxBlurFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageBrightnessFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageBulgeDistortionFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageCGAColorspaceFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageChromaKeyBlendFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageColorBalanceFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageColorBlendFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageColorBurnBlendFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageColorDodgeBlendFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageColorInvertFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageColorMatrixFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageContrastFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageCrosshatchFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageDarkenBlendFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageDifferenceBlendFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageDilationFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageDirectionalSobelEdgeDetectionFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageDissolveBlendFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageDivideBlendFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageEmbossFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageExclusionBlendFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageExposureFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageFalseColorFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageFilterGroup.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageGammaFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageGaussianBlurFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageGlassSphereFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageGrayscaleFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageHardLightBlendFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageHazeFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageHighlightShadowFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageHueBlendFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageHueFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageKuwaharaFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageLaplacianFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageLevelsFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageLightenBlendFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageLinearBurnBlendFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageLookupFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageLuminosityBlendFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageMixBlendFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageMonochromeFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageMultiplyBlendFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageNativeLibrary.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageNonMaximumSuppressionFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageNormalBlendFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageOpacityFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageOverlayBlendFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImagePixelationFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImagePosterizeFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageRGBDilationFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageRGBFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageRenderer.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSaturationBlendFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSaturationFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageScreenBlendFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSepiaFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSharpenFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSketchFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSmoothToonFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSobelEdgeDetection.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSobelThresholdFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSoftLightBlendFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSourceOverBlendFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSphereRefractionFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSubtractBlendFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSwirlFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageThresholdEdgeDetection.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageToneCurveFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageToonFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageTwoInputFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageTwoPassFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageTwoPassTextureSamplingFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageView.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageVignetteFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageWeakPixelInclusionFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageWhiteBalanceFilter.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/OpenGlUtils.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/PixelBuffer.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/Rotation.java delete mode 100755 Gpu-Image/src/jp/co/cyberagent/android/gpuimage/util/TextureRotationUtil.java delete mode 100644 app/src/main/java/com/common/util/AppUtils.java delete mode 100644 app/src/main/java/com/common/util/ArrayUtils.java delete mode 100644 app/src/main/java/com/common/util/CollectionUtils.java delete mode 100644 app/src/main/java/com/common/util/ListUtils.java delete mode 100644 app/src/main/java/com/common/util/MapUtils.java delete mode 100644 app/src/main/java/com/common/util/NetWorkUtils.java delete mode 100644 app/src/main/java/com/common/util/ObjectUtils.java delete mode 100644 app/src/main/java/com/common/util/PackageUtils.java delete mode 100644 app/src/main/java/com/common/util/PreferencesUtils.java delete mode 100644 app/src/main/java/com/common/util/RandomUtils.java delete mode 100644 app/src/main/java/com/common/util/ResourceUtils.java delete mode 100644 app/src/main/java/com/common/util/ShellUtils.java delete mode 100644 app/src/main/java/com/common/util/SystemUtils.java delete mode 100644 app/src/main/java/com/stickercamera/app/camera/CameraBaseFragmentActivity.java delete mode 100644 app/src/main/java/com/stickercamera/base/BaseFragmentActivity.java delete mode 100755 app/src/main/res/drawable-hdpi/lookup_amatorka.png delete mode 100755 app/src/main/res/raw/tone_cuver_sample.acv diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..3a8b8b8 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,62 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Overview + +StickerCamera is an Android app for taking/picking a photo, cropping it square, applying GPU filters, then overlaying movable/scalable/rotatable stickers and positional tags before saving locally. It started as a 2015-era project but the build toolchain and dependencies have since been **modernized** (AGP 8 / AndroidX / Java 17 — see below). The *app logic* is still legacy in places (e.g. legacy `android.hardware.Camera`, no runtime-permission handling), so watch for old patterns even though the toolchain is current. + +## Build & Run + +Gradle multi-module project driven by the wrapper. The toolchain is current: + +- Android Gradle Plugin **8.11.1**, Gradle **8.13**, `compileSdk 36`, `minSdk 26`, `targetSdk 36`. +- **Java 17** source/target. No Retrolambda (lambdas run natively). +- ButterKnife 10.x's annotation processor needs JDK-internal javac APIs; JDK 16+ encapsulates these, so `app/build.gradle` opens them via `--add-exports`/`--add-opens` on `JavaCompile` tasks. Keep that block if you touch the build script. + +```bash +./gradlew assembleDebug # build debug APK -> app/build/outputs/apk/ +./gradlew installDebug # build + install on a connected device/emulator +./gradlew :app:compileDebugJavaWithJavac # fast Java-only compile check +./gradlew clean +./gradlew lint # Android lint +./gradlew connectedAndroidTest # instrumentation tests (require a device/emulator) +``` + +There are effectively no real tests — `app/src/androidTest/.../ApplicationTest.java` is the empty Android Studio stub. Verify changes by running the app on a device. + +## Modules + +`settings.gradle` includes two modules: + +- **`:app`** — the application (package `com.github.skykai.stickercamera`; app classes live under `com.stickercamera`, `com.common`, `com.customview`). +- **`:ImageViewTouch`** — vendored zoomable/pannable image view, used as `com.imagezoom.ImageViewTouch`. The sticker overlay extends this. **Kept vendored on purpose**: the app's `MyImageViewDrawableOverlay`/`MyHighlightView` override many of `ImageViewTouchBase`'s protected methods, and this fork is repackaged to `com.imagezoom`, so it cannot be swapped for the upstream `it.sephiroth.android.library.imagezoom` Maven artifact without rewriting the overlay. + +GPU filters come from the **Maven dependency** `jp.co.cyberagent.android:gpuimage:2.1.0` (wasabeef fork), not a vendored module. Note its package layout: core classes (`GPUImageView`, `GPUImage`, `GPUImageRenderer`) are in `jp.co.cyberagent.android.gpuimage`, while all filter classes (`GPUImageFilter`, `GPUImageToneCurveFilter`, …) are in the **`jp.co.cyberagent.android.gpuimage.filter`** subpackage. + +## Architecture + +### Screen flow +`MainActivity` (gallery of saved creations; opens camera automatically when none exist) → `CameraActivity` (capture) or `AlbumActivity` (pick) → `CameraManager.processPhotoItem()` routes by aspect ratio: square images go straight to `PhotoProcessActivity`, others to `CropPhotoActivity` first. `PhotoProcessActivity` is the editor; `EditTextActivity` is a sub-screen for entering tag text. + +### Core singletons +- **`App`** (Application, registered in manifest) — initializes Universal Image Loader, caches `DisplayMetrics`, and exposes `dp2px`/`px2dp`, screen size, and `getApp()`. Reach global state through `App.getApp()`. +- **`CameraManager`** — opens the camera and keeps a `Stack` of camera-flow activities so the whole flow can be `close()`d at once. `CameraBaseActivity` auto-registers/unregisters with it; editor activities should extend it. +- **`EffectService`** — supplies the ordered list of `FilterEffect`s shown in the filter bar. + +### Photo editor (`PhotoProcessActivity`) — three independent overlay systems +1. **Filters**: a `GPUImageView` renders the bitmap. The app uses only the "原始" (NORMAL) pass and tone-curve `.acv` presets in `app/src/main/res/raw/`. `GPUImageFilterTools` is trimmed to exactly those (`FilterType` enum is NORMAL + `ACV_*`; each `ACV_*` maps to an `R.raw.*` curve via `GPUImageToneCurveFilter`). To add a filter: drop the `.acv`, add a `FilterType`, wire it in `GPUImageFilterTools`, and register it in `EffectService.getLocalFilters()`. +2. **Stickers**: `MyImageViewDrawableOverlay` (extends `ImageViewTouch`) hosts `MyHighlightView` handles drawing `StickerDrawable`s. `EffectUtil` adds/clears stickers and holds the static `addonList` (sticker drawables `R.drawable.sticker1..8`) plus the live overlay state. Add stickers by extending `addonList`. +3. **Tags**: `LabelView` (a positioned `TagItem`) placed via `LabelSelector`; tag text is edited in `EditTextActivity`. + +### Persistence +No database. Saved creations are a `List` serialized to JSON with **fastjson** and stored in SharedPreferences under `AppConstants.FEED_INFO` (via `DataUtils`). Output images are written through `FileUtils` (`getPhotoSavedPath()`), which uses **app-specific external storage** (`Context.getExternalFilesDir(...)`) — this works on all API levels without a storage permission, required because direct writes to public external storage fail under scoped storage / `targetSdk 36`. Universal Image Loader's disk cache uses `AppConstants.APP_IMAGE` and falls back to internal cache when external storage is unavailable. `largeHeap` is enabled because full-res bitmaps are processed in memory. + +### Cross-cutting conventions +- **AndroidX everywhere** — there are no `android.support.*` imports left. +- **`BaseActivity`** (extends `AppCompatActivity`) is the UI base: edge-to-edge via `WindowInsets` (the old SystemBarTint was removed), optional `CommonTitleBar` wiring, and dialog/toast/progress helpers delegated to `ActivityHelper` → `DialogHelper` (toasts are always posted via `runOnUiThread`). New activities should extend `BaseActivity` (or `CameraBaseActivity` inside the camera flow). +- **ButterKnife 10.x** for view injection — `@BindView`/`@OnClick` + `ButterKnife.bind(this)` (the modern API). +- **EventBus (greenrobot 3.x)** for loosely-coupled events between the editor and the main gallery — `@Subscribe`-annotated handlers (e.g. notifying that a new creation was saved). +- Lists use AndroidX **RecyclerView**; FABs use Material **FloatingActionButton**. +- The camera uses the legacy `android.hardware.Camera` API; `CameraHelper` selects `CameraHelperGB` vs `CameraHelperBase` by SDK level. **There is still no runtime-permission handling** (permissions are manifest-only) — a real gap under `targetSdk 36` for `CAMERA`; storage was sidestepped by writing to app-specific dirs instead of requesting `WRITE_EXTERNAL_STORAGE`. +- Reusable, app-agnostic helpers live in `com.common.util` (vendored Trinea android-common utils, pruned to only what the app uses); custom widgets/drawables live in `com.customview`. diff --git a/Gpu-Image/.gitignore b/Gpu-Image/.gitignore deleted file mode 100755 index 85e23b4..0000000 --- a/Gpu-Image/.gitignore +++ /dev/null @@ -1,32 +0,0 @@ -#Android generated -bin -gen -obj - -#Eclipse -#.project -#.classpath -.settings - -#IntelliJ IDEA -.idea -*.iml -*.ipr -*.iws -out - -#Checkstyle -.checkstyle - -#Maven -target -release.properties -pom.xml.* - -#Ant -build.xml -local.properties -proguard.cfg - -#OSX -.DS_Store diff --git a/Gpu-Image/AndroidManifest.xml b/Gpu-Image/AndroidManifest.xml deleted file mode 100755 index 9a40236..0000000 --- a/Gpu-Image/AndroidManifest.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/Gpu-Image/build.gradle b/Gpu-Image/build.gradle deleted file mode 100755 index 9c3a172..0000000 --- a/Gpu-Image/build.gradle +++ /dev/null @@ -1,28 +0,0 @@ -apply plugin: 'com.android.library' - -android { - namespace 'jp.co.cyberagent.android.gpuimage' - compileSdk 36 - - defaultConfig { - minSdk 26 - } - - sourceSets { - main { - manifest.srcFile 'AndroidManifest.xml' - java.srcDirs = ['src'] - resources.srcDirs = ['src'] - jniLibs.srcDirs = ['libs'] - } - } - - compileOptions { - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 - } - - lint { - abortOnError false - } -} diff --git a/Gpu-Image/gradle.properties b/Gpu-Image/gradle.properties deleted file mode 100755 index 9e16223..0000000 --- a/Gpu-Image/gradle.properties +++ /dev/null @@ -1,3 +0,0 @@ -POM_NAME=GPUImage for Android Library -POM_ARTIFACT_ID=gpuimage-library -POM_PACKAGING=aar \ No newline at end of file diff --git a/Gpu-Image/libs/arm64-v8a/libgpuimage-library.so b/Gpu-Image/libs/arm64-v8a/libgpuimage-library.so deleted file mode 100755 index aeada07e37627233f4300872a44366a04e80a2a4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5440 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 diff --git a/Gpu-Image/proguard-project.txt b/Gpu-Image/proguard-project.txt deleted file mode 100755 index f2fe155..0000000 --- a/Gpu-Image/proguard-project.txt +++ /dev/null @@ -1,20 +0,0 @@ -# To enable ProGuard in your project, edit project.properties -# to define the proguard.config property as described in that file. -# -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in ${sdk.dir}/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the ProGuard -# include property in project.properties. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# Add any project specific keep options here: - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} diff --git a/Gpu-Image/project.properties b/Gpu-Image/project.properties deleted file mode 100755 index 93c8c3c..0000000 --- a/Gpu-Image/project.properties +++ /dev/null @@ -1,15 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must be checked in Version Control Systems. -# -# To customize properties used by the Ant build system edit -# "ant.properties", and override values to adapt the script to your -# project structure. -# -# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): -#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt - -# Project target. -target=android-21 -android.library=true diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImage.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImage.java deleted file mode 100755 index e083917..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImage.java +++ /dev/null @@ -1,697 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.annotation.TargetApi; -import android.app.ActivityManager; -import android.content.Context; -import android.content.pm.ConfigurationInfo; -import android.database.Cursor; -import android.graphics.Bitmap; -import android.graphics.Bitmap.CompressFormat; -import android.graphics.BitmapFactory; -import android.graphics.Matrix; -import android.graphics.PixelFormat; -import android.hardware.Camera; -import android.media.ExifInterface; -import android.media.MediaScannerConnection; -import android.net.Uri; -import android.opengl.GLSurfaceView; -import android.os.AsyncTask; -import android.os.Build; -import android.os.Environment; -import android.os.Handler; -import android.provider.MediaStore; -import android.view.Display; -import android.view.WindowManager; - -import java.io.*; -import java.net.URL; -import java.util.List; -import java.util.concurrent.Semaphore; - -/** - * The main accessor for GPUImage functionality. This class helps to do common - * tasks through a simple interface. - */ -public class GPUImage { - private final Context mContext; - private final GPUImageRenderer mRenderer; - private GLSurfaceView mGlSurfaceView; - private GPUImageFilter mFilter; - private Bitmap mCurrentBitmap; - private ScaleType mScaleType = ScaleType.CENTER_CROP; - - /** - * Instantiates a new GPUImage object. - * - * @param context the context - */ - public GPUImage(final Context context) { - if (!supportsOpenGLES2(context)) { - throw new IllegalStateException("OpenGL ES 2.0 is not supported on this phone."); - } - - mContext = context; - mFilter = new GPUImageFilter(); - mRenderer = new GPUImageRenderer(mFilter); - } - - /** - * Checks if OpenGL ES 2.0 is supported on the current device. - * - * @param context the context - * @return true, if successful - */ - private boolean supportsOpenGLES2(final Context context) { - final ActivityManager activityManager = (ActivityManager) - context.getSystemService(Context.ACTIVITY_SERVICE); - final ConfigurationInfo configurationInfo = - activityManager.getDeviceConfigurationInfo(); - return configurationInfo.reqGlEsVersion >= 0x20000; - } - - /** - * Sets the GLSurfaceView which will display the preview. - * - * @param view the GLSurfaceView - */ - public void setGLSurfaceView(final GLSurfaceView view) { - mGlSurfaceView = view; - mGlSurfaceView.setEGLContextClientVersion(2); - mGlSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0); - mGlSurfaceView.getHolder().setFormat(PixelFormat.RGBA_8888); - mGlSurfaceView.setRenderer(mRenderer); - mGlSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); - mGlSurfaceView.requestRender(); - } - - /** - * Request the preview to be rendered again. - */ - public void requestRender() { - if (mGlSurfaceView != null) { - mGlSurfaceView.requestRender(); - } - } - - /** - * Sets the up camera to be connected to GPUImage to get a filtered preview. - * - * @param camera the camera - */ - public void setUpCamera(final Camera camera) { - setUpCamera(camera, 0, false, false); - } - - /** - * Sets the up camera to be connected to GPUImage to get a filtered preview. - * - * @param camera the camera - * @param degrees by how many degrees the image should be rotated - * @param flipHorizontal if the image should be flipped horizontally - * @param flipVertical if the image should be flipped vertically - */ - public void setUpCamera(final Camera camera, final int degrees, final boolean flipHorizontal, - final boolean flipVertical) { - mGlSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY); - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.GINGERBREAD_MR1) { - setUpCameraGingerbread(camera); - } else { - camera.setPreviewCallback(mRenderer); - camera.startPreview(); - } - Rotation rotation = Rotation.NORMAL; - switch (degrees) { - case 90: - rotation = Rotation.ROTATION_90; - break; - case 180: - rotation = Rotation.ROTATION_180; - break; - case 270: - rotation = Rotation.ROTATION_270; - break; - } - mRenderer.setRotationCamera(rotation, flipHorizontal, flipVertical); - } - - @TargetApi(11) - private void setUpCameraGingerbread(final Camera camera) { - mRenderer.setUpSurfaceTexture(camera); - } - - /** - * Sets the filter which should be applied to the image which was (or will - * be) set by setImage(...). - * - * @param filter the new filter - */ - public void setFilter(final GPUImageFilter filter) { - mFilter = filter; - mRenderer.setFilter(mFilter); - requestRender(); - } - - /** - * Sets the image on which the filter should be applied. - * - * @param bitmap the new image - */ - public void setImage(final Bitmap bitmap) { - mCurrentBitmap = bitmap; - mRenderer.setImageBitmap(bitmap, false); - requestRender(); - } - - /** - * This sets the scale type of GPUImage. This has to be run before setting the image. - * If image is set and scale type changed, image needs to be reset. - * - * @param scaleType The new ScaleType - */ - public void setScaleType(ScaleType scaleType) { - mScaleType = scaleType; - mRenderer.setScaleType(scaleType); - mRenderer.deleteImage(); - mCurrentBitmap = null; - requestRender(); - } - - /** - * Sets the rotation of the displayed image. - * - * @param rotation new rotation - */ - public void setRotation(Rotation rotation) { - mRenderer.setRotation(rotation); - } - - /** - * Deletes the current image. - */ - public void deleteImage() { - mRenderer.deleteImage(); - mCurrentBitmap = null; - requestRender(); - } - - /** - * Sets the image on which the filter should be applied from a Uri. - * - * @param uri the uri of the new image - */ - public void setImage(final Uri uri) { - new LoadImageUriTask(this, uri).execute(); - } - - /** - * Sets the image on which the filter should be applied from a File. - * - * @param file the file of the new image - */ - public void setImage(final File file) { - new LoadImageFileTask(this, file).execute(); - } - - private String getPath(final Uri uri) { - String[] projection = { - MediaStore.Images.Media.DATA, - }; - Cursor cursor = mContext.getContentResolver() - .query(uri, projection, null, null, null); - int pathIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); - String path = null; - if (cursor.moveToFirst()) { - path = cursor.getString(pathIndex); - } - cursor.close(); - return path; - } - - /** - * Gets the current displayed image with applied filter as a Bitmap. - * - * @return the current image with filter applied - */ - public Bitmap getBitmapWithFilterApplied() { - return getBitmapWithFilterApplied(mCurrentBitmap); - } - - /** - * Gets the given bitmap with current filter applied as a Bitmap. - * - * @param bitmap the bitmap on which the current filter should be applied - * @return the bitmap with filter applied - */ - public Bitmap getBitmapWithFilterApplied(final Bitmap bitmap) { - if (mGlSurfaceView != null) { - mRenderer.deleteImage(); - mRenderer.runOnDraw(new Runnable() { - - @Override - public void run() { - synchronized(mFilter) { - mFilter.destroy(); - mFilter.notify(); - } - } - }); - synchronized(mFilter) { - requestRender(); - try { - mFilter.wait(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - - GPUImageRenderer renderer = new GPUImageRenderer(mFilter); - renderer.setRotation(Rotation.NORMAL, - mRenderer.isFlippedHorizontally(), mRenderer.isFlippedVertically()); - renderer.setScaleType(mScaleType); - PixelBuffer buffer = new PixelBuffer(bitmap.getWidth(), bitmap.getHeight()); - buffer.setRenderer(renderer); - renderer.setImageBitmap(bitmap, false); - Bitmap result = buffer.getBitmap(); - mFilter.destroy(); - renderer.deleteImage(); - buffer.destroy(); - - mRenderer.setFilter(mFilter); - if (mCurrentBitmap != null) { - mRenderer.setImageBitmap(mCurrentBitmap, false); - } - requestRender(); - - return result; - } - - /** - * Gets the images for multiple filters on a image. This can be used to - * quickly get thumbnail images for filters.
    - * Whenever a new Bitmap is ready, the listener will be called with the - * bitmap. The order of the calls to the listener will be the same as the - * filter order. - * - * @param bitmap the bitmap on which the filters will be applied - * @param filters the filters which will be applied on the bitmap - * @param listener the listener on which the results will be notified - */ - public static void getBitmapForMultipleFilters(final Bitmap bitmap, - final List filters, final ResponseListener listener) { - if (filters.isEmpty()) { - return; - } - GPUImageRenderer renderer = new GPUImageRenderer(filters.get(0)); - renderer.setImageBitmap(bitmap, false); - PixelBuffer buffer = new PixelBuffer(bitmap.getWidth(), bitmap.getHeight()); - buffer.setRenderer(renderer); - - for (GPUImageFilter filter : filters) { - renderer.setFilter(filter); - listener.response(buffer.getBitmap()); - filter.destroy(); - } - renderer.deleteImage(); - buffer.destroy(); - } - - /** - * Deprecated: Please use - * {@link GPUImageView#saveToPictures(String, String, jp.co.cyberagent.android.gpuimage.GPUImageView.OnPictureSavedListener)} - * - * Save current image with applied filter to Pictures. It will be stored on - * the default Picture folder on the phone below the given folderName and - * fileName.
    - * This method is async and will notify when the image was saved through the - * listener. - * - * @param folderName the folder name - * @param fileName the file name - * @param listener the listener - */ - @Deprecated - public void saveToPictures(final String folderName, final String fileName, - final OnPictureSavedListener listener) { - saveToPictures(mCurrentBitmap, folderName, fileName, listener); - } - - /** - * Deprecated: Please use - * {@link GPUImageView#saveToPictures(String, String, jp.co.cyberagent.android.gpuimage.GPUImageView.OnPictureSavedListener)} - * - * Apply and save the given bitmap with applied filter to Pictures. It will - * be stored on the default Picture folder on the phone below the given - * folerName and fileName.
    - * This method is async and will notify when the image was saved through the - * listener. - * - * @param bitmap the bitmap - * @param folderName the folder name - * @param fileName the file name - * @param listener the listener - */ - @Deprecated - public void saveToPictures(final Bitmap bitmap, final String folderName, final String fileName, - final OnPictureSavedListener listener) { - new SaveTask(bitmap, folderName, fileName, listener).execute(); - } - - /** - * Runs the given Runnable on the OpenGL thread. - * - * @param runnable The runnable to be run on the OpenGL thread. - */ - void runOnGLThread(Runnable runnable) { - mRenderer.runOnDrawEnd(runnable); - } - - private int getOutputWidth() { - if (mRenderer != null && mRenderer.getFrameWidth() != 0) { - return mRenderer.getFrameWidth(); - } else if (mCurrentBitmap != null) { - return mCurrentBitmap.getWidth(); - } else { - WindowManager windowManager = - (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); - Display display = windowManager.getDefaultDisplay(); - return display.getWidth(); - } - } - - private int getOutputHeight() { - if (mRenderer != null && mRenderer.getFrameHeight() != 0) { - return mRenderer.getFrameHeight(); - } else if (mCurrentBitmap != null) { - return mCurrentBitmap.getHeight(); - } else { - WindowManager windowManager = - (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); - Display display = windowManager.getDefaultDisplay(); - return display.getHeight(); - } - } - - @Deprecated - private class SaveTask extends AsyncTask { - - private final Bitmap mBitmap; - private final String mFolderName; - private final String mFileName; - private final OnPictureSavedListener mListener; - private final Handler mHandler; - - public SaveTask(final Bitmap bitmap, final String folderName, final String fileName, - final OnPictureSavedListener listener) { - mBitmap = bitmap; - mFolderName = folderName; - mFileName = fileName; - mListener = listener; - mHandler = new Handler(); - } - - @Override - protected Void doInBackground(final Void... params) { - Bitmap result = getBitmapWithFilterApplied(mBitmap); - saveImage(mFolderName, mFileName, result); - return null; - } - - private void saveImage(final String folderName, final String fileName, final Bitmap image) { - File path = Environment - .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); - File file = new File(path, folderName + "/" + fileName); - try { - file.getParentFile().mkdirs(); - image.compress(CompressFormat.JPEG, 80, new FileOutputStream(file)); - MediaScannerConnection.scanFile(mContext, - new String[] { - file.toString() - }, null, - new MediaScannerConnection.OnScanCompletedListener() { - @Override - public void onScanCompleted(final String path, final Uri uri) { - if (mListener != null) { - mHandler.post(new Runnable() { - - @Override - public void run() { - mListener.onPictureSaved(uri); - } - }); - } - } - }); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } - } - } - - public interface OnPictureSavedListener { - void onPictureSaved(Uri uri); - } - - private class LoadImageUriTask extends LoadImageTask { - - private final Uri mUri; - - public LoadImageUriTask(GPUImage gpuImage, Uri uri) { - super(gpuImage); - mUri = uri; - } - - @Override - protected Bitmap decode(BitmapFactory.Options options) { - try { - InputStream inputStream; - if (mUri.getScheme().startsWith("http") || mUri.getScheme().startsWith("https")) { - inputStream = new URL(mUri.toString()).openStream(); - } else { - inputStream = mContext.getContentResolver().openInputStream(mUri); - } - return BitmapFactory.decodeStream(inputStream, null, options); - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - @Override - protected int getImageOrientation() throws IOException { - Cursor cursor = mContext.getContentResolver().query(mUri, - new String[] { MediaStore.Images.ImageColumns.ORIENTATION }, null, null, null); - - if (cursor == null || cursor.getCount() != 1) { - return 0; - } - - cursor.moveToFirst(); - int orientation = cursor.getInt(0); - cursor.close(); - return orientation; - } - } - - private class LoadImageFileTask extends LoadImageTask { - - private final File mImageFile; - - public LoadImageFileTask(GPUImage gpuImage, File file) { - super(gpuImage); - mImageFile = file; - } - - @Override - protected Bitmap decode(BitmapFactory.Options options) { - return BitmapFactory.decodeFile(mImageFile.getAbsolutePath(), options); - } - - @Override - protected int getImageOrientation() throws IOException { - ExifInterface exif = new ExifInterface(mImageFile.getAbsolutePath()); - int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1); - switch (orientation) { - case ExifInterface.ORIENTATION_NORMAL: - return 0; - case ExifInterface.ORIENTATION_ROTATE_90: - return 90; - case ExifInterface.ORIENTATION_ROTATE_180: - return 180; - case ExifInterface.ORIENTATION_ROTATE_270: - return 270; - default: - return 0; - } - } - } - - private abstract class LoadImageTask extends AsyncTask { - - private final GPUImage mGPUImage; - private int mOutputWidth; - private int mOutputHeight; - - @SuppressWarnings("deprecation") - public LoadImageTask(final GPUImage gpuImage) { - mGPUImage = gpuImage; - } - - @Override - protected Bitmap doInBackground(Void... params) { - if (mRenderer != null && mRenderer.getFrameWidth() == 0) { - try { - synchronized (mRenderer.mSurfaceChangedWaiter) { - mRenderer.mSurfaceChangedWaiter.wait(3000); - } - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - mOutputWidth = getOutputWidth(); - mOutputHeight = getOutputHeight(); - return loadResizedImage(); - } - - @Override - protected void onPostExecute(Bitmap bitmap) { - super.onPostExecute(bitmap); - mGPUImage.deleteImage(); - mGPUImage.setImage(bitmap); - } - - protected abstract Bitmap decode(BitmapFactory.Options options); - - private Bitmap loadResizedImage() { - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inJustDecodeBounds = true; - decode(options); - int scale = 1; - while (checkSize(options.outWidth / scale > mOutputWidth, options.outHeight / scale > mOutputHeight)) { - scale++; - } - - scale--; - if (scale < 1) { - scale = 1; - } - options = new BitmapFactory.Options(); - options.inSampleSize = scale; - options.inPreferredConfig = Bitmap.Config.RGB_565; - options.inPurgeable = true; - options.inTempStorage = new byte[32 * 1024]; - Bitmap bitmap = decode(options); - if (bitmap == null) { - return null; - } - bitmap = rotateImage(bitmap); - bitmap = scaleBitmap(bitmap); - return bitmap; - } - - private Bitmap scaleBitmap(Bitmap bitmap) { - // resize to desired dimensions - int width = bitmap.getWidth(); - int height = bitmap.getHeight(); - int[] newSize = getScaleSize(width, height); - Bitmap workBitmap = Bitmap.createScaledBitmap(bitmap, newSize[0], newSize[1], true); - if (workBitmap != bitmap) { - bitmap.recycle(); - bitmap = workBitmap; - System.gc(); - } - - if (mScaleType == ScaleType.CENTER_CROP) { - // Crop it - int diffWidth = newSize[0] - mOutputWidth; - int diffHeight = newSize[1] - mOutputHeight; - workBitmap = Bitmap.createBitmap(bitmap, diffWidth / 2, diffHeight / 2, - newSize[0] - diffWidth, newSize[1] - diffHeight); - if (workBitmap != bitmap) { - bitmap.recycle(); - bitmap = workBitmap; - } - } - - return bitmap; - } - - /** - * Retrieve the scaling size for the image dependent on the ScaleType.
    - *
    - * If CROP: sides are same size or bigger than output's sides
    - * Else : sides are same size or smaller than output's sides - */ - private int[] getScaleSize(int width, int height) { - float newWidth; - float newHeight; - - float withRatio = (float) width / mOutputWidth; - float heightRatio = (float) height / mOutputHeight; - - boolean adjustWidth = mScaleType == ScaleType.CENTER_CROP - ? withRatio > heightRatio : withRatio < heightRatio; - - if (adjustWidth) { - newHeight = mOutputHeight; - newWidth = (newHeight / height) * width; - } else { - newWidth = mOutputWidth; - newHeight = (newWidth / width) * height; - } - return new int[]{Math.round(newWidth), Math.round(newHeight)}; - } - - private boolean checkSize(boolean widthBigger, boolean heightBigger) { - if (mScaleType == ScaleType.CENTER_CROP) { - return widthBigger && heightBigger; - } else { - return widthBigger || heightBigger; - } - } - - private Bitmap rotateImage(final Bitmap bitmap) { - if (bitmap == null) { - return null; - } - Bitmap rotatedBitmap = bitmap; - try { - int orientation = getImageOrientation(); - if (orientation != 0) { - Matrix matrix = new Matrix(); - matrix.postRotate(orientation); - rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), - bitmap.getHeight(), matrix, true); - bitmap.recycle(); - } - } catch (IOException e) { - e.printStackTrace(); - } - return rotatedBitmap; - } - - protected abstract int getImageOrientation() throws IOException; - } - - public interface ResponseListener { - void response(T item); - } - - public enum ScaleType { CENTER_INSIDE, CENTER_CROP } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImage3x3ConvolutionFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImage3x3ConvolutionFilter.java deleted file mode 100755 index 0c5e5a0..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImage3x3ConvolutionFilter.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; - -/** - * Runs a 3x3 convolution kernel against the image - */ -public class GPUImage3x3ConvolutionFilter extends GPUImage3x3TextureSamplingFilter { - public static final String THREE_X_THREE_TEXTURE_SAMPLING_FRAGMENT_SHADER = "" + - "precision highp float;\n" + - "\n" + - "uniform sampler2D inputImageTexture;\n" + - "\n" + - "uniform mediump mat3 convolutionMatrix;\n" + - "\n" + - "varying vec2 textureCoordinate;\n" + - "varying vec2 leftTextureCoordinate;\n" + - "varying vec2 rightTextureCoordinate;\n" + - "\n" + - "varying vec2 topTextureCoordinate;\n" + - "varying vec2 topLeftTextureCoordinate;\n" + - "varying vec2 topRightTextureCoordinate;\n" + - "\n" + - "varying vec2 bottomTextureCoordinate;\n" + - "varying vec2 bottomLeftTextureCoordinate;\n" + - "varying vec2 bottomRightTextureCoordinate;\n" + - "\n" + - "void main()\n" + - "{\n" + - " mediump vec4 bottomColor = texture2D(inputImageTexture, bottomTextureCoordinate);\n" + - " mediump vec4 bottomLeftColor = texture2D(inputImageTexture, bottomLeftTextureCoordinate);\n" + - " mediump vec4 bottomRightColor = texture2D(inputImageTexture, bottomRightTextureCoordinate);\n" + - " mediump vec4 centerColor = texture2D(inputImageTexture, textureCoordinate);\n" + - " mediump vec4 leftColor = texture2D(inputImageTexture, leftTextureCoordinate);\n" + - " mediump vec4 rightColor = texture2D(inputImageTexture, rightTextureCoordinate);\n" + - " mediump vec4 topColor = texture2D(inputImageTexture, topTextureCoordinate);\n" + - " mediump vec4 topRightColor = texture2D(inputImageTexture, topRightTextureCoordinate);\n" + - " mediump vec4 topLeftColor = texture2D(inputImageTexture, topLeftTextureCoordinate);\n" + - "\n" + - " mediump vec4 resultColor = topLeftColor * convolutionMatrix[0][0] + topColor * convolutionMatrix[0][1] + topRightColor * convolutionMatrix[0][2];\n" + - " resultColor += leftColor * convolutionMatrix[1][0] + centerColor * convolutionMatrix[1][1] + rightColor * convolutionMatrix[1][2];\n" + - " resultColor += bottomLeftColor * convolutionMatrix[2][0] + bottomColor * convolutionMatrix[2][1] + bottomRightColor * convolutionMatrix[2][2];\n" + - "\n" + - " gl_FragColor = resultColor;\n" + - "}"; - - private float[] mConvolutionKernel; - private int mUniformConvolutionMatrix; - - /** - * Instantiates a new GPUimage3x3ConvolutionFilter with default values, that - * will look like the original image. - */ - public GPUImage3x3ConvolutionFilter() { - this(new float[] { - 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f - }); - } - - /** - * Instantiates a new GPUimage3x3ConvolutionFilter with given convolution kernel. - * - * @param convolutionKernel the convolution kernel - */ - public GPUImage3x3ConvolutionFilter(final float[] convolutionKernel) { - super(THREE_X_THREE_TEXTURE_SAMPLING_FRAGMENT_SHADER); - mConvolutionKernel = convolutionKernel; - } - - @Override - public void onInit() { - super.onInit(); - mUniformConvolutionMatrix = GLES20.glGetUniformLocation(getProgram(), "convolutionMatrix"); - setConvolutionKernel(mConvolutionKernel); - } - - /** - * Sets the convolution kernel. - * - * @param convolutionKernel the new convolution kernel - */ - public void setConvolutionKernel(final float[] convolutionKernel) { - mConvolutionKernel = convolutionKernel; - setUniformMatrix3f(mUniformConvolutionMatrix, mConvolutionKernel); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImage3x3TextureSamplingFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImage3x3TextureSamplingFilter.java deleted file mode 100755 index 2e6820a..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImage3x3TextureSamplingFilter.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; - -public class GPUImage3x3TextureSamplingFilter extends GPUImageFilter { - public static final String THREE_X_THREE_TEXTURE_SAMPLING_VERTEX_SHADER = "" + - "attribute vec4 position;\n" + - "attribute vec4 inputTextureCoordinate;\n" + - "\n" + - "uniform highp float texelWidth; \n" + - "uniform highp float texelHeight; \n" + - "\n" + - "varying vec2 textureCoordinate;\n" + - "varying vec2 leftTextureCoordinate;\n" + - "varying vec2 rightTextureCoordinate;\n" + - "\n" + - "varying vec2 topTextureCoordinate;\n" + - "varying vec2 topLeftTextureCoordinate;\n" + - "varying vec2 topRightTextureCoordinate;\n" + - "\n" + - "varying vec2 bottomTextureCoordinate;\n" + - "varying vec2 bottomLeftTextureCoordinate;\n" + - "varying vec2 bottomRightTextureCoordinate;\n" + - "\n" + - "void main()\n" + - "{\n" + - " gl_Position = position;\n" + - "\n" + - " vec2 widthStep = vec2(texelWidth, 0.0);\n" + - " vec2 heightStep = vec2(0.0, texelHeight);\n" + - " vec2 widthHeightStep = vec2(texelWidth, texelHeight);\n" + - " vec2 widthNegativeHeightStep = vec2(texelWidth, -texelHeight);\n" + - "\n" + - " textureCoordinate = inputTextureCoordinate.xy;\n" + - " leftTextureCoordinate = inputTextureCoordinate.xy - widthStep;\n" + - " rightTextureCoordinate = inputTextureCoordinate.xy + widthStep;\n" + - "\n" + - " topTextureCoordinate = inputTextureCoordinate.xy - heightStep;\n" + - " topLeftTextureCoordinate = inputTextureCoordinate.xy - widthHeightStep;\n" + - " topRightTextureCoordinate = inputTextureCoordinate.xy + widthNegativeHeightStep;\n" + - "\n" + - " bottomTextureCoordinate = inputTextureCoordinate.xy + heightStep;\n" + - " bottomLeftTextureCoordinate = inputTextureCoordinate.xy - widthNegativeHeightStep;\n" + - " bottomRightTextureCoordinate = inputTextureCoordinate.xy + widthHeightStep;\n" + - "}"; - - private int mUniformTexelWidthLocation; - private int mUniformTexelHeightLocation; - - private boolean mHasOverriddenImageSizeFactor = false; - private float mTexelWidth; - private float mTexelHeight; - private float mLineSize = 1.0f; - - public GPUImage3x3TextureSamplingFilter() { - this(NO_FILTER_VERTEX_SHADER); - } - - public GPUImage3x3TextureSamplingFilter(final String fragmentShader) { - super(THREE_X_THREE_TEXTURE_SAMPLING_VERTEX_SHADER, fragmentShader); - } - - @Override - public void onInit() { - super.onInit(); - mUniformTexelWidthLocation = GLES20.glGetUniformLocation(getProgram(), "texelWidth"); - mUniformTexelHeightLocation = GLES20.glGetUniformLocation(getProgram(), "texelHeight"); - if (mTexelWidth != 0) { - updateTexelValues(); - } - } - - @Override - public void onOutputSizeChanged(final int width, final int height) { - super.onOutputSizeChanged(width, height); - if (!mHasOverriddenImageSizeFactor) { - setLineSize(mLineSize); - } - } - - public void setTexelWidth(final float texelWidth) { - mHasOverriddenImageSizeFactor = true; - mTexelWidth = texelWidth; - setFloat(mUniformTexelWidthLocation, texelWidth); - } - - public void setTexelHeight(final float texelHeight) { - mHasOverriddenImageSizeFactor = true; - mTexelHeight = texelHeight; - setFloat(mUniformTexelHeightLocation, texelHeight); - } - - public void setLineSize(final float size) { - mLineSize = size; - mTexelWidth = size / getOutputWidth(); - mTexelHeight = size / getOutputHeight(); - updateTexelValues(); - } - - private void updateTexelValues() { - setFloat(mUniformTexelWidthLocation, mTexelWidth); - setFloat(mUniformTexelHeightLocation, mTexelHeight); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageAddBlendFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageAddBlendFilter.java deleted file mode 100755 index 59dcb34..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageAddBlendFilter.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -public class GPUImageAddBlendFilter extends GPUImageTwoInputFilter { - public static final String ADD_BLEND_FRAGMENT_SHADER = "varying highp vec2 textureCoordinate;\n" + - " varying highp vec2 textureCoordinate2;\n" + - "\n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform sampler2D inputImageTexture2;\n" + - " \n" + - " void main()\n" + - " {\n" + - " lowp vec4 base = texture2D(inputImageTexture, textureCoordinate);\n" + - " lowp vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);\n" + - "\n" + - " mediump float r;\n" + - " if (overlay.r * base.a + base.r * overlay.a >= overlay.a * base.a) {\n" + - " r = overlay.a * base.a + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);\n" + - " } else {\n" + - " r = overlay.r + base.r;\n" + - " }\n" + - "\n" + - " mediump float g;\n" + - " if (overlay.g * base.a + base.g * overlay.a >= overlay.a * base.a) {\n" + - " g = overlay.a * base.a + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);\n" + - " } else {\n" + - " g = overlay.g + base.g;\n" + - " }\n" + - "\n" + - " mediump float b;\n" + - " if (overlay.b * base.a + base.b * overlay.a >= overlay.a * base.a) {\n" + - " b = overlay.a * base.a + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);\n" + - " } else {\n" + - " b = overlay.b + base.b;\n" + - " }\n" + - "\n" + - " mediump float a = overlay.a + base.a - overlay.a * base.a;\n" + - " \n" + - " gl_FragColor = vec4(r, g, b, a);\n" + - " }"; - - public GPUImageAddBlendFilter() { - super(ADD_BLEND_FRAGMENT_SHADER); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageAlphaBlendFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageAlphaBlendFilter.java deleted file mode 100755 index 753c24d..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageAlphaBlendFilter.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -/** - * Mix ranges from 0.0 (only image 1) to 1.0 (only image 2), with 0.5 (half of either) as the normal level - */ -public class GPUImageAlphaBlendFilter extends GPUImageMixBlendFilter{ - public static final String ALPHA_BLEND_FRAGMENT_SHADER = "varying highp vec2 textureCoordinate;\n" + - " varying highp vec2 textureCoordinate2;\n" + - "\n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform sampler2D inputImageTexture2;\n" + - " \n" + - " uniform lowp float mixturePercent;\n" + - "\n" + - " void main()\n" + - " {\n" + - " lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + - " lowp vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);\n" + - "\n" + - " gl_FragColor = vec4(mix(textureColor.rgb, textureColor2.rgb, textureColor2.a * mixturePercent), textureColor.a);\n" + - " }"; - - public GPUImageAlphaBlendFilter() { - super(ALPHA_BLEND_FRAGMENT_SHADER); - } - - public GPUImageAlphaBlendFilter(float mix) { - super(ALPHA_BLEND_FRAGMENT_SHADER, mix); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageBoxBlurFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageBoxBlurFilter.java deleted file mode 100755 index 4e681b3..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageBoxBlurFilter.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -/** - * A hardware-accelerated 9-hit box blur of an image - * - * scaling: for the size of the applied blur, default of 1.0 - */ -public class GPUImageBoxBlurFilter extends GPUImageTwoPassTextureSamplingFilter { - public static final String VERTEX_SHADER = - "attribute vec4 position;\n" + - "attribute vec2 inputTextureCoordinate;\n" + - "\n" + - "uniform float texelWidthOffset; \n" + - "uniform float texelHeightOffset; \n" + - "\n" + - "varying vec2 centerTextureCoordinate;\n" + - "varying vec2 oneStepLeftTextureCoordinate;\n" + - "varying vec2 twoStepsLeftTextureCoordinate;\n" + - "varying vec2 oneStepRightTextureCoordinate;\n" + - "varying vec2 twoStepsRightTextureCoordinate;\n" + - "\n" + - "void main()\n" + - "{\n" + - "gl_Position = position;\n" + - "\n" + - "vec2 firstOffset = vec2(1.5 * texelWidthOffset, 1.5 * texelHeightOffset);\n" + - "vec2 secondOffset = vec2(3.5 * texelWidthOffset, 3.5 * texelHeightOffset);\n" + - "\n" + - "centerTextureCoordinate = inputTextureCoordinate;\n" + - "oneStepLeftTextureCoordinate = inputTextureCoordinate - firstOffset;\n" + - "twoStepsLeftTextureCoordinate = inputTextureCoordinate - secondOffset;\n" + - "oneStepRightTextureCoordinate = inputTextureCoordinate + firstOffset;\n" + - "twoStepsRightTextureCoordinate = inputTextureCoordinate + secondOffset;\n" + - "}\n"; - - public static final String FRAGMENT_SHADER = - "precision highp float;\n" + - "\n" + - "uniform sampler2D inputImageTexture;\n" + - "\n" + - "varying vec2 centerTextureCoordinate;\n" + - "varying vec2 oneStepLeftTextureCoordinate;\n" + - "varying vec2 twoStepsLeftTextureCoordinate;\n" + - "varying vec2 oneStepRightTextureCoordinate;\n" + - "varying vec2 twoStepsRightTextureCoordinate;\n" + - "\n" + - "void main()\n" + - "{\n" + - "lowp vec4 fragmentColor = texture2D(inputImageTexture, centerTextureCoordinate) * 0.2;\n" + - "fragmentColor += texture2D(inputImageTexture, oneStepLeftTextureCoordinate) * 0.2;\n" + - "fragmentColor += texture2D(inputImageTexture, oneStepRightTextureCoordinate) * 0.2;\n" + - "fragmentColor += texture2D(inputImageTexture, twoStepsLeftTextureCoordinate) * 0.2;\n" + - "fragmentColor += texture2D(inputImageTexture, twoStepsRightTextureCoordinate) * 0.2;\n" + - "\n" + - "gl_FragColor = fragmentColor;\n" + - "}\n"; - - private float blurSize = 1f; - - /** - * Construct new BoxBlurFilter with default blur size of 1.0. - */ - public GPUImageBoxBlurFilter() { - this(1f); - } - - - public GPUImageBoxBlurFilter(float blurSize) { - super(VERTEX_SHADER, FRAGMENT_SHADER, VERTEX_SHADER, FRAGMENT_SHADER); - this.blurSize = blurSize; - } - - /** - * A scaling for the size of the applied blur, default of 1.0 - * - * @param blurSize - */ - public void setBlurSize(float blurSize) { - this.blurSize = blurSize; - runOnDraw(new Runnable() { - @Override - public void run() { - initTexelOffsets(); - } - }); - } - - @Override - public float getVerticalTexelOffsetRatio() { - return blurSize; - } - - @Override - public float getHorizontalTexelOffsetRatio() { - return blurSize; - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageBrightnessFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageBrightnessFilter.java deleted file mode 100755 index e528ee8..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageBrightnessFilter.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; - -/** - * brightness value ranges from -1.0 to 1.0, with 0.0 as the normal level - */ -public class GPUImageBrightnessFilter extends GPUImageFilter { - public static final String BRIGHTNESS_FRAGMENT_SHADER = "" + - "varying highp vec2 textureCoordinate;\n" + - " \n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform lowp float brightness;\n" + - " \n" + - " void main()\n" + - " {\n" + - " lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + - " \n" + - " gl_FragColor = vec4((textureColor.rgb + vec3(brightness)), textureColor.w);\n" + - " }"; - - private int mBrightnessLocation; - private float mBrightness; - - public GPUImageBrightnessFilter() { - this(0.0f); - } - - public GPUImageBrightnessFilter(final float brightness) { - super(NO_FILTER_VERTEX_SHADER, BRIGHTNESS_FRAGMENT_SHADER); - mBrightness = brightness; - } - - @Override - public void onInit() { - super.onInit(); - mBrightnessLocation = GLES20.glGetUniformLocation(getProgram(), "brightness"); - } - - @Override - public void onInitialized() { - super.onInitialized(); - setBrightness(mBrightness); - } - - public void setBrightness(final float brightness) { - mBrightness = brightness; - setFloat(mBrightnessLocation, mBrightness); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageBulgeDistortionFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageBulgeDistortionFilter.java deleted file mode 100755 index af49bed..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageBulgeDistortionFilter.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.graphics.PointF; -import android.opengl.GLES20; - -public class GPUImageBulgeDistortionFilter extends GPUImageFilter { - public static final String BULGE_FRAGMENT_SHADER = "" + - "varying highp vec2 textureCoordinate;\n" + - "\n" + - "uniform sampler2D inputImageTexture;\n" + - "\n" + - "uniform highp float aspectRatio;\n" + - "uniform highp vec2 center;\n" + - "uniform highp float radius;\n" + - "uniform highp float scale;\n" + - "\n" + - "void main()\n" + - "{\n" + - "highp vec2 textureCoordinateToUse = vec2(textureCoordinate.x, (textureCoordinate.y * aspectRatio + 0.5 - 0.5 * aspectRatio));\n" + - "highp float dist = distance(center, textureCoordinateToUse);\n" + - "textureCoordinateToUse = textureCoordinate;\n" + - "\n" + - "if (dist < radius)\n" + - "{\n" + - "textureCoordinateToUse -= center;\n" + - "highp float percent = 1.0 - ((radius - dist) / radius) * scale;\n" + - "percent = percent * percent;\n" + - "\n" + - "textureCoordinateToUse = textureCoordinateToUse * percent;\n" + - "textureCoordinateToUse += center;\n" + - "}\n" + - "\n" + - "gl_FragColor = texture2D(inputImageTexture, textureCoordinateToUse ); \n" + - "}\n"; - - private float mScale; - private int mScaleLocation; - private float mRadius; - private int mRadiusLocation; - private PointF mCenter; - private int mCenterLocation; - private float mAspectRatio; - private int mAspectRatioLocation; - - public GPUImageBulgeDistortionFilter() { - this(0.25f, 0.5f, new PointF(0.5f, 0.5f)); - } - - public GPUImageBulgeDistortionFilter(float radius, float scale, PointF center) { - super(NO_FILTER_VERTEX_SHADER, BULGE_FRAGMENT_SHADER); - mRadius = radius; - mScale = scale; - mCenter = center; - } - - @Override - public void onInit() { - super.onInit(); - mScaleLocation = GLES20.glGetUniformLocation(getProgram(), "scale"); - mRadiusLocation = GLES20.glGetUniformLocation(getProgram(), "radius"); - mCenterLocation = GLES20.glGetUniformLocation(getProgram(), "center"); - mAspectRatioLocation = GLES20.glGetUniformLocation(getProgram(), "aspectRatio"); - } - - @Override - public void onInitialized() { - super.onInitialized(); - setRadius(mRadius); - setScale(mScale); - setCenter(mCenter); - } - - @Override - public void onOutputSizeChanged(int width, int height) { - mAspectRatio = (float) height / width; - setAspectRatio(mAspectRatio); - super.onOutputSizeChanged(width, height); - } - - private void setAspectRatio(float aspectRatio) { - mAspectRatio = aspectRatio; - setFloat(mAspectRatioLocation, aspectRatio); - } - - /** - * The radius of the distortion, ranging from 0.0 to 1.0, with a default of 0.25 - * - * @param radius from 0.0 to 1.0, default 0.25 - */ - public void setRadius(float radius) { - mRadius = radius; - setFloat(mRadiusLocation, radius); - } - - /** - * The amount of distortion to apply, from -1.0 to 1.0, with a default of 0.5 - * - * @param scale from -1.0 to 1.0, default 0.5 - */ - public void setScale(float scale) { - mScale = scale; - setFloat(mScaleLocation, scale); - } - - /** - * The center about which to apply the distortion, with a default of (0.5, 0.5) - * - * @param center default (0.5, 0.5) - */ - public void setCenter(PointF center) { - mCenter = center; - setPoint(mCenterLocation, center); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageCGAColorspaceFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageCGAColorspaceFilter.java deleted file mode 100755 index 5258595..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageCGAColorspaceFilter.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -public class GPUImageCGAColorspaceFilter extends GPUImageFilter { - public static final String CGACOLORSPACE_FRAGMENT_SHADER = "" + - "varying highp vec2 textureCoordinate;\n" + - "\n" + - "uniform sampler2D inputImageTexture;\n" + - "\n" + - "void main()\n" + - "{\n" + - "highp vec2 sampleDivisor = vec2(1.0 / 200.0, 1.0 / 320.0);\n" + - "//highp vec4 colorDivisor = vec4(colorDepth);\n" + - "\n" + - "highp vec2 samplePos = textureCoordinate - mod(textureCoordinate, sampleDivisor);\n" + - "highp vec4 color = texture2D(inputImageTexture, samplePos );\n" + - "\n" + - "//gl_FragColor = texture2D(inputImageTexture, samplePos );\n" + - "mediump vec4 colorCyan = vec4(85.0 / 255.0, 1.0, 1.0, 1.0);\n" + - "mediump vec4 colorMagenta = vec4(1.0, 85.0 / 255.0, 1.0, 1.0);\n" + - "mediump vec4 colorWhite = vec4(1.0, 1.0, 1.0, 1.0);\n" + - "mediump vec4 colorBlack = vec4(0.0, 0.0, 0.0, 1.0);\n" + - "\n" + - "mediump vec4 endColor;\n" + - "highp float blackDistance = distance(color, colorBlack);\n" + - "highp float whiteDistance = distance(color, colorWhite);\n" + - "highp float magentaDistance = distance(color, colorMagenta);\n" + - "highp float cyanDistance = distance(color, colorCyan);\n" + - "\n" + - "mediump vec4 finalColor;\n" + - "\n" + - "highp float colorDistance = min(magentaDistance, cyanDistance);\n" + - "colorDistance = min(colorDistance, whiteDistance);\n" + - "colorDistance = min(colorDistance, blackDistance); \n" + - "\n" + - "if (colorDistance == blackDistance) {\n" + - "finalColor = colorBlack;\n" + - "} else if (colorDistance == whiteDistance) {\n" + - "finalColor = colorWhite;\n" + - "} else if (colorDistance == cyanDistance) {\n" + - "finalColor = colorCyan;\n" + - "} else {\n" + - "finalColor = colorMagenta;\n" + - "}\n" + - "\n" + - "gl_FragColor = finalColor;\n" + - "}\n"; - - public GPUImageCGAColorspaceFilter() { - super(NO_FILTER_VERTEX_SHADER, CGACOLORSPACE_FRAGMENT_SHADER); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageChromaKeyBlendFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageChromaKeyBlendFilter.java deleted file mode 100755 index 7957b05..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageChromaKeyBlendFilter.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; - -/** - * Selectively replaces a color in the first image with the second image - */ -public class GPUImageChromaKeyBlendFilter extends GPUImageTwoInputFilter { - public static final String CHROMA_KEY_BLEND_FRAGMENT_SHADER = " precision highp float;\n" + - " \n" + - " varying highp vec2 textureCoordinate;\n" + - " varying highp vec2 textureCoordinate2;\n" + - "\n" + - " uniform float thresholdSensitivity;\n" + - " uniform float smoothing;\n" + - " uniform vec3 colorToReplace;\n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform sampler2D inputImageTexture2;\n" + - " \n" + - " void main()\n" + - " {\n" + - " vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + - " vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);\n" + - " \n" + - " float maskY = 0.2989 * colorToReplace.r + 0.5866 * colorToReplace.g + 0.1145 * colorToReplace.b;\n" + - " float maskCr = 0.7132 * (colorToReplace.r - maskY);\n" + - " float maskCb = 0.5647 * (colorToReplace.b - maskY);\n" + - " \n" + - " float Y = 0.2989 * textureColor.r + 0.5866 * textureColor.g + 0.1145 * textureColor.b;\n" + - " float Cr = 0.7132 * (textureColor.r - Y);\n" + - " float Cb = 0.5647 * (textureColor.b - Y);\n" + - " \n" + - " float blendValue = 1.0 - smoothstep(thresholdSensitivity, thresholdSensitivity + smoothing, distance(vec2(Cr, Cb), vec2(maskCr, maskCb)));\n" + - " gl_FragColor = mix(textureColor, textureColor2, blendValue);\n" + - " }"; - - private int mThresholdSensitivityLocation; - private int mSmoothingLocation; - private int mColorToReplaceLocation; - private float mSmoothing = 0.1f; - private float mThresholdSensitivity = 0.3f; - private float[] mColorToReplace = new float[]{0.0f, 1.0f, 0.0f}; - - public GPUImageChromaKeyBlendFilter() { - super(CHROMA_KEY_BLEND_FRAGMENT_SHADER); - - } - - @Override - public void onInit() { - super.onInit(); - mThresholdSensitivityLocation = GLES20.glGetUniformLocation(getProgram(), "thresholdSensitivity"); - mSmoothingLocation = GLES20.glGetUniformLocation(getProgram(), "smoothing"); - mColorToReplaceLocation = GLES20.glGetUniformLocation(getProgram(), "colorToReplace"); - } - - @Override - public void onInitialized() { - super.onInitialized(); - setSmoothing(mSmoothing); - setThresholdSensitivity(mThresholdSensitivity); - setColorToReplace(mColorToReplace[0], mColorToReplace[1], mColorToReplace[2]); - } - - /** - * The degree of smoothing controls how gradually similar colors are replaced in the image - * The default value is 0.1 - */ - public void setSmoothing(final float smoothing) { - mSmoothing = smoothing; - setFloat(mSmoothingLocation, mSmoothing); - } - - /** - * The threshold sensitivity controls how similar pixels need to be colored to be replaced - * The default value is 0.3 - */ - public void setThresholdSensitivity(final float thresholdSensitivity) { - mThresholdSensitivity = thresholdSensitivity; - setFloat(mThresholdSensitivityLocation, mThresholdSensitivity); - } - - /** The color to be replaced is specified using individual red, green, and blue components (normalized to 1.0). - * The default is green: (0.0, 1.0, 0.0). - * - * @param redComponent Red component of color to be replaced - * @param greenComponent Green component of color to be replaced - * @param blueComponent Blue component of color to be replaced - */ - public void setColorToReplace(float redComponent, float greenComponent, float blueComponent) { - mColorToReplace = new float[]{redComponent, greenComponent, blueComponent}; - setFloatVec3(mColorToReplaceLocation, mColorToReplace); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageColorBalanceFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageColorBalanceFilter.java deleted file mode 100755 index 68c078a..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageColorBalanceFilter.java +++ /dev/null @@ -1,197 +0,0 @@ -package jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; - -/** - * Created by edward_chiang on 13/10/16. - */ -public class GPUImageColorBalanceFilter extends GPUImageFilter { - - public static final String GPU_IMAGE_COLOR_BALANCE_FRAGMENT_SHADER = "" + - "varying highp vec2 textureCoordinate;\n" + - "uniform sampler2D inputImageTexture;\n" + - "uniform lowp vec3 shadowsShift;\n" + - "uniform lowp vec3 midtonesShift;\n" + - "uniform lowp vec3 highlightsShift;\n" + - "uniform int preserveLuminosity;\n" + - "lowp vec3 RGBToHSL(lowp vec3 color)\n" + - - "{\n" + - "lowp vec3 hsl; // init to 0 to avoid warnings ? (and reverse if + remove first part)\n" + - - "lowp float fmin = min(min(color.r, color.g), color.b); //Min. value of RGB\n" + - "lowp float fmax = max(max(color.r, color.g), color.b); //Max. value of RGB\n" + - "lowp float delta = fmax - fmin; //Delta RGB value\n" + - - "hsl.z = (fmax + fmin) / 2.0; // Luminance\n" + - - "if (delta == 0.0) //This is a gray, no chroma...\n" + - "{\n" + - " hsl.x = 0.0; // Hue\n" + - " hsl.y = 0.0; // Saturation\n" + - "}\n" + - "else //Chromatic data...\n" + - "{\n" + - " if (hsl.z < 0.5)\n" + - " hsl.y = delta / (fmax + fmin); // Saturation\n" + - " else\n"+ - " hsl.y = delta / (2.0 - fmax - fmin); // Saturation\n" + - "\n" + - " lowp float deltaR = (((fmax - color.r) / 6.0) + (delta / 2.0)) / delta;\n" + - " lowp float deltaG = (((fmax - color.g) / 6.0) + (delta / 2.0)) / delta;\n" + - " lowp float deltaB = (((fmax - color.b) / 6.0) + (delta / 2.0)) / delta;\n" + - "\n" + - " if (color.r == fmax )\n" + - " hsl.x = deltaB - deltaG; // Hue\n" + - " else if (color.g == fmax)\n" + - " hsl.x = (1.0 / 3.0) + deltaR - deltaB; // Hue\n" + - " else if (color.b == fmax)\n" + - " hsl.x = (2.0 / 3.0) + deltaG - deltaR; // Hue\n" + - - " if (hsl.x < 0.0)\n" + - " hsl.x += 1.0; // Hue\n" + - " else if (hsl.x > 1.0)\n" + - " hsl.x -= 1.0; // Hue\n" + - "}\n" + - "\n" + - "return hsl;\n" + - "}\n" + - - "lowp float HueToRGB(lowp float f1, lowp float f2, lowp float hue)\n" + - "{\n"+ - " if (hue < 0.0)\n"+ - " hue += 1.0;\n"+ - " else if (hue > 1.0)\n"+ - " hue -= 1.0;\n"+ - " lowp float res;\n"+ - " if ((6.0 * hue) < 1.0)\n"+ - " res = f1 + (f2 - f1) * 6.0 * hue;\n"+ - " else if ((2.0 * hue) < 1.0)\n"+ - " res = f2;\n"+ - " else if ((3.0 * hue) < 2.0)\n"+ - " res = f1 + (f2 - f1) * ((2.0 / 3.0) - hue) * 6.0;\n"+ - " else\n"+ - " res = f1;\n"+ - " return res;\n"+ - "}\n"+ - - "lowp vec3 HSLToRGB(lowp vec3 hsl)\n"+ - "{\n" + - " lowp vec3 rgb;\n" + - - " if (hsl.y == 0.0)\n" + - " rgb = vec3(hsl.z); // Luminance\n" + - " else\n" + - " {\n" + - " lowp float f2;\n" + - - " if (hsl.z < 0.5)\n" + - " f2 = hsl.z * (1.0 + hsl.y);\n" + - " else\n" + - " f2 = (hsl.z + hsl.y) - (hsl.y * hsl.z);\n" + - - " lowp float f1 = 2.0 * hsl.z - f2;\n" + - - " rgb.r = HueToRGB(f1, f2, hsl.x + (1.0/3.0));\n" + - " rgb.g = HueToRGB(f1, f2, hsl.x);\n" + - " rgb.b= HueToRGB(f1, f2, hsl.x - (1.0/3.0));\n" + - " }\n" + - - " return rgb;\n "+ - "}\n" + - - "lowp float RGBToL(lowp vec3 color)\n" + - "{\n" + - " lowp float fmin = min(min(color.r, color.g), color.b); //Min. value of RGB\n" + - " lowp float fmax = max(max(color.r, color.g), color.b); //Max. value of RGB\n" + - - " return (fmax + fmin) / 2.0; // Luminance\n" + - "}\n" + - - "void main()\n"+ - "{\n"+ - " lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + - - " // Alternative way:\n" + - " //lowp vec3 lightness = RGBToL(textureColor.rgb);\n" + - " lowp vec3 lightness = textureColor.rgb;\n" + - - " const lowp float a = 0.25;\n" + - " const lowp float b = 0.333;\n" + - " const lowp float scale = 0.7;\n" + - - " lowp vec3 shadows = shadowsShift * (clamp((lightness - b) / -a + 0.5, 0.0, 1.0) * scale);\n" + - " lowp vec3 midtones = midtonesShift * (clamp((lightness - b) / a + 0.5, 0.0, 1.0) *\n" + - " clamp((lightness + b - 1.0) / -a + 0.5, 0.0, 1.0) * scale);\n" + - " lowp vec3 highlights = highlightsShift * (clamp((lightness + b - 1.0) / a + 0.5, 0.0, 1.0) * scale);\n" + - - " mediump vec3 newColor = textureColor.rgb + shadows + midtones + highlights;\n"+ - " newColor = clamp(newColor, 0.0, 1.0);\n "+ - - " if (preserveLuminosity != 0) {\n "+ - " lowp vec3 newHSL = RGBToHSL(newColor);\n" + - " lowp float oldLum = RGBToL(textureColor.rgb);\n" + - " textureColor.rgb = HSLToRGB(vec3(newHSL.x, newHSL.y, oldLum));\n" + - " gl_FragColor = textureColor;\n" + - " } else {\n" + - " gl_FragColor = vec4(newColor.rgb, textureColor.w);\n" + - " }\n" + - "}\n"; - - private int mShadowsLocation; - private int mMidtonesLocation; - private int mHighlightsLocation; - private int mPreserveLuminosityLocation; - - private float[] showdows; - private float[] midtones; - private float[] highlights; - private boolean preserveLuminosity; - - - public GPUImageColorBalanceFilter() { - super(NO_FILTER_VERTEX_SHADER, GPU_IMAGE_COLOR_BALANCE_FRAGMENT_SHADER); - this.showdows = new float[]{0.0f, 0.0f, 0.0f}; - this.midtones = new float[]{0.0f, 0.0f, 0.0f}; - this.highlights = new float[]{0.0f, 0.0f, 0.0f}; - this.preserveLuminosity = true; - } - - @Override - public void onInit() { - super.onInit(); - mShadowsLocation = GLES20.glGetUniformLocation(getProgram(), "shadowsShift"); - mMidtonesLocation = GLES20.glGetUniformLocation(getProgram(), "midtonesShift"); - mHighlightsLocation = GLES20.glGetUniformLocation(getProgram(), "highlightsShift"); - mPreserveLuminosityLocation = GLES20.glGetUniformLocation(getProgram(), "preserveLuminosity"); - } - - @Override - public void onInitialized() { - super.onInitialized(); - setMidtones(this.midtones); - setShowdows(this.showdows); - setHighlights(this.highlights); - setPreserveLuminosity(this.preserveLuminosity); - } - - public void setShowdows(float[] showdows) { - this.showdows = showdows; - setFloatVec3(mShadowsLocation, showdows); - } - - public void setMidtones(float[] midtones) { - this.midtones = midtones; - setFloatVec3(mMidtonesLocation, midtones); - } - - public void setHighlights(float[] highlights) { - this.highlights = highlights; - setFloatVec3(mHighlightsLocation, highlights); - } - - public void setPreserveLuminosity(boolean preserveLuminosity) { - this.preserveLuminosity = preserveLuminosity; - setInteger(mPreserveLuminosityLocation, preserveLuminosity ? 1: 0); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageColorBlendFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageColorBlendFilter.java deleted file mode 100755 index 0f5de14..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageColorBlendFilter.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -public class GPUImageColorBlendFilter extends GPUImageTwoInputFilter { - public static final String COLOR_BLEND_FRAGMENT_SHADER = "varying highp vec2 textureCoordinate;\n" + - " varying highp vec2 textureCoordinate2;\n" + - " \n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform sampler2D inputImageTexture2;\n" + - " \n" + - " highp float lum(lowp vec3 c) {\n" + - " return dot(c, vec3(0.3, 0.59, 0.11));\n" + - " }\n" + - " \n" + - " lowp vec3 clipcolor(lowp vec3 c) {\n" + - " highp float l = lum(c);\n" + - " lowp float n = min(min(c.r, c.g), c.b);\n" + - " lowp float x = max(max(c.r, c.g), c.b);\n" + - " \n" + - " if (n < 0.0) {\n" + - " c.r = l + ((c.r - l) * l) / (l - n);\n" + - " c.g = l + ((c.g - l) * l) / (l - n);\n" + - " c.b = l + ((c.b - l) * l) / (l - n);\n" + - " }\n" + - " if (x > 1.0) {\n" + - " c.r = l + ((c.r - l) * (1.0 - l)) / (x - l);\n" + - " c.g = l + ((c.g - l) * (1.0 - l)) / (x - l);\n" + - " c.b = l + ((c.b - l) * (1.0 - l)) / (x - l);\n" + - " }\n" + - " \n" + - " return c;\n" + - " }\n" + - "\n" + - " lowp vec3 setlum(lowp vec3 c, highp float l) {\n" + - " highp float d = l - lum(c);\n" + - " c = c + vec3(d);\n" + - " return clipcolor(c);\n" + - " }\n" + - " \n" + - " void main()\n" + - " {\n" + - " highp vec4 baseColor = texture2D(inputImageTexture, textureCoordinate);\n" + - " highp vec4 overlayColor = texture2D(inputImageTexture2, textureCoordinate2);\n" + - "\n" + - " gl_FragColor = vec4(baseColor.rgb * (1.0 - overlayColor.a) + setlum(overlayColor.rgb, lum(baseColor.rgb)) * overlayColor.a, baseColor.a);\n" + - " }"; - - public GPUImageColorBlendFilter() { - super(COLOR_BLEND_FRAGMENT_SHADER); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageColorBurnBlendFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageColorBurnBlendFilter.java deleted file mode 100755 index e3b5c42..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageColorBurnBlendFilter.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -public class GPUImageColorBurnBlendFilter extends GPUImageTwoInputFilter { - public static final String COLOR_BURN_BLEND_FRAGMENT_SHADER = "varying highp vec2 textureCoordinate;\n" + - " varying highp vec2 textureCoordinate2;\n" + - "\n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform sampler2D inputImageTexture2;\n" + - " \n" + - " void main()\n" + - " {\n" + - " mediump vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + - " mediump vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);\n" + - " mediump vec4 whiteColor = vec4(1.0);\n" + - " gl_FragColor = whiteColor - (whiteColor - textureColor) / textureColor2;\n" + - " }"; - - public GPUImageColorBurnBlendFilter() { - super(COLOR_BURN_BLEND_FRAGMENT_SHADER); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageColorDodgeBlendFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageColorDodgeBlendFilter.java deleted file mode 100755 index 702a3a9..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageColorDodgeBlendFilter.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -public class GPUImageColorDodgeBlendFilter extends GPUImageTwoInputFilter { - public static final String COLOR_DODGE_BLEND_FRAGMENT_SHADER = "precision mediump float;\n" + - " \n" + - " varying highp vec2 textureCoordinate;\n" + - " varying highp vec2 textureCoordinate2;\n" + - " \n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform sampler2D inputImageTexture2;\n" + - " \n" + - " void main()\n" + - " {\n" + - " vec4 base = texture2D(inputImageTexture, textureCoordinate);\n" + - " vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);\n" + - " \n" + - " vec3 baseOverlayAlphaProduct = vec3(overlay.a * base.a);\n" + - " vec3 rightHandProduct = overlay.rgb * (1.0 - base.a) + base.rgb * (1.0 - overlay.a);\n" + - " \n" + - " vec3 firstBlendColor = baseOverlayAlphaProduct + rightHandProduct;\n" + - " vec3 overlayRGB = clamp((overlay.rgb / clamp(overlay.a, 0.01, 1.0)) * step(0.0, overlay.a), 0.0, 0.99);\n" + - " \n" + - " vec3 secondBlendColor = (base.rgb * overlay.a) / (1.0 - overlayRGB) + rightHandProduct;\n" + - " \n" + - " vec3 colorChoice = step((overlay.rgb * base.a + base.rgb * overlay.a), baseOverlayAlphaProduct);\n" + - " \n" + - " gl_FragColor = vec4(mix(firstBlendColor, secondBlendColor, colorChoice), 1.0);\n" + - " }"; - - public GPUImageColorDodgeBlendFilter() { - super(COLOR_DODGE_BLEND_FRAGMENT_SHADER); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageColorInvertFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageColorInvertFilter.java deleted file mode 100755 index 2d8df9b..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageColorInvertFilter.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -/** - * Invert all the colors in the image. - */ -public class GPUImageColorInvertFilter extends GPUImageFilter { - public static final String COLOR_INVERT_FRAGMENT_SHADER = "" + - "varying highp vec2 textureCoordinate;\n" + - "\n" + - "uniform sampler2D inputImageTexture;\n" + - "\n" + - "void main()\n" + - "{\n" + - " lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + - " \n" + - " gl_FragColor = vec4((1.0 - textureColor.rgb), textureColor.w);\n" + - "}"; - - public GPUImageColorInvertFilter() { - super(NO_FILTER_VERTEX_SHADER, COLOR_INVERT_FRAGMENT_SHADER); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageColorMatrixFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageColorMatrixFilter.java deleted file mode 100755 index 59203c4..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageColorMatrixFilter.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; - -/** - * Applies a ColorMatrix to the image. - */ -public class GPUImageColorMatrixFilter extends GPUImageFilter { - public static final String COLOR_MATRIX_FRAGMENT_SHADER = "" + - "varying highp vec2 textureCoordinate;\n" + - "\n" + - "uniform sampler2D inputImageTexture;\n" + - "\n" + - "uniform lowp mat4 colorMatrix;\n" + - "uniform lowp float intensity;\n" + - "\n" + - "void main()\n" + - "{\n" + - " lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + - " lowp vec4 outputColor = textureColor * colorMatrix;\n" + - " \n" + - " gl_FragColor = (intensity * outputColor) + ((1.0 - intensity) * textureColor);\n" + - "}"; - - private float mIntensity; - private float[] mColorMatrix; - private int mColorMatrixLocation; - private int mIntensityLocation; - - public GPUImageColorMatrixFilter() { - this(1.0f, new float[] { - 1.0f, 0.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f - }); - } - - public GPUImageColorMatrixFilter(final float intensity, final float[] colorMatrix) { - super(NO_FILTER_VERTEX_SHADER, COLOR_MATRIX_FRAGMENT_SHADER); - mIntensity = intensity; - mColorMatrix = colorMatrix; - } - - @Override - public void onInit() { - super.onInit(); - mColorMatrixLocation = GLES20.glGetUniformLocation(getProgram(), "colorMatrix"); - mIntensityLocation = GLES20.glGetUniformLocation(getProgram(), "intensity"); - } - - @Override - public void onInitialized() { - super.onInitialized(); - setIntensity(mIntensity); - setColorMatrix(mColorMatrix); - } - - public void setIntensity(final float intensity) { - mIntensity = intensity; - setFloat(mIntensityLocation, intensity); - } - - public void setColorMatrix(final float[] colorMatrix) { - mColorMatrix = colorMatrix; - setUniformMatrix4f(mColorMatrixLocation, colorMatrix); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageContrastFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageContrastFilter.java deleted file mode 100755 index 1d2b910..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageContrastFilter.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; - -/** - * Changes the contrast of the image.
    - *
    - * contrast value ranges from 0.0 to 4.0, with 1.0 as the normal level - */ -public class GPUImageContrastFilter extends GPUImageFilter { - public static final String CONTRAST_FRAGMENT_SHADER = "" + - "varying highp vec2 textureCoordinate;\n" + - " \n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform lowp float contrast;\n" + - " \n" + - " void main()\n" + - " {\n" + - " lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + - " \n" + - " gl_FragColor = vec4(((textureColor.rgb - vec3(0.5)) * contrast + vec3(0.5)), textureColor.w);\n" + - " }"; - - private int mContrastLocation; - private float mContrast; - - public GPUImageContrastFilter() { - this(1.2f); - } - - public GPUImageContrastFilter(float contrast) { - super(NO_FILTER_VERTEX_SHADER, CONTRAST_FRAGMENT_SHADER); - mContrast = contrast; - } - - @Override - public void onInit() { - super.onInit(); - mContrastLocation = GLES20.glGetUniformLocation(getProgram(), "contrast"); - } - - @Override - public void onInitialized() { - super.onInitialized(); - setContrast(mContrast); - } - - public void setContrast(final float contrast) { - mContrast = contrast; - setFloat(mContrastLocation, mContrast); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageCrosshatchFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageCrosshatchFilter.java deleted file mode 100755 index 04a3d4c..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageCrosshatchFilter.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; - -/** - * crossHatchSpacing: The fractional width of the image to use as the spacing for the crosshatch. The default is 0.03. - * lineWidth: A relative width for the crosshatch lines. The default is 0.003. - */ -public class GPUImageCrosshatchFilter extends GPUImageFilter { - public static final String CROSSHATCH_FRAGMENT_SHADER = "" + - "varying highp vec2 textureCoordinate;\n" + - "uniform sampler2D inputImageTexture;\n" + - "uniform highp float crossHatchSpacing;\n" + - "uniform highp float lineWidth;\n" + - "const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);\n" + - "void main()\n" + - "{\n" + - "highp float luminance = dot(texture2D(inputImageTexture, textureCoordinate).rgb, W);\n" + - "lowp vec4 colorToDisplay = vec4(1.0, 1.0, 1.0, 1.0);\n" + - "if (luminance < 1.00)\n" + - "{\n" + - "if (mod(textureCoordinate.x + textureCoordinate.y, crossHatchSpacing) <= lineWidth)\n" + - "{\n" + - "colorToDisplay = vec4(0.0, 0.0, 0.0, 1.0);\n" + - "}\n" + - "}\n" + - "if (luminance < 0.75)\n" + - "{\n" + - "if (mod(textureCoordinate.x - textureCoordinate.y, crossHatchSpacing) <= lineWidth)\n" + - "{\n" + - "colorToDisplay = vec4(0.0, 0.0, 0.0, 1.0);\n" + - "}\n" + - "}\n" + - "if (luminance < 0.50)\n" + - "{\n" + - "if (mod(textureCoordinate.x + textureCoordinate.y - (crossHatchSpacing / 2.0), crossHatchSpacing) <= lineWidth)\n" + - "{\n" + - "colorToDisplay = vec4(0.0, 0.0, 0.0, 1.0);\n" + - "}\n" + - "}\n" + - "if (luminance < 0.3)\n" + - "{\n" + - "if (mod(textureCoordinate.x - textureCoordinate.y - (crossHatchSpacing / 2.0), crossHatchSpacing) <= lineWidth)\n" + - "{\n" + - "colorToDisplay = vec4(0.0, 0.0, 0.0, 1.0);\n" + - "}\n" + - "}\n" + - "gl_FragColor = colorToDisplay;\n" + - "}\n"; - - private float mCrossHatchSpacing; - private int mCrossHatchSpacingLocation; - private float mLineWidth; - private int mLineWidthLocation; - - /** - * Using default values of crossHatchSpacing: 0.03f and lineWidth: 0.003f. - */ - public GPUImageCrosshatchFilter() { - this(0.03f, 0.003f); - } - - public GPUImageCrosshatchFilter(float crossHatchSpacing, float lineWidth) { - super(NO_FILTER_VERTEX_SHADER, CROSSHATCH_FRAGMENT_SHADER); - mCrossHatchSpacing = crossHatchSpacing; - mLineWidth = lineWidth; - } - - @Override - public void onInit() { - super.onInit(); - mCrossHatchSpacingLocation = GLES20.glGetUniformLocation(getProgram(), "crossHatchSpacing"); - mLineWidthLocation = GLES20.glGetUniformLocation(getProgram(), "lineWidth"); - } - - @Override - public void onInitialized() { - super.onInitialized(); - setCrossHatchSpacing(mCrossHatchSpacing); - setLineWidth(mLineWidth); - } - - /** - * The fractional width of the image to use as the spacing for the crosshatch. The default is 0.03. - * - * @param crossHatchSpacing default 0.03 - */ - public void setCrossHatchSpacing(final float crossHatchSpacing) { - float singlePixelSpacing; - if (getOutputWidth() != 0) { - singlePixelSpacing = 1.0f / (float) getOutputWidth(); - } else { - singlePixelSpacing = 1.0f / 2048.0f; - } - - if (crossHatchSpacing < singlePixelSpacing) { - mCrossHatchSpacing = singlePixelSpacing; - } else { - mCrossHatchSpacing = crossHatchSpacing; - } - - setFloat(mCrossHatchSpacingLocation, mCrossHatchSpacing); - } - - /** - * A relative width for the crosshatch lines. The default is 0.003. - * - * @param lineWidth default 0.003 - */ - public void setLineWidth(final float lineWidth) { - mLineWidth = lineWidth; - setFloat(mLineWidthLocation, mLineWidth); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageDarkenBlendFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageDarkenBlendFilter.java deleted file mode 100755 index 385e8e3..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageDarkenBlendFilter.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -public class GPUImageDarkenBlendFilter extends GPUImageTwoInputFilter { - public static final String DARKEN_BLEND_FRAGMENT_SHADER = "varying highp vec2 textureCoordinate;\n" + - " varying highp vec2 textureCoordinate2;\n" + - "\n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform sampler2D inputImageTexture2;\n" + - " \n" + - " void main()\n" + - " {\n" + - " lowp vec4 base = texture2D(inputImageTexture, textureCoordinate);\n" + - " lowp vec4 overlayer = texture2D(inputImageTexture2, textureCoordinate2);\n" + - " \n" + - " gl_FragColor = vec4(min(overlayer.rgb * base.a, base.rgb * overlayer.a) + overlayer.rgb * (1.0 - base.a) + base.rgb * (1.0 - overlayer.a), 1.0);\n" + - " }"; - - public GPUImageDarkenBlendFilter() { - super(DARKEN_BLEND_FRAGMENT_SHADER); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageDifferenceBlendFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageDifferenceBlendFilter.java deleted file mode 100755 index 1a32cd0..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageDifferenceBlendFilter.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -public class GPUImageDifferenceBlendFilter extends GPUImageTwoInputFilter { - public static final String DIFFERENCE_BLEND_FRAGMENT_SHADER = "varying highp vec2 textureCoordinate;\n" + - " varying highp vec2 textureCoordinate2;\n" + - "\n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform sampler2D inputImageTexture2;\n" + - " \n" + - " void main()\n" + - " {\n" + - " mediump vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + - " mediump vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);\n" + - " gl_FragColor = vec4(abs(textureColor2.rgb - textureColor.rgb), textureColor.a);\n" + - " }"; - - public GPUImageDifferenceBlendFilter() { - super(DIFFERENCE_BLEND_FRAGMENT_SHADER); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageDilationFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageDilationFilter.java deleted file mode 100755 index f6ce4e2..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageDilationFilter.java +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -/** - * For each pixel, this sets it to the maximum value of the red channel in a rectangular neighborhood extending - * out dilationRadius pixels from the center. - * This extends out bright features, and is most commonly used with black-and-white thresholded images. - */ -public class GPUImageDilationFilter extends GPUImageTwoPassTextureSamplingFilter { - public static final String VERTEX_SHADER_1 = - "attribute vec4 position;\n" + - "attribute vec2 inputTextureCoordinate;\n" + - "\n" + - "uniform float texelWidthOffset; \n" + - "uniform float texelHeightOffset; \n" + - "\n" + - "varying vec2 centerTextureCoordinate;\n" + - "varying vec2 oneStepPositiveTextureCoordinate;\n" + - "varying vec2 oneStepNegativeTextureCoordinate;\n" + - "\n" + - "void main()\n" + - "{\n" + - "gl_Position = position;\n" + - "\n" + - "vec2 offset = vec2(texelWidthOffset, texelHeightOffset);\n" + - "\n" + - "centerTextureCoordinate = inputTextureCoordinate;\n" + - "oneStepNegativeTextureCoordinate = inputTextureCoordinate - offset;\n" + - "oneStepPositiveTextureCoordinate = inputTextureCoordinate + offset;\n" + - "}\n"; - - public static final String VERTEX_SHADER_2 = - "attribute vec4 position;\n" + - "attribute vec2 inputTextureCoordinate;\n" + - "\n" + - "uniform float texelWidthOffset;\n" + - "uniform float texelHeightOffset;\n" + - "\n" + - "varying vec2 centerTextureCoordinate;\n" + - "varying vec2 oneStepPositiveTextureCoordinate;\n" + - "varying vec2 oneStepNegativeTextureCoordinate;\n" + - "varying vec2 twoStepsPositiveTextureCoordinate;\n" + - "varying vec2 twoStepsNegativeTextureCoordinate;\n" + - "\n" + - "void main()\n" + - "{\n" + - "gl_Position = position;\n" + - "\n" + - "vec2 offset = vec2(texelWidthOffset, texelHeightOffset);\n" + - "\n" + - "centerTextureCoordinate = inputTextureCoordinate;\n" + - "oneStepNegativeTextureCoordinate = inputTextureCoordinate - offset;\n" + - "oneStepPositiveTextureCoordinate = inputTextureCoordinate + offset;\n" + - "twoStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 2.0);\n" + - "twoStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 2.0);\n" + - "}\n"; - - public static final String VERTEX_SHADER_3 = - "attribute vec4 position;\n" + - "attribute vec2 inputTextureCoordinate;\n" + - "\n" + - "uniform float texelWidthOffset;\n" + - "uniform float texelHeightOffset;\n" + - "\n" + - "varying vec2 centerTextureCoordinate;\n" + - "varying vec2 oneStepPositiveTextureCoordinate;\n" + - "varying vec2 oneStepNegativeTextureCoordinate;\n" + - "varying vec2 twoStepsPositiveTextureCoordinate;\n" + - "varying vec2 twoStepsNegativeTextureCoordinate;\n" + - "varying vec2 threeStepsPositiveTextureCoordinate;\n" + - "varying vec2 threeStepsNegativeTextureCoordinate;\n" + - "\n" + - "void main()\n" + - "{\n" + - "gl_Position = position;\n" + - "\n" + - "vec2 offset = vec2(texelWidthOffset, texelHeightOffset);\n" + - "\n" + - "centerTextureCoordinate = inputTextureCoordinate;\n" + - "oneStepNegativeTextureCoordinate = inputTextureCoordinate - offset;\n" + - "oneStepPositiveTextureCoordinate = inputTextureCoordinate + offset;\n" + - "twoStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 2.0);\n" + - "twoStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 2.0);\n" + - "threeStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 3.0);\n" + - "threeStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 3.0);\n" + - "}\n"; - - public static final String VERTEX_SHADER_4 = - - "attribute vec4 position;\n" + - "attribute vec2 inputTextureCoordinate;\n" + - "\n" + - "uniform float texelWidthOffset;\n" + - "uniform float texelHeightOffset;\n" + - "\n" + - "varying vec2 centerTextureCoordinate;\n" + - "varying vec2 oneStepPositiveTextureCoordinate;\n" + - "varying vec2 oneStepNegativeTextureCoordinate;\n" + - "varying vec2 twoStepsPositiveTextureCoordinate;\n" + - "varying vec2 twoStepsNegativeTextureCoordinate;\n" + - "varying vec2 threeStepsPositiveTextureCoordinate;\n" + - "varying vec2 threeStepsNegativeTextureCoordinate;\n" + - "varying vec2 fourStepsPositiveTextureCoordinate;\n" + - "varying vec2 fourStepsNegativeTextureCoordinate;\n" + - "\n" + - "void main()\n" + - "{\n" + - "gl_Position = position;\n" + - "\n" + - "vec2 offset = vec2(texelWidthOffset, texelHeightOffset);\n" + - "\n" + - "centerTextureCoordinate = inputTextureCoordinate;\n" + - "oneStepNegativeTextureCoordinate = inputTextureCoordinate - offset;\n" + - "oneStepPositiveTextureCoordinate = inputTextureCoordinate + offset;\n" + - "twoStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 2.0);\n" + - "twoStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 2.0);\n" + - "threeStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 3.0);\n" + - "threeStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 3.0);\n" + - "fourStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 4.0);\n" + - "fourStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 4.0);\n" + - "}\n"; - - - public static final String FRAGMENT_SHADER_1 = - "precision lowp float;\n" + - "\n" + - "varying vec2 centerTextureCoordinate;\n" + - "varying vec2 oneStepPositiveTextureCoordinate;\n" + - "varying vec2 oneStepNegativeTextureCoordinate;\n" + - "\n" + - "uniform sampler2D inputImageTexture;\n" + - "\n" + - "void main()\n" + - "{\n" + - "float centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate).r;\n" + - "float oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate).r;\n" + - "float oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate).r;\n" + - "\n" + - "lowp float maxValue = max(centerIntensity, oneStepPositiveIntensity);\n" + - "maxValue = max(maxValue, oneStepNegativeIntensity);\n" + - "\n" + - "gl_FragColor = vec4(vec3(maxValue), 1.0);\n" + - "}\n"; - - public static final String FRAGMENT_SHADER_2 = - "precision lowp float;\n" + - "\n" + - "varying vec2 centerTextureCoordinate;\n" + - "varying vec2 oneStepPositiveTextureCoordinate;\n" + - "varying vec2 oneStepNegativeTextureCoordinate;\n" + - "varying vec2 twoStepsPositiveTextureCoordinate;\n" + - "varying vec2 twoStepsNegativeTextureCoordinate;\n" + - "\n" + - "uniform sampler2D inputImageTexture;\n" + - "\n" + - "void main()\n" + - "{\n" + - "float centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate).r;\n" + - "float oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate).r;\n" + - "float oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate).r;\n" + - "float twoStepsPositiveIntensity = texture2D(inputImageTexture, twoStepsPositiveTextureCoordinate).r;\n" + - "float twoStepsNegativeIntensity = texture2D(inputImageTexture, twoStepsNegativeTextureCoordinate).r;\n" + - "\n" + - "lowp float maxValue = max(centerIntensity, oneStepPositiveIntensity);\n" + - "maxValue = max(maxValue, oneStepNegativeIntensity);\n" + - "maxValue = max(maxValue, twoStepsPositiveIntensity);\n" + - "maxValue = max(maxValue, twoStepsNegativeIntensity);\n" + - "\n" + - "gl_FragColor = vec4(vec3(maxValue), 1.0);\n" + - "}\n"; - - public static final String FRAGMENT_SHADER_3 = - "precision lowp float;\n" + - "\n" + - "varying vec2 centerTextureCoordinate;\n" + - "varying vec2 oneStepPositiveTextureCoordinate;\n" + - "varying vec2 oneStepNegativeTextureCoordinate;\n" + - "varying vec2 twoStepsPositiveTextureCoordinate;\n" + - "varying vec2 twoStepsNegativeTextureCoordinate;\n" + - "varying vec2 threeStepsPositiveTextureCoordinate;\n" + - "varying vec2 threeStepsNegativeTextureCoordinate;\n" + - "\n" + - "uniform sampler2D inputImageTexture;\n" + - "\n" + - "void main()\n" + - "{\n" + - "float centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate).r;\n" + - "float oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate).r;\n" + - "float oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate).r;\n" + - "float twoStepsPositiveIntensity = texture2D(inputImageTexture, twoStepsPositiveTextureCoordinate).r;\n" + - "float twoStepsNegativeIntensity = texture2D(inputImageTexture, twoStepsNegativeTextureCoordinate).r;\n" + - "float threeStepsPositiveIntensity = texture2D(inputImageTexture, threeStepsPositiveTextureCoordinate).r;\n" + - "float threeStepsNegativeIntensity = texture2D(inputImageTexture, threeStepsNegativeTextureCoordinate).r;\n" + - "\n" + - "lowp float maxValue = max(centerIntensity, oneStepPositiveIntensity);\n" + - "maxValue = max(maxValue, oneStepNegativeIntensity);\n" + - "maxValue = max(maxValue, twoStepsPositiveIntensity);\n" + - "maxValue = max(maxValue, twoStepsNegativeIntensity);\n" + - "maxValue = max(maxValue, threeStepsPositiveIntensity);\n" + - "maxValue = max(maxValue, threeStepsNegativeIntensity);\n" + - "\n" + - "gl_FragColor = vec4(vec3(maxValue), 1.0);\n" + - "}\n"; - - public static final String FRAGMENT_SHADER_4 = - "precision lowp float;\n" + - "\n" + - "varying vec2 centerTextureCoordinate;\n" + - "varying vec2 oneStepPositiveTextureCoordinate;\n" + - "varying vec2 oneStepNegativeTextureCoordinate;\n" + - "varying vec2 twoStepsPositiveTextureCoordinate;\n" + - "varying vec2 twoStepsNegativeTextureCoordinate;\n" + - "varying vec2 threeStepsPositiveTextureCoordinate;\n" + - "varying vec2 threeStepsNegativeTextureCoordinate;\n" + - "varying vec2 fourStepsPositiveTextureCoordinate;\n" + - "varying vec2 fourStepsNegativeTextureCoordinate;\n" + - "\n" + - "uniform sampler2D inputImageTexture;\n" + - "\n" + - "void main()\n" + - "{\n" + - "float centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate).r;\n" + - "float oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate).r;\n" + - "float oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate).r;\n" + - "float twoStepsPositiveIntensity = texture2D(inputImageTexture, twoStepsPositiveTextureCoordinate).r;\n" + - "float twoStepsNegativeIntensity = texture2D(inputImageTexture, twoStepsNegativeTextureCoordinate).r;\n" + - "float threeStepsPositiveIntensity = texture2D(inputImageTexture, threeStepsPositiveTextureCoordinate).r;\n" + - "float threeStepsNegativeIntensity = texture2D(inputImageTexture, threeStepsNegativeTextureCoordinate).r;\n" + - "float fourStepsPositiveIntensity = texture2D(inputImageTexture, fourStepsPositiveTextureCoordinate).r;\n" + - "float fourStepsNegativeIntensity = texture2D(inputImageTexture, fourStepsNegativeTextureCoordinate).r;\n" + - "\n" + - "lowp float maxValue = max(centerIntensity, oneStepPositiveIntensity);\n" + - "maxValue = max(maxValue, oneStepNegativeIntensity);\n" + - "maxValue = max(maxValue, twoStepsPositiveIntensity);\n" + - "maxValue = max(maxValue, twoStepsNegativeIntensity);\n" + - "maxValue = max(maxValue, threeStepsPositiveIntensity);\n" + - "maxValue = max(maxValue, threeStepsNegativeIntensity);\n" + - "maxValue = max(maxValue, fourStepsPositiveIntensity);\n" + - "maxValue = max(maxValue, fourStepsNegativeIntensity);\n" + - "\n" + - "gl_FragColor = vec4(vec3(maxValue), 1.0);\n" + - "}\n"; - - - public GPUImageDilationFilter() { - this(1); - } - - /** - * Acceptable values for dilationRadius, which sets the distance in pixels to sample out from the center, - * are 1, 2, 3, and 4. - * - * @param radius 1, 2, 3 or 4 - */ - public GPUImageDilationFilter(int radius) { - this(getVertexShader(radius), getFragmentShader(radius)); - } - - private GPUImageDilationFilter(String vertexShader, String fragmentShader) { - super(vertexShader, fragmentShader, vertexShader, fragmentShader); - } - - private static String getVertexShader(int radius) { - switch (radius) { - case 0: - case 1: - return VERTEX_SHADER_1; - case 2: - return VERTEX_SHADER_2; - case 3: - return VERTEX_SHADER_3; - default: - return VERTEX_SHADER_4; - } - } - - private static String getFragmentShader(int radius) { - switch (radius) { - case 0: - case 1: - return FRAGMENT_SHADER_1; - case 2: - return FRAGMENT_SHADER_2; - case 3: - return FRAGMENT_SHADER_3; - default: - return FRAGMENT_SHADER_4; - } - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageDirectionalSobelEdgeDetectionFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageDirectionalSobelEdgeDetectionFilter.java deleted file mode 100755 index a5884a1..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageDirectionalSobelEdgeDetectionFilter.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - - -public class GPUImageDirectionalSobelEdgeDetectionFilter extends GPUImage3x3TextureSamplingFilter { - public static final String DIRECTIONAL_SOBEL_EDGE_DETECTION_FRAGMENT_SHADER = "" + - "precision mediump float;\n" + - "\n" + - "varying vec2 textureCoordinate;\n" + - "varying vec2 leftTextureCoordinate;\n" + - "varying vec2 rightTextureCoordinate;\n" + - "\n" + - "varying vec2 topTextureCoordinate;\n" + - "varying vec2 topLeftTextureCoordinate;\n" + - "varying vec2 topRightTextureCoordinate;\n" + - "\n" + - "varying vec2 bottomTextureCoordinate;\n" + - "varying vec2 bottomLeftTextureCoordinate;\n" + - "varying vec2 bottomRightTextureCoordinate;\n" + - "\n" + - "uniform sampler2D inputImageTexture;\n" + - "\n" + - "void main()\n" + - "{\n" + - " float bottomLeftIntensity = texture2D(inputImageTexture, bottomLeftTextureCoordinate).r;\n" + - " float topRightIntensity = texture2D(inputImageTexture, topRightTextureCoordinate).r;\n" + - " float topLeftIntensity = texture2D(inputImageTexture, topLeftTextureCoordinate).r;\n" + - " float bottomRightIntensity = texture2D(inputImageTexture, bottomRightTextureCoordinate).r;\n" + - " float leftIntensity = texture2D(inputImageTexture, leftTextureCoordinate).r;\n" + - " float rightIntensity = texture2D(inputImageTexture, rightTextureCoordinate).r;\n" + - " float bottomIntensity = texture2D(inputImageTexture, bottomTextureCoordinate).r;\n" + - " float topIntensity = texture2D(inputImageTexture, topTextureCoordinate).r;\n" + - "\n" + - " vec2 gradientDirection;\n" + - " gradientDirection.x = -bottomLeftIntensity - 2.0 * leftIntensity - topLeftIntensity + bottomRightIntensity + 2.0 * rightIntensity + topRightIntensity;\n" + - " gradientDirection.y = -topLeftIntensity - 2.0 * topIntensity - topRightIntensity + bottomLeftIntensity + 2.0 * bottomIntensity + bottomRightIntensity;\n" + - "\n" + - " float gradientMagnitude = length(gradientDirection);\n" + - " vec2 normalizedDirection = normalize(gradientDirection);\n" + - " normalizedDirection = sign(normalizedDirection) * floor(abs(normalizedDirection) + 0.617316); // Offset by 1-sin(pi/8) to set to 0 if near axis, 1 if away\n" + - " normalizedDirection = (normalizedDirection + 1.0) * 0.5; // Place -1.0 - 1.0 within 0 - 1.0\n" + - "\n" + - " gl_FragColor = vec4(gradientMagnitude, normalizedDirection.x, normalizedDirection.y, 1.0);\n" + - "}"; - - public GPUImageDirectionalSobelEdgeDetectionFilter() { - super(DIRECTIONAL_SOBEL_EDGE_DETECTION_FRAGMENT_SHADER); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageDissolveBlendFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageDissolveBlendFilter.java deleted file mode 100755 index cd2880a..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageDissolveBlendFilter.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; - -/** - * Mix ranges from 0.0 (only image 1) to 1.0 (only image 2), with 0.5 (half of either) as the normal level - */ -public class GPUImageDissolveBlendFilter extends GPUImageMixBlendFilter{ - public static final String DISSOLVE_BLEND_FRAGMENT_SHADER = "varying highp vec2 textureCoordinate;\n" + - " varying highp vec2 textureCoordinate2;\n" + - "\n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform sampler2D inputImageTexture2;\n" + - " uniform lowp float mixturePercent;\n" + - " \n" + - " void main()\n" + - " {\n" + - " lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + - " lowp vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);\n" + - " \n" + - " gl_FragColor = mix(textureColor, textureColor2, mixturePercent);\n" + - " }"; - - public GPUImageDissolveBlendFilter() { - super(DISSOLVE_BLEND_FRAGMENT_SHADER); - } - - public GPUImageDissolveBlendFilter(float mix) { - super(DISSOLVE_BLEND_FRAGMENT_SHADER, mix); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageDivideBlendFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageDivideBlendFilter.java deleted file mode 100755 index 179cd4e..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageDivideBlendFilter.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -public class GPUImageDivideBlendFilter extends GPUImageTwoInputFilter { - public static final String DIVIDE_BLEND_FRAGMENT_SHADER = "varying highp vec2 textureCoordinate;\n" + - " varying highp vec2 textureCoordinate2;\n" + - "\n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform sampler2D inputImageTexture2;\n" + - " \n" + - " void main()\n" + - " {\n" + - " mediump vec4 base = texture2D(inputImageTexture, textureCoordinate);\n" + - " mediump vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);\n" + - " \n" + - " mediump float ra;\n" + - " if (overlay.a == 0.0 || ((base.r / overlay.r) > (base.a / overlay.a)))\n" + - " ra = overlay.a * base.a + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);\n" + - " else\n" + - " ra = (base.r * overlay.a * overlay.a) / overlay.r + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);\n" + - " \n" + - "\n" + - " mediump float ga;\n" + - " if (overlay.a == 0.0 || ((base.g / overlay.g) > (base.a / overlay.a)))\n" + - " ga = overlay.a * base.a + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);\n" + - " else\n" + - " ga = (base.g * overlay.a * overlay.a) / overlay.g + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);\n" + - "\n" + - " \n" + - " mediump float ba;\n" + - " if (overlay.a == 0.0 || ((base.b / overlay.b) > (base.a / overlay.a)))\n" + - " ba = overlay.a * base.a + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);\n" + - " else\n" + - " ba = (base.b * overlay.a * overlay.a) / overlay.b + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);\n" + - "\n" + - " mediump float a = overlay.a + base.a - overlay.a * base.a;\n" + - " \n" + - " gl_FragColor = vec4(ra, ga, ba, a);\n" + - " }"; - - public GPUImageDivideBlendFilter() { - super(DIVIDE_BLEND_FRAGMENT_SHADER); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageEmbossFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageEmbossFilter.java deleted file mode 100755 index f4cbdef..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageEmbossFilter.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -/** - * Applies an emboss effect to the image.
    - *
    - * Intensity ranges from 0.0 to 4.0, with 1.0 as the normal level - */ -public class GPUImageEmbossFilter extends GPUImage3x3ConvolutionFilter { - private float mIntensity; - - public GPUImageEmbossFilter() { - this(1.0f); - } - - public GPUImageEmbossFilter(final float intensity) { - super(); - mIntensity = intensity; - } - - @Override - public void onInit() { - super.onInit(); - setIntensity(mIntensity); - } - - public void setIntensity(final float intensity) { - mIntensity = intensity; - setConvolutionKernel(new float[] { - intensity * (-2.0f), -intensity, 0.0f, - -intensity, 1.0f, intensity, - 0.0f, intensity, intensity * 2.0f, - }); - } - - public float getIntensity() { - return mIntensity; - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageExclusionBlendFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageExclusionBlendFilter.java deleted file mode 100755 index dcfc934..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageExclusionBlendFilter.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -public class GPUImageExclusionBlendFilter extends GPUImageTwoInputFilter { - public static final String EXCLUSION_BLEND_FRAGMENT_SHADER = "varying highp vec2 textureCoordinate;\n" + - " varying highp vec2 textureCoordinate2;\n" + - "\n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform sampler2D inputImageTexture2;\n" + - " \n" + - " void main()\n" + - " {\n" + - " mediump vec4 base = texture2D(inputImageTexture, textureCoordinate);\n" + - " mediump vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);\n" + - " \n" + - " // Dca = (Sca.Da + Dca.Sa - 2.Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa)\n" + - " \n" + - " gl_FragColor = vec4((overlay.rgb * base.a + base.rgb * overlay.a - 2.0 * overlay.rgb * base.rgb) + overlay.rgb * (1.0 - base.a) + base.rgb * (1.0 - overlay.a), base.a);\n" + - " }"; - - public GPUImageExclusionBlendFilter() { - super(EXCLUSION_BLEND_FRAGMENT_SHADER); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageExposureFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageExposureFilter.java deleted file mode 100755 index de5de41..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageExposureFilter.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; - -/** - * exposure: The adjusted exposure (-10.0 - 10.0, with 0.0 as the default) - */ -public class GPUImageExposureFilter extends GPUImageFilter { - public static final String EXPOSURE_FRAGMENT_SHADER = "" + - " varying highp vec2 textureCoordinate;\n" + - " \n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform highp float exposure;\n" + - " \n" + - " void main()\n" + - " {\n" + - " highp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + - " \n" + - " gl_FragColor = vec4(textureColor.rgb * pow(2.0, exposure), textureColor.w);\n" + - " } "; - - private int mExposureLocation; - private float mExposure; - - public GPUImageExposureFilter() { - this(1.0f); - } - - public GPUImageExposureFilter(final float exposure) { - super(NO_FILTER_VERTEX_SHADER, EXPOSURE_FRAGMENT_SHADER); - mExposure = exposure; - } - - @Override - public void onInit() { - super.onInit(); - mExposureLocation = GLES20.glGetUniformLocation(getProgram(), "exposure"); - } - - @Override - public void onInitialized() { - super.onInitialized(); - setExposure(mExposure); - } - - public void setExposure(final float exposure) { - mExposure = exposure; - setFloat(mExposureLocation, mExposure); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageFalseColorFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageFalseColorFilter.java deleted file mode 100755 index c815ad0..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageFalseColorFilter.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; - -public class GPUImageFalseColorFilter extends GPUImageFilter { - public static final String FALSECOLOR_FRAGMENT_SHADER = "" + - "precision lowp float;\n" + - "\n" + - "varying highp vec2 textureCoordinate;\n" + - "\n" + - "uniform sampler2D inputImageTexture;\n" + - "uniform float intensity;\n" + - "uniform vec3 firstColor;\n" + - "uniform vec3 secondColor;\n" + - "\n" + - "const mediump vec3 luminanceWeighting = vec3(0.2125, 0.7154, 0.0721);\n" + - "\n" + - "void main()\n" + - "{\n" + - "lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + - "float luminance = dot(textureColor.rgb, luminanceWeighting);\n" + - "\n" + - "gl_FragColor = vec4( mix(firstColor.rgb, secondColor.rgb, luminance), textureColor.a);\n" + - "}\n"; - - private float[] mFirstColor; - private int mFirstColorLocation; - private float[] mSecondColor; - private int mSecondColorLocation; - - public GPUImageFalseColorFilter() { - this(0f, 0f, 0.5f, 1f, 0f, 0f); - } - - public GPUImageFalseColorFilter(float firstRed, float firstGreen, float firstBlue, float secondRed, float secondGreen, float secondBlue) { - this(new float[]{firstRed, firstGreen, firstBlue}, new float[]{secondRed, secondGreen, secondBlue}); - } - - public GPUImageFalseColorFilter(float[] firstColor, float[] secondColor) { - super(NO_FILTER_VERTEX_SHADER, FALSECOLOR_FRAGMENT_SHADER); - mFirstColor = firstColor; - mSecondColor = secondColor; - } - - @Override - public void onInit() { - super.onInit(); - mFirstColorLocation = GLES20.glGetUniformLocation(getProgram(), "firstColor"); - mSecondColorLocation = GLES20.glGetUniformLocation(getProgram(), "secondColor"); - } - - @Override - public void onInitialized() { - super.onInitialized(); - setFirstColor(mFirstColor); - setSecondColor(mSecondColor); - } - - public void setFirstColor(final float[] firstColor) { - mFirstColor = firstColor; - setFloatVec3(mFirstColorLocation, firstColor); - } - - public void setSecondColor(final float[] secondColor) { - mSecondColor = secondColor; - setFloatVec3(mSecondColorLocation, secondColor); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageFilter.java deleted file mode 100755 index 7a8641a..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageFilter.java +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.content.Context; -import android.content.res.AssetManager; -import android.graphics.PointF; -import android.opengl.GLES20; - -import java.io.InputStream; -import java.nio.FloatBuffer; -import java.util.LinkedList; - -public class GPUImageFilter { - public static final String NO_FILTER_VERTEX_SHADER = "" + - "attribute vec4 position;\n" + - "attribute vec4 inputTextureCoordinate;\n" + - " \n" + - "varying vec2 textureCoordinate;\n" + - " \n" + - "void main()\n" + - "{\n" + - " gl_Position = position;\n" + - " textureCoordinate = inputTextureCoordinate.xy;\n" + - "}"; - public static final String NO_FILTER_FRAGMENT_SHADER = "" + - "varying highp vec2 textureCoordinate;\n" + - " \n" + - "uniform sampler2D inputImageTexture;\n" + - " \n" + - "void main()\n" + - "{\n" + - " gl_FragColor = texture2D(inputImageTexture, textureCoordinate);\n" + - "}"; - - private final LinkedList mRunOnDraw; - private final String mVertexShader; - private final String mFragmentShader; - protected int mGLProgId; - protected int mGLAttribPosition; - protected int mGLUniformTexture; - protected int mGLAttribTextureCoordinate; - protected int mOutputWidth; - protected int mOutputHeight; - private boolean mIsInitialized; - - public GPUImageFilter() { - this(NO_FILTER_VERTEX_SHADER, NO_FILTER_FRAGMENT_SHADER); - } - - public GPUImageFilter(final String vertexShader, final String fragmentShader) { - mRunOnDraw = new LinkedList(); - mVertexShader = vertexShader; - mFragmentShader = fragmentShader; - } - - public final void init() { - onInit(); - mIsInitialized = true; - onInitialized(); - } - - public void onInit() { - mGLProgId = OpenGlUtils.loadProgram(mVertexShader, mFragmentShader); - mGLAttribPosition = GLES20.glGetAttribLocation(mGLProgId, "position"); - mGLUniformTexture = GLES20.glGetUniformLocation(mGLProgId, "inputImageTexture"); - mGLAttribTextureCoordinate = GLES20.glGetAttribLocation(mGLProgId, - "inputTextureCoordinate"); - mIsInitialized = true; - } - - public void onInitialized() { - } - - public final void destroy() { - mIsInitialized = false; - GLES20.glDeleteProgram(mGLProgId); - onDestroy(); - } - - public void onDestroy() { - } - - public void onOutputSizeChanged(final int width, final int height) { - mOutputWidth = width; - mOutputHeight = height; - } - - public void onDraw(final int textureId, final FloatBuffer cubeBuffer, - final FloatBuffer textureBuffer) { - GLES20.glUseProgram(mGLProgId); - runPendingOnDrawTasks(); - if (!mIsInitialized) { - return; - } - - cubeBuffer.position(0); - GLES20.glVertexAttribPointer(mGLAttribPosition, 2, GLES20.GL_FLOAT, false, 0, cubeBuffer); - GLES20.glEnableVertexAttribArray(mGLAttribPosition); - textureBuffer.position(0); - GLES20.glVertexAttribPointer(mGLAttribTextureCoordinate, 2, GLES20.GL_FLOAT, false, 0, - textureBuffer); - GLES20.glEnableVertexAttribArray(mGLAttribTextureCoordinate); - if (textureId != OpenGlUtils.NO_TEXTURE) { - GLES20.glActiveTexture(GLES20.GL_TEXTURE0); - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId); - GLES20.glUniform1i(mGLUniformTexture, 0); - } - onDrawArraysPre(); - GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); - GLES20.glDisableVertexAttribArray(mGLAttribPosition); - GLES20.glDisableVertexAttribArray(mGLAttribTextureCoordinate); - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); - } - - protected void onDrawArraysPre() {} - - protected void runPendingOnDrawTasks() { - while (!mRunOnDraw.isEmpty()) { - mRunOnDraw.removeFirst().run(); - } - } - - public boolean isInitialized() { - return mIsInitialized; - } - - public int getOutputWidth() { - return mOutputWidth; - } - - public int getOutputHeight() { - return mOutputHeight; - } - - public int getProgram() { - return mGLProgId; - } - - public int getAttribPosition() { - return mGLAttribPosition; - } - - public int getAttribTextureCoordinate() { - return mGLAttribTextureCoordinate; - } - - public int getUniformTexture() { - return mGLUniformTexture; - } - - protected void setInteger(final int location, final int intValue) { - runOnDraw(new Runnable() { - @Override - public void run() { - GLES20.glUniform1i(location, intValue); - } - }); - } - - protected void setFloat(final int location, final float floatValue) { - runOnDraw(new Runnable() { - @Override - public void run() { - GLES20.glUniform1f(location, floatValue); - } - }); - } - - protected void setFloatVec2(final int location, final float[] arrayValue) { - runOnDraw(new Runnable() { - @Override - public void run() { - GLES20.glUniform2fv(location, 1, FloatBuffer.wrap(arrayValue)); - } - }); - } - - protected void setFloatVec3(final int location, final float[] arrayValue) { - runOnDraw(new Runnable() { - @Override - public void run() { - GLES20.glUniform3fv(location, 1, FloatBuffer.wrap(arrayValue)); - } - }); - } - - protected void setFloatVec4(final int location, final float[] arrayValue) { - runOnDraw(new Runnable() { - @Override - public void run() { - GLES20.glUniform4fv(location, 1, FloatBuffer.wrap(arrayValue)); - } - }); - } - - protected void setFloatArray(final int location, final float[] arrayValue) { - runOnDraw(new Runnable() { - @Override - public void run() { - GLES20.glUniform1fv(location, arrayValue.length, FloatBuffer.wrap(arrayValue)); - } - }); - } - - protected void setPoint(final int location, final PointF point) { - runOnDraw(new Runnable() { - - @Override - public void run() { - float[] vec2 = new float[2]; - vec2[0] = point.x; - vec2[1] = point.y; - GLES20.glUniform2fv(location, 1, vec2, 0); - } - }); - } - - protected void setUniformMatrix3f(final int location, final float[] matrix) { - runOnDraw(new Runnable() { - - @Override - public void run() { - GLES20.glUniformMatrix3fv(location, 1, false, matrix, 0); - } - }); - } - - protected void setUniformMatrix4f(final int location, final float[] matrix) { - runOnDraw(new Runnable() { - - @Override - public void run() { - GLES20.glUniformMatrix4fv(location, 1, false, matrix, 0); - } - }); - } - - protected void runOnDraw(final Runnable runnable) { - synchronized (mRunOnDraw) { - mRunOnDraw.addLast(runnable); - } - } - - public static String loadShader(String file, Context context) { - try { - AssetManager assetManager = context.getAssets(); - InputStream ims = assetManager.open(file); - - String re = convertStreamToString(ims); - ims.close(); - return re; - } catch (Exception e) { - e.printStackTrace(); - } - - return ""; - } - - public static String convertStreamToString(java.io.InputStream is) { - java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A"); - return s.hasNext() ? s.next() : ""; - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageFilterGroup.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageFilterGroup.java deleted file mode 100755 index 10ea41c..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageFilterGroup.java +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.annotation.SuppressLint; -import android.opengl.GLES20; -import jp.co.cyberagent.android.gpuimage.util.TextureRotationUtil; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.FloatBuffer; -import java.util.ArrayList; -import java.util.List; - -import static jp.co.cyberagent.android.gpuimage.GPUImageRenderer.CUBE; -import static jp.co.cyberagent.android.gpuimage.util.TextureRotationUtil.TEXTURE_NO_ROTATION; - -/** - * Resembles a filter that consists of multiple filters applied after each - * other. - */ -public class GPUImageFilterGroup extends GPUImageFilter { - - protected List mFilters; - protected List mMergedFilters; - private int[] mFrameBuffers; - private int[] mFrameBufferTextures; - - private final FloatBuffer mGLCubeBuffer; - private final FloatBuffer mGLTextureBuffer; - private final FloatBuffer mGLTextureFlipBuffer; - - /** - * Instantiates a new GPUImageFilterGroup with no filters. - */ - public GPUImageFilterGroup() { - this(null); - } - - /** - * Instantiates a new GPUImageFilterGroup with the given filters. - * - * @param filters the filters which represent this filter - */ - public GPUImageFilterGroup(List filters) { - mFilters = filters; - if (mFilters == null) { - mFilters = new ArrayList(); - } else { - updateMergedFilters(); - } - - mGLCubeBuffer = ByteBuffer.allocateDirect(CUBE.length * 4) - .order(ByteOrder.nativeOrder()) - .asFloatBuffer(); - mGLCubeBuffer.put(CUBE).position(0); - - mGLTextureBuffer = ByteBuffer.allocateDirect(TEXTURE_NO_ROTATION.length * 4) - .order(ByteOrder.nativeOrder()) - .asFloatBuffer(); - mGLTextureBuffer.put(TEXTURE_NO_ROTATION).position(0); - - float[] flipTexture = TextureRotationUtil.getRotation(Rotation.NORMAL, false, true); - mGLTextureFlipBuffer = ByteBuffer.allocateDirect(flipTexture.length * 4) - .order(ByteOrder.nativeOrder()) - .asFloatBuffer(); - mGLTextureFlipBuffer.put(flipTexture).position(0); - } - - public void addFilter(GPUImageFilter aFilter) { - if (aFilter == null) { - return; - } - mFilters.add(aFilter); - updateMergedFilters(); - } - - /* - * (non-Javadoc) - * @see jp.co.cyberagent.android.gpuimage.GPUImageFilter#onInit() - */ - @Override - public void onInit() { - super.onInit(); - for (GPUImageFilter filter : mFilters) { - filter.init(); - } - } - - /* - * (non-Javadoc) - * @see jp.co.cyberagent.android.gpuimage.GPUImageFilter#onDestroy() - */ - @Override - public void onDestroy() { - destroyFramebuffers(); - for (GPUImageFilter filter : mFilters) { - filter.destroy(); - } - super.onDestroy(); - } - - private void destroyFramebuffers() { - if (mFrameBufferTextures != null) { - GLES20.glDeleteTextures(mFrameBufferTextures.length, mFrameBufferTextures, 0); - mFrameBufferTextures = null; - } - if (mFrameBuffers != null) { - GLES20.glDeleteFramebuffers(mFrameBuffers.length, mFrameBuffers, 0); - mFrameBuffers = null; - } - } - - /* - * (non-Javadoc) - * @see - * jp.co.cyberagent.android.gpuimage.GPUImageFilter#onOutputSizeChanged(int, - * int) - */ - @Override - public void onOutputSizeChanged(final int width, final int height) { - super.onOutputSizeChanged(width, height); - if (mFrameBuffers != null) { - destroyFramebuffers(); - } - - int size = mFilters.size(); - for (int i = 0; i < size; i++) { - mFilters.get(i).onOutputSizeChanged(width, height); - } - - if (mMergedFilters != null && mMergedFilters.size() > 0) { - size = mMergedFilters.size(); - mFrameBuffers = new int[size - 1]; - mFrameBufferTextures = new int[size - 1]; - - for (int i = 0; i < size - 1; i++) { - GLES20.glGenFramebuffers(1, mFrameBuffers, i); - GLES20.glGenTextures(1, mFrameBufferTextures, i); - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mFrameBufferTextures[i]); - GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0, - GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null); - GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, - GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); - GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, - GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); - GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, - GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); - GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, - GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); - - GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mFrameBuffers[i]); - GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, - GLES20.GL_TEXTURE_2D, mFrameBufferTextures[i], 0); - - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); - GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); - } - } - } - - /* - * (non-Javadoc) - * @see jp.co.cyberagent.android.gpuimage.GPUImageFilter#onDraw(int, - * java.nio.FloatBuffer, java.nio.FloatBuffer) - */ - @SuppressLint("WrongCall") - @Override - public void onDraw(final int textureId, final FloatBuffer cubeBuffer, - final FloatBuffer textureBuffer) { - runPendingOnDrawTasks(); - if (!isInitialized() || mFrameBuffers == null || mFrameBufferTextures == null) { - return; - } - if (mMergedFilters != null) { - int size = mMergedFilters.size(); - int previousTexture = textureId; - for (int i = 0; i < size; i++) { - GPUImageFilter filter = mMergedFilters.get(i); - boolean isNotLast = i < size - 1; - if (isNotLast) { - GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mFrameBuffers[i]); - GLES20.glClearColor(0, 0, 0, 0); - } - - if (i == 0) { - filter.onDraw(previousTexture, cubeBuffer, textureBuffer); - } else if (i == size - 1) { - filter.onDraw(previousTexture, mGLCubeBuffer, (size % 2 == 0) ? mGLTextureFlipBuffer : mGLTextureBuffer); - } else { - filter.onDraw(previousTexture, mGLCubeBuffer, mGLTextureBuffer); - } - - if (isNotLast) { - GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); - previousTexture = mFrameBufferTextures[i]; - } - } - } - } - - /** - * Gets the filters. - * - * @return the filters - */ - public List getFilters() { - return mFilters; - } - - public List getMergedFilters() { - return mMergedFilters; - } - - public void updateMergedFilters() { - if (mFilters == null) { - return; - } - - if (mMergedFilters == null) { - mMergedFilters = new ArrayList(); - } else { - mMergedFilters.clear(); - } - - List filters; - for (GPUImageFilter filter : mFilters) { - if (filter instanceof GPUImageFilterGroup) { - ((GPUImageFilterGroup) filter).updateMergedFilters(); - filters = ((GPUImageFilterGroup) filter).getMergedFilters(); - if (filters == null || filters.isEmpty()) - continue; - mMergedFilters.addAll(filters); - continue; - } - mMergedFilters.add(filter); - } - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageGammaFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageGammaFilter.java deleted file mode 100755 index 1f902d0..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageGammaFilter.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; - -/** - * gamma value ranges from 0.0 to 3.0, with 1.0 as the normal level - */ -public class GPUImageGammaFilter extends GPUImageFilter { - public static final String GAMMA_FRAGMENT_SHADER = "" + - "varying highp vec2 textureCoordinate;\n" + - " \n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform lowp float gamma;\n" + - " \n" + - " void main()\n" + - " {\n" + - " lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + - " \n" + - " gl_FragColor = vec4(pow(textureColor.rgb, vec3(gamma)), textureColor.w);\n" + - " }"; - - private int mGammaLocation; - private float mGamma; - - public GPUImageGammaFilter() { - this(1.2f); - } - - public GPUImageGammaFilter(final float gamma) { - super(NO_FILTER_VERTEX_SHADER, GAMMA_FRAGMENT_SHADER); - mGamma = gamma; - } - - @Override - public void onInit() { - super.onInit(); - mGammaLocation = GLES20.glGetUniformLocation(getProgram(), "gamma"); - } - - @Override - public void onInitialized() { - super.onInitialized(); - setGamma(mGamma); - } - - public void setGamma(final float gamma) { - mGamma = gamma; - setFloat(mGammaLocation, mGamma); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageGaussianBlurFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageGaussianBlurFilter.java deleted file mode 100755 index c912f73..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageGaussianBlurFilter.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -/** - * A more generalized 9x9 Gaussian blur filter - * blurSize value ranging from 0.0 on up, with a default of 1.0 - */ -public class GPUImageGaussianBlurFilter extends GPUImageTwoPassTextureSamplingFilter { - public static final String VERTEX_SHADER = - "attribute vec4 position;\n" + - "attribute vec4 inputTextureCoordinate;\n" + - "\n" + - "const int GAUSSIAN_SAMPLES = 9;\n" + - "\n" + - "uniform float texelWidthOffset;\n" + - "uniform float texelHeightOffset;\n" + - "\n" + - "varying vec2 textureCoordinate;\n" + - "varying vec2 blurCoordinates[GAUSSIAN_SAMPLES];\n" + - "\n" + - "void main()\n" + - "{\n" + - " gl_Position = position;\n" + - " textureCoordinate = inputTextureCoordinate.xy;\n" + - " \n" + - " // Calculate the positions for the blur\n" + - " int multiplier = 0;\n" + - " vec2 blurStep;\n" + - " vec2 singleStepOffset = vec2(texelHeightOffset, texelWidthOffset);\n" + - " \n" + - " for (int i = 0; i < GAUSSIAN_SAMPLES; i++)\n" + - " {\n" + - " multiplier = (i - ((GAUSSIAN_SAMPLES - 1) / 2));\n" + - " // Blur in x (horizontal)\n" + - " blurStep = float(multiplier) * singleStepOffset;\n" + - " blurCoordinates[i] = inputTextureCoordinate.xy + blurStep;\n" + - " }\n" + - "}\n"; - - public static final String FRAGMENT_SHADER = - "uniform sampler2D inputImageTexture;\n" + - "\n" + - "const lowp int GAUSSIAN_SAMPLES = 9;\n" + - "\n" + - "varying highp vec2 textureCoordinate;\n" + - "varying highp vec2 blurCoordinates[GAUSSIAN_SAMPLES];\n" + - "\n" + - "void main()\n" + - "{\n" + - " lowp vec3 sum = vec3(0.0);\n" + - " lowp vec4 fragColor=texture2D(inputImageTexture,textureCoordinate);\n" + - " \n" + - " sum += texture2D(inputImageTexture, blurCoordinates[0]).rgb * 0.05;\n" + - " sum += texture2D(inputImageTexture, blurCoordinates[1]).rgb * 0.09;\n" + - " sum += texture2D(inputImageTexture, blurCoordinates[2]).rgb * 0.12;\n" + - " sum += texture2D(inputImageTexture, blurCoordinates[3]).rgb * 0.15;\n" + - " sum += texture2D(inputImageTexture, blurCoordinates[4]).rgb * 0.18;\n" + - " sum += texture2D(inputImageTexture, blurCoordinates[5]).rgb * 0.15;\n" + - " sum += texture2D(inputImageTexture, blurCoordinates[6]).rgb * 0.12;\n" + - " sum += texture2D(inputImageTexture, blurCoordinates[7]).rgb * 0.09;\n" + - " sum += texture2D(inputImageTexture, blurCoordinates[8]).rgb * 0.05;\n" + - "\n" + - " gl_FragColor = vec4(sum,fragColor.a);\n" + - "}"; - - protected float mBlurSize = 1f; - - public GPUImageGaussianBlurFilter() { - this(1f); - } - - public GPUImageGaussianBlurFilter(float blurSize) { - super(VERTEX_SHADER, FRAGMENT_SHADER, VERTEX_SHADER, FRAGMENT_SHADER); - mBlurSize = blurSize; - } - - @Override - public float getVerticalTexelOffsetRatio() { - return mBlurSize; - } - - @Override - public float getHorizontalTexelOffsetRatio() { - return mBlurSize; - } - - /** - * A multiplier for the blur size, ranging from 0.0 on up, with a default of 1.0 - * - * @param blurSize from 0.0 on up, default 1.0 - */ - public void setBlurSize(float blurSize) { - mBlurSize = blurSize; - runOnDraw(new Runnable() { - @Override - public void run() { - initTexelOffsets(); - } - }); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageGlassSphereFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageGlassSphereFilter.java deleted file mode 100755 index 460019c..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageGlassSphereFilter.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.graphics.PointF; -import android.opengl.GLES20; - -public class GPUImageGlassSphereFilter extends GPUImageFilter { - public static final String SPHERE_FRAGMENT_SHADER = "" + - "varying highp vec2 textureCoordinate;\n" + - "\n" + - "uniform sampler2D inputImageTexture;\n" + - "\n" + - "uniform highp vec2 center;\n" + - "uniform highp float radius;\n" + - "uniform highp float aspectRatio;\n" + - "uniform highp float refractiveIndex;\n" + - "// uniform vec3 lightPosition;\n" + - "const highp vec3 lightPosition = vec3(-0.5, 0.5, 1.0);\n" + - "const highp vec3 ambientLightPosition = vec3(0.0, 0.0, 1.0);\n" + - "\n" + - "void main()\n" + - "{\n" + - "highp vec2 textureCoordinateToUse = vec2(textureCoordinate.x, (textureCoordinate.y * aspectRatio + 0.5 - 0.5 * aspectRatio));\n" + - "highp float distanceFromCenter = distance(center, textureCoordinateToUse);\n" + - "lowp float checkForPresenceWithinSphere = step(distanceFromCenter, radius);\n" + - "\n" + - "distanceFromCenter = distanceFromCenter / radius;\n" + - "\n" + - "highp float normalizedDepth = radius * sqrt(1.0 - distanceFromCenter * distanceFromCenter);\n" + - "highp vec3 sphereNormal = normalize(vec3(textureCoordinateToUse - center, normalizedDepth));\n" + - "\n" + - "highp vec3 refractedVector = 2.0 * refract(vec3(0.0, 0.0, -1.0), sphereNormal, refractiveIndex);\n" + - "refractedVector.xy = -refractedVector.xy;\n" + - "\n" + - "highp vec3 finalSphereColor = texture2D(inputImageTexture, (refractedVector.xy + 1.0) * 0.5).rgb;\n" + - "\n" + - "// Grazing angle lighting\n" + - "highp float lightingIntensity = 2.5 * (1.0 - pow(clamp(dot(ambientLightPosition, sphereNormal), 0.0, 1.0), 0.25));\n" + - "finalSphereColor += lightingIntensity;\n" + - "\n" + - "// Specular lighting\n" + - "lightingIntensity = clamp(dot(normalize(lightPosition), sphereNormal), 0.0, 1.0);\n" + - "lightingIntensity = pow(lightingIntensity, 15.0);\n" + - "finalSphereColor += vec3(0.8, 0.8, 0.8) * lightingIntensity;\n" + - "\n" + - "gl_FragColor = vec4(finalSphereColor, 1.0) * checkForPresenceWithinSphere;\n" + - "}\n"; - - private PointF mCenter; - private int mCenterLocation; - private float mRadius; - private int mRadiusLocation; - private float mAspectRatio; - private int mAspectRatioLocation; - private float mRefractiveIndex; - private int mRefractiveIndexLocation; - - public GPUImageGlassSphereFilter() { - this(new PointF(0.5f, 0.5f), 0.25f, 0.71f); - } - - public GPUImageGlassSphereFilter(PointF center, float radius, float refractiveIndex) { - super(NO_FILTER_VERTEX_SHADER, SPHERE_FRAGMENT_SHADER); - mCenter = center; - mRadius = radius; - mRefractiveIndex = refractiveIndex; - } - - @Override - public void onInit() { - super.onInit(); - mCenterLocation = GLES20.glGetUniformLocation(getProgram(), "center"); - mRadiusLocation = GLES20.glGetUniformLocation(getProgram(), "radius"); - mAspectRatioLocation = GLES20.glGetUniformLocation(getProgram(), "aspectRatio"); - mRefractiveIndexLocation = GLES20.glGetUniformLocation(getProgram(), "refractiveIndex"); - } - - @Override - public void onInitialized() { - super.onInitialized(); - setRadius(mRadius); - setCenter(mCenter); - setRefractiveIndex(mRefractiveIndex); - } - - @Override - public void onOutputSizeChanged(int width, int height) { - mAspectRatio = (float) height / width; - setAspectRatio(mAspectRatio); - super.onOutputSizeChanged(width, height); - } - - private void setAspectRatio(float aspectRatio) { - mAspectRatio = aspectRatio; - setFloat(mAspectRatioLocation, aspectRatio); - } - - public void setRefractiveIndex(float refractiveIndex) { - mRefractiveIndex = refractiveIndex; - setFloat(mRefractiveIndexLocation, refractiveIndex); - } - - public void setCenter(PointF center) { - mCenter = center; - setPoint(mCenterLocation, center); - } - - public void setRadius(float radius) { - mRadius = radius; - setFloat(mRadiusLocation, radius); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageGrayscaleFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageGrayscaleFilter.java deleted file mode 100755 index b0a67f9..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageGrayscaleFilter.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -/** - * Applies a grayscale effect to the image. - */ -public class GPUImageGrayscaleFilter extends GPUImageFilter { - public static final String GRAYSCALE_FRAGMENT_SHADER = "" + - "precision highp float;\n" + - "\n" + - "varying vec2 textureCoordinate;\n" + - "\n" + - "uniform sampler2D inputImageTexture;\n" + - "\n" + - "const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);\n" + - "\n" + - "void main()\n" + - "{\n" + - " lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + - " float luminance = dot(textureColor.rgb, W);\n" + - "\n" + - " gl_FragColor = vec4(vec3(luminance), textureColor.a);\n" + - "}"; - - public GPUImageGrayscaleFilter() { - super(NO_FILTER_VERTEX_SHADER, GRAYSCALE_FRAGMENT_SHADER); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageHardLightBlendFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageHardLightBlendFilter.java deleted file mode 100755 index 5bcb9c9..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageHardLightBlendFilter.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -public class GPUImageHardLightBlendFilter extends GPUImageTwoInputFilter { - public static final String HARD_LIGHT_BLEND_FRAGMENT_SHADER = "varying highp vec2 textureCoordinate;\n" + - " varying highp vec2 textureCoordinate2;\n" + - "\n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform sampler2D inputImageTexture2;\n" + - "\n" + - " const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);\n" + - "\n" + - " void main()\n" + - " {\n" + - " mediump vec4 base = texture2D(inputImageTexture, textureCoordinate);\n" + - " mediump vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);\n" + - "\n" + - " highp float ra;\n" + - " if (2.0 * overlay.r < overlay.a) {\n" + - " ra = 2.0 * overlay.r * base.r + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);\n" + - " } else {\n" + - " ra = overlay.a * base.a - 2.0 * (base.a - base.r) * (overlay.a - overlay.r) + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);\n" + - " }\n" + - " \n" + - " highp float ga;\n" + - " if (2.0 * overlay.g < overlay.a) {\n" + - " ga = 2.0 * overlay.g * base.g + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);\n" + - " } else {\n" + - " ga = overlay.a * base.a - 2.0 * (base.a - base.g) * (overlay.a - overlay.g) + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);\n" + - " }\n" + - " \n" + - " highp float ba;\n" + - " if (2.0 * overlay.b < overlay.a) {\n" + - " ba = 2.0 * overlay.b * base.b + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);\n" + - " } else {\n" + - " ba = overlay.a * base.a - 2.0 * (base.a - base.b) * (overlay.a - overlay.b) + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);\n" + - " }\n" + - " \n" + - " gl_FragColor = vec4(ra, ga, ba, 1.0);\n" + - " }"; - - public GPUImageHardLightBlendFilter() { - super(HARD_LIGHT_BLEND_FRAGMENT_SHADER); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageHazeFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageHazeFilter.java deleted file mode 100755 index bb230ab..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageHazeFilter.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; - -/** - * The haze filter can be used to add or remove haze. - * - * This is similar to a UV filter. - */ -public class GPUImageHazeFilter extends GPUImageFilter { - public static final String HAZE_FRAGMENT_SHADER = "" + - "varying highp vec2 textureCoordinate;\n" + - "\n" + - "uniform sampler2D inputImageTexture;\n" + - "\n" + - "uniform lowp float distance;\n" + - "uniform highp float slope;\n" + - "\n" + - "void main()\n" + - "{\n" + - " //todo reconsider precision modifiers \n" + - " highp vec4 color = vec4(1.0);//todo reimplement as a parameter\n" + - "\n" + - " highp float d = textureCoordinate.y * slope + distance; \n" + - "\n" + - " highp vec4 c = texture2D(inputImageTexture, textureCoordinate) ; // consider using unpremultiply\n" + - "\n" + - " c = (c - d * color) / (1.0 -d);\n" + - "\n" + - " gl_FragColor = c; //consider using premultiply(c);\n" + - "}\n"; - - private float mDistance; - private int mDistanceLocation; - private float mSlope; - private int mSlopeLocation; - - public GPUImageHazeFilter() { - this(0.2f, 0.0f); - } - - public GPUImageHazeFilter(float distance, float slope) { - super(NO_FILTER_VERTEX_SHADER, HAZE_FRAGMENT_SHADER); - mDistance = distance; - mSlope = slope; - } - - @Override - public void onInit() { - super.onInit(); - mDistanceLocation = GLES20.glGetUniformLocation(getProgram(), "distance"); - mSlopeLocation = GLES20.glGetUniformLocation(getProgram(), "slope"); - } - - @Override - public void onInitialized() { - super.onInitialized(); - setDistance(mDistance); - setSlope(mSlope); - } - - /** - * Strength of the color applied. Default 0. Values between -.3 and .3 are best. - * - * @param distance -0.3 to 0.3 are best, default 0 - */ - public void setDistance(float distance) { - mDistance = distance; - setFloat(mDistanceLocation, distance); - } - - /** - * Amount of color change. Default 0. Values between -.3 and .3 are best. - * - * @param slope -0.3 to 0.3 are best, default 0 - */ - public void setSlope(float slope) { - mSlope = slope; - setFloat(mSlopeLocation, slope); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageHighlightShadowFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageHighlightShadowFilter.java deleted file mode 100755 index 878c508..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageHighlightShadowFilter.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; - -/** - * Adjusts the shadows and highlights of an image - * shadows: Increase to lighten shadows, from 0.0 to 1.0, with 0.0 as the default. - * highlights: Decrease to darken highlights, from 0.0 to 1.0, with 1.0 as the default. - */ -public class GPUImageHighlightShadowFilter extends GPUImageFilter { - public static final String HIGHLIGHT_SHADOW_FRAGMENT_SHADER = "" + - " uniform sampler2D inputImageTexture;\n" + - " varying highp vec2 textureCoordinate;\n" + - " \n" + - " uniform lowp float shadows;\n" + - " uniform lowp float highlights;\n" + - " \n" + - " const mediump vec3 luminanceWeighting = vec3(0.3, 0.3, 0.3);\n" + - " \n" + - " void main()\n" + - " {\n" + - " lowp vec4 source = texture2D(inputImageTexture, textureCoordinate);\n" + - " mediump float luminance = dot(source.rgb, luminanceWeighting);\n" + - " \n" + - " mediump float shadow = clamp((pow(luminance, 1.0/(shadows+1.0)) + (-0.76)*pow(luminance, 2.0/(shadows+1.0))) - luminance, 0.0, 1.0);\n" + - " mediump float highlight = clamp((1.0 - (pow(1.0-luminance, 1.0/(2.0-highlights)) + (-0.8)*pow(1.0-luminance, 2.0/(2.0-highlights)))) - luminance, -1.0, 0.0);\n" + - " lowp vec3 result = vec3(0.0, 0.0, 0.0) + ((luminance + shadow + highlight) - 0.0) * ((source.rgb - vec3(0.0, 0.0, 0.0))/(luminance - 0.0));\n" + - " \n" + - " gl_FragColor = vec4(result.rgb, source.a);\n" + - " }"; - - private int mShadowsLocation; - private float mShadows; - private int mHighlightsLocation; - private float mHighlights; - - public GPUImageHighlightShadowFilter() { - this(0.0f, 1.0f); - } - - public GPUImageHighlightShadowFilter(final float shadows, final float highlights) { - super(NO_FILTER_VERTEX_SHADER, HIGHLIGHT_SHADOW_FRAGMENT_SHADER); - mHighlights = highlights; - mShadows = shadows; - } - - @Override - public void onInit() { - super.onInit(); - mHighlightsLocation = GLES20.glGetUniformLocation(getProgram(), "highlights"); - mShadowsLocation = GLES20.glGetUniformLocation(getProgram(), "shadows"); - } - - @Override - public void onInitialized() { - super.onInitialized(); - setHighlights(mHighlights); - setShadows(mShadows); - } - - public void setHighlights(final float highlights) { - mHighlights = highlights; - setFloat(mHighlightsLocation, mHighlights); - } - - public void setShadows(final float shadows) { - mShadows = shadows; - setFloat(mShadowsLocation, mShadows); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageHueBlendFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageHueBlendFilter.java deleted file mode 100755 index 3950901..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageHueBlendFilter.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -public class GPUImageHueBlendFilter extends GPUImageTwoInputFilter { - public static final String HUE_BLEND_FRAGMENT_SHADER = "varying highp vec2 textureCoordinate;\n" + - " varying highp vec2 textureCoordinate2;\n" + - " \n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform sampler2D inputImageTexture2;\n" + - " \n" + - " highp float lum(lowp vec3 c) {\n" + - " return dot(c, vec3(0.3, 0.59, 0.11));\n" + - " }\n" + - " \n" + - " lowp vec3 clipcolor(lowp vec3 c) {\n" + - " highp float l = lum(c);\n" + - " lowp float n = min(min(c.r, c.g), c.b);\n" + - " lowp float x = max(max(c.r, c.g), c.b);\n" + - " \n" + - " if (n < 0.0) {\n" + - " c.r = l + ((c.r - l) * l) / (l - n);\n" + - " c.g = l + ((c.g - l) * l) / (l - n);\n" + - " c.b = l + ((c.b - l) * l) / (l - n);\n" + - " }\n" + - " if (x > 1.0) {\n" + - " c.r = l + ((c.r - l) * (1.0 - l)) / (x - l);\n" + - " c.g = l + ((c.g - l) * (1.0 - l)) / (x - l);\n" + - " c.b = l + ((c.b - l) * (1.0 - l)) / (x - l);\n" + - " }\n" + - " \n" + - " return c;\n" + - " }\n" + - " \n" + - " lowp vec3 setlum(lowp vec3 c, highp float l) {\n" + - " highp float d = l - lum(c);\n" + - " c = c + vec3(d);\n" + - " return clipcolor(c);\n" + - " }\n" + - " \n" + - " highp float sat(lowp vec3 c) {\n" + - " lowp float n = min(min(c.r, c.g), c.b);\n" + - " lowp float x = max(max(c.r, c.g), c.b);\n" + - " return x - n;\n" + - " }\n" + - " \n" + - " lowp float mid(lowp float cmin, lowp float cmid, lowp float cmax, highp float s) {\n" + - " return ((cmid - cmin) * s) / (cmax - cmin);\n" + - " }\n" + - " \n" + - " lowp vec3 setsat(lowp vec3 c, highp float s) {\n" + - " if (c.r > c.g) {\n" + - " if (c.r > c.b) {\n" + - " if (c.g > c.b) {\n" + - " /* g is mid, b is min */\n" + - " c.g = mid(c.b, c.g, c.r, s);\n" + - " c.b = 0.0;\n" + - " } else {\n" + - " /* b is mid, g is min */\n" + - " c.b = mid(c.g, c.b, c.r, s);\n" + - " c.g = 0.0;\n" + - " }\n" + - " c.r = s;\n" + - " } else {\n" + - " /* b is max, r is mid, g is min */\n" + - " c.r = mid(c.g, c.r, c.b, s);\n" + - " c.b = s;\n" + - " c.r = 0.0;\n" + - " }\n" + - " } else if (c.r > c.b) {\n" + - " /* g is max, r is mid, b is min */\n" + - " c.r = mid(c.b, c.r, c.g, s);\n" + - " c.g = s;\n" + - " c.b = 0.0;\n" + - " } else if (c.g > c.b) {\n" + - " /* g is max, b is mid, r is min */\n" + - " c.b = mid(c.r, c.b, c.g, s);\n" + - " c.g = s;\n" + - " c.r = 0.0;\n" + - " } else if (c.b > c.g) {\n" + - " /* b is max, g is mid, r is min */\n" + - " c.g = mid(c.r, c.g, c.b, s);\n" + - " c.b = s;\n" + - " c.r = 0.0;\n" + - " } else {\n" + - " c = vec3(0.0);\n" + - " }\n" + - " return c;\n" + - " }\n" + - " \n" + - " void main()\n" + - " {\n" + - " highp vec4 baseColor = texture2D(inputImageTexture, textureCoordinate);\n" + - " highp vec4 overlayColor = texture2D(inputImageTexture2, textureCoordinate2);\n" + - " \n" + - " gl_FragColor = vec4(baseColor.rgb * (1.0 - overlayColor.a) + setlum(setsat(overlayColor.rgb, sat(baseColor.rgb)), lum(baseColor.rgb)) * overlayColor.a, baseColor.a);\n" + - " }"; - - public GPUImageHueBlendFilter() { - super(HUE_BLEND_FRAGMENT_SHADER); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageHueFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageHueFilter.java deleted file mode 100755 index 9fcf793..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageHueFilter.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; - -public class GPUImageHueFilter extends GPUImageFilter { - public static final String HUE_FRAGMENT_SHADER = "" + - "precision highp float;\n" + - "varying highp vec2 textureCoordinate;\n" + - "\n" + - "uniform sampler2D inputImageTexture;\n" + - "uniform mediump float hueAdjust;\n" + - "const highp vec4 kRGBToYPrime = vec4 (0.299, 0.587, 0.114, 0.0);\n" + - "const highp vec4 kRGBToI = vec4 (0.595716, -0.274453, -0.321263, 0.0);\n" + - "const highp vec4 kRGBToQ = vec4 (0.211456, -0.522591, 0.31135, 0.0);\n" + - "\n" + - "const highp vec4 kYIQToR = vec4 (1.0, 0.9563, 0.6210, 0.0);\n" + - "const highp vec4 kYIQToG = vec4 (1.0, -0.2721, -0.6474, 0.0);\n" + - "const highp vec4 kYIQToB = vec4 (1.0, -1.1070, 1.7046, 0.0);\n" + - "\n" + - "void main ()\n" + - "{\n" + - " // Sample the input pixel\n" + - " highp vec4 color = texture2D(inputImageTexture, textureCoordinate);\n" + - "\n" + - " // Convert to YIQ\n" + - " highp float YPrime = dot (color, kRGBToYPrime);\n" + - " highp float I = dot (color, kRGBToI);\n" + - " highp float Q = dot (color, kRGBToQ);\n" + - "\n" + - " // Calculate the hue and chroma\n" + - " highp float hue = atan (Q, I);\n" + - " highp float chroma = sqrt (I * I + Q * Q);\n" + - "\n" + - " // Make the user's adjustments\n" + - " hue += (-hueAdjust); //why negative rotation?\n" + - "\n" + - " // Convert back to YIQ\n" + - " Q = chroma * sin (hue);\n" + - " I = chroma * cos (hue);\n" + - "\n" + - " // Convert back to RGB\n" + - " highp vec4 yIQ = vec4 (YPrime, I, Q, 0.0);\n" + - " color.r = dot (yIQ, kYIQToR);\n" + - " color.g = dot (yIQ, kYIQToG);\n" + - " color.b = dot (yIQ, kYIQToB);\n" + - "\n" + - " // Save the result\n" + - " gl_FragColor = color;\n" + - "}\n"; - - private float mHue; - private int mHueLocation; - - public GPUImageHueFilter() { - this(90.0f); - } - - public GPUImageHueFilter(final float hue) { - super(NO_FILTER_VERTEX_SHADER, HUE_FRAGMENT_SHADER); - mHue = hue; - } - - @Override - public void onInit() { - super.onInit(); - mHueLocation = GLES20.glGetUniformLocation(getProgram(), "hueAdjust"); - } - - @Override - public void onInitialized() { - super.onInitialized(); - setHue(mHue); - } - - public void setHue(final float hue) { - mHue = hue; - float hueAdjust = (mHue % 360.0f) * (float) Math.PI / 180.0f; - setFloat(mHueLocation, hueAdjust); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageKuwaharaFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageKuwaharaFilter.java deleted file mode 100755 index 6fc7f32..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageKuwaharaFilter.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; - -/** - * Kuwahara image abstraction, drawn from the work of Kyprianidis, et. al. in their publication - * "Anisotropic Kuwahara Filtering on the GPU" within the GPU Pro collection. This produces an oil-painting-like - * image, but it is extremely computationally expensive, so it can take seconds to render a frame on an iPad 2. - * This might be best used for still images. - */ -public class GPUImageKuwaharaFilter extends GPUImageFilter { - public static final String KUWAHARA_FRAGMENT_SHADER = "" + - "varying highp vec2 textureCoordinate;\n" + - "uniform sampler2D inputImageTexture;\n" + - "uniform int radius;\n" + - "\n" + - "precision highp float;\n" + - "\n" + - "const vec2 src_size = vec2 (1.0 / 768.0, 1.0 / 1024.0);\n" + - "\n" + - "void main (void) \n" + - "{\n" + - "vec2 uv = textureCoordinate;\n" + - "float n = float((radius + 1) * (radius + 1));\n" + - "int i; int j;\n" + - "vec3 m0 = vec3(0.0); vec3 m1 = vec3(0.0); vec3 m2 = vec3(0.0); vec3 m3 = vec3(0.0);\n" + - "vec3 s0 = vec3(0.0); vec3 s1 = vec3(0.0); vec3 s2 = vec3(0.0); vec3 s3 = vec3(0.0);\n" + - "vec3 c;\n" + - "\n" + - "for (j = -radius; j <= 0; ++j) {\n" + - "for (i = -radius; i <= 0; ++i) {\n" + - "c = texture2D(inputImageTexture, uv + vec2(i,j) * src_size).rgb;\n" + - "m0 += c;\n" + - "s0 += c * c;\n" + - "}\n" + - "}\n" + - "\n" + - "for (j = -radius; j <= 0; ++j) {\n" + - "for (i = 0; i <= radius; ++i) {\n" + - "c = texture2D(inputImageTexture, uv + vec2(i,j) * src_size).rgb;\n" + - "m1 += c;\n" + - "s1 += c * c;\n" + - "}\n" + - "}\n" + - "\n" + - "for (j = 0; j <= radius; ++j) {\n" + - "for (i = 0; i <= radius; ++i) {\n" + - "c = texture2D(inputImageTexture, uv + vec2(i,j) * src_size).rgb;\n" + - "m2 += c;\n" + - "s2 += c * c;\n" + - "}\n" + - "}\n" + - "\n" + - "for (j = 0; j <= radius; ++j) {\n" + - "for (i = -radius; i <= 0; ++i) {\n" + - "c = texture2D(inputImageTexture, uv + vec2(i,j) * src_size).rgb;\n" + - "m3 += c;\n" + - "s3 += c * c;\n" + - "}\n" + - "}\n" + - "\n" + - "\n" + - "float min_sigma2 = 1e+2;\n" + - "m0 /= n;\n" + - "s0 = abs(s0 / n - m0 * m0);\n" + - "\n" + - "float sigma2 = s0.r + s0.g + s0.b;\n" + - "if (sigma2 < min_sigma2) {\n" + - "min_sigma2 = sigma2;\n" + - "gl_FragColor = vec4(m0, 1.0);\n" + - "}\n" + - "\n" + - "m1 /= n;\n" + - "s1 = abs(s1 / n - m1 * m1);\n" + - "\n" + - "sigma2 = s1.r + s1.g + s1.b;\n" + - "if (sigma2 < min_sigma2) {\n" + - "min_sigma2 = sigma2;\n" + - "gl_FragColor = vec4(m1, 1.0);\n" + - "}\n" + - "\n" + - "m2 /= n;\n" + - "s2 = abs(s2 / n - m2 * m2);\n" + - "\n" + - "sigma2 = s2.r + s2.g + s2.b;\n" + - "if (sigma2 < min_sigma2) {\n" + - "min_sigma2 = sigma2;\n" + - "gl_FragColor = vec4(m2, 1.0);\n" + - "}\n" + - "\n" + - "m3 /= n;\n" + - "s3 = abs(s3 / n - m3 * m3);\n" + - "\n" + - "sigma2 = s3.r + s3.g + s3.b;\n" + - "if (sigma2 < min_sigma2) {\n" + - "min_sigma2 = sigma2;\n" + - "gl_FragColor = vec4(m3, 1.0);\n" + - "}\n" + - "}\n"; - - private int mRadius; - private int mRadiusLocation; - - public GPUImageKuwaharaFilter() { - this(3); - } - - public GPUImageKuwaharaFilter(int radius) { - super(NO_FILTER_VERTEX_SHADER, KUWAHARA_FRAGMENT_SHADER); - mRadius = radius; - } - - @Override - public void onInit() { - super.onInit(); - mRadiusLocation = GLES20.glGetUniformLocation(getProgram(), "radius"); - } - - @Override - public void onInitialized() { - super.onInitialized(); - setRadius(mRadius); - } - - /** - * The radius to sample from when creating the brush-stroke effect, with a default of 3. - * The larger the radius, the slower the filter. - * - * @param radius default 3 - */ - public void setRadius(final int radius) { - mRadius = radius; - setInteger(mRadiusLocation, radius); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageLaplacianFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageLaplacianFilter.java deleted file mode 100755 index d320f64..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageLaplacianFilter.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; - -public class GPUImageLaplacianFilter extends GPUImage3x3TextureSamplingFilter { - public static final String LAPLACIAN_FRAGMENT_SHADER = "" + - "precision highp float;\n" + - "\n" + - "uniform sampler2D inputImageTexture;\n" + - "\n" + - "uniform mediump mat3 convolutionMatrix;\n" + - "\n" + - "varying vec2 textureCoordinate;\n" + - "varying vec2 leftTextureCoordinate;\n" + - "varying vec2 rightTextureCoordinate;\n" + - "\n" + - "varying vec2 topTextureCoordinate;\n" + - "varying vec2 topLeftTextureCoordinate;\n" + - "varying vec2 topRightTextureCoordinate;\n" + - "\n" + - "varying vec2 bottomTextureCoordinate;\n" + - "varying vec2 bottomLeftTextureCoordinate;\n" + - "varying vec2 bottomRightTextureCoordinate;\n" + - "\n" + - "void main()\n" + - "{\n" + - "mediump vec3 bottomColor = texture2D(inputImageTexture, bottomTextureCoordinate).rgb;\n" + - "mediump vec3 bottomLeftColor = texture2D(inputImageTexture, bottomLeftTextureCoordinate).rgb;\n" + - "mediump vec3 bottomRightColor = texture2D(inputImageTexture, bottomRightTextureCoordinate).rgb;\n" + - "mediump vec4 centerColor = texture2D(inputImageTexture, textureCoordinate);\n" + - "mediump vec3 leftColor = texture2D(inputImageTexture, leftTextureCoordinate).rgb;\n" + - "mediump vec3 rightColor = texture2D(inputImageTexture, rightTextureCoordinate).rgb;\n" + - "mediump vec3 topColor = texture2D(inputImageTexture, topTextureCoordinate).rgb;\n" + - "mediump vec3 topRightColor = texture2D(inputImageTexture, topRightTextureCoordinate).rgb;\n" + - "mediump vec3 topLeftColor = texture2D(inputImageTexture, topLeftTextureCoordinate).rgb;\n" + - "\n" + - "mediump vec3 resultColor = topLeftColor * convolutionMatrix[0][0] + topColor * convolutionMatrix[0][1] + topRightColor * convolutionMatrix[0][2];\n" + - "resultColor += leftColor * convolutionMatrix[1][0] + centerColor.rgb * convolutionMatrix[1][1] + rightColor * convolutionMatrix[1][2];\n" + - "resultColor += bottomLeftColor * convolutionMatrix[2][0] + bottomColor * convolutionMatrix[2][1] + bottomRightColor * convolutionMatrix[2][2];\n" + - "\n" + - "// Normalize the results to allow for negative gradients in the 0.0-1.0 colorspace\n" + - "resultColor = resultColor + 0.5;\n" + - "\n" + - "gl_FragColor = vec4(resultColor, centerColor.a);\n" + - "}\n"; - - private float[] mConvolutionKernel; - private int mUniformConvolutionMatrix; - - public GPUImageLaplacianFilter() { - this(new float[]{ - 0.5f, 1.0f, 0.5f, - 1.0f, -6.0f, 1.0f, - 0.5f, 1.0f, 0.5f - }); - } - - private GPUImageLaplacianFilter(final float[] convolutionKernel) { - super(LAPLACIAN_FRAGMENT_SHADER); - mConvolutionKernel = convolutionKernel; - } - - @Override - public void onInit() { - super.onInit(); - mUniformConvolutionMatrix = GLES20.glGetUniformLocation(getProgram(), "convolutionMatrix"); - setConvolutionKernel(mConvolutionKernel); - } - - private void setConvolutionKernel(final float[] convolutionKernel) { - mConvolutionKernel = convolutionKernel; - setUniformMatrix3f(mUniformConvolutionMatrix, mConvolutionKernel); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageLevelsFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageLevelsFilter.java deleted file mode 100755 index d7fbcfd..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageLevelsFilter.java +++ /dev/null @@ -1,130 +0,0 @@ -package jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; -import android.util.Log; - -/** - * Created by vashisthg 30/05/14. - */ -public class GPUImageLevelsFilter extends GPUImageFilter{ - - private static final String LOGTAG = GPUImageLevelsFilter.class.getSimpleName(); - - public static final String LEVELS_FRAGMET_SHADER = - - " varying highp vec2 textureCoordinate;\n" + - " \n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform mediump vec3 levelMinimum;\n" + - " uniform mediump vec3 levelMiddle;\n" + - " uniform mediump vec3 levelMaximum;\n" + - " uniform mediump vec3 minOutput;\n" + - " uniform mediump vec3 maxOutput;\n" + - " \n" + - " void main()\n" + - " {\n" + - " mediump vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + - " \n" + - " gl_FragColor = vec4( mix(minOutput, maxOutput, pow(min(max(textureColor.rgb -levelMinimum, vec3(0.0)) / (levelMaximum - levelMinimum ), vec3(1.0)), 1.0 /levelMiddle)) , textureColor.a);\n" + - " }\n"; - - private int mMinLocation; - private float[] mMin; - private int mMidLocation; - private float[] mMid; - private int mMaxLocation; - private float[] mMax; - private int mMinOutputLocation; - private float[] mMinOutput; - private int mMaxOutputLocation; - private float[] mMaxOutput; - - public GPUImageLevelsFilter() { - this(new float[] {0.0f,0.0f,0.0f}, new float[] {1.0f, 1.0f, 1.0f }, new float[] {1.0f, 1.0f ,1.0f}, new float[] {0.0f, 0.0f, 0.0f}, new float[] {1.0f,1.0f,1.0f}); - } - - private GPUImageLevelsFilter(final float[] min, final float[] mid, final float[] max, final float[] minOUt, final float[] maxOut) { - super(NO_FILTER_VERTEX_SHADER, LEVELS_FRAGMET_SHADER); - - mMin = min; - mMid = mid; - mMax = max; - mMinOutput = minOUt; - mMaxOutput = maxOut; - setMin(0.0f, 1.0f, 1.0f, 0.0f, 1.0f); - } - - @Override - public void onInit() { - super.onInit(); - mMinLocation = GLES20.glGetUniformLocation(getProgram(), "levelMinimum"); - mMidLocation = GLES20.glGetUniformLocation(getProgram(), "levelMiddle"); - mMaxLocation = GLES20.glGetUniformLocation(getProgram(), "levelMaximum"); - mMinOutputLocation = GLES20.glGetUniformLocation(getProgram(), "minOutput"); - mMaxOutputLocation = GLES20.glGetUniformLocation(getProgram(), "maxOutput"); - } - - @Override - public void onInitialized() { - super.onInitialized(); - updateUniforms(); - } - - - public void updateUniforms () { - setFloatVec3(mMinLocation, mMin); - setFloatVec3(mMidLocation, mMid); - setFloatVec3(mMaxLocation, mMax); - setFloatVec3(mMinOutputLocation, mMinOutput); - setFloatVec3(mMaxOutputLocation, mMaxOutput); - } - - public void setMin(float min, float mid , float max ,float minOut , float maxOut) { - setRedMin(min, mid, max, minOut, maxOut); - setGreenMin(min, mid, max, minOut, maxOut); - setBlueMin(min, mid, max, minOut, maxOut); - } - - public void setMin(float min, float mid , float max ) { - setMin(min, mid, max, 0.0f, 1.0f); - } - - public void setRedMin(float min, float mid , float max ,float minOut , float maxOut) { - mMin[0] = min; - mMid[0] = mid; - mMax[0] = max; - mMinOutput[0] = minOut; - mMaxOutput[0] = maxOut; - updateUniforms(); - } - - public void setRedMin(float min, float mid , float max ){ - setRedMin(min, mid, max, 0, 1); - } - - public void setGreenMin(float min, float mid , float max ,float minOut , float maxOut) { - mMin[1] = min; - mMid[1] = mid; - mMax[1] = max; - mMinOutput[1] = minOut; - mMaxOutput[1] = maxOut; - updateUniforms(); - } - - public void setGreenMin(float min, float mid , float max ){ - setGreenMin(min, mid, max, 0, 1); - } - - public void setBlueMin(float min, float mid , float max ,float minOut , float maxOut) { - mMin[2] = min; - mMid[2] = mid; - mMax[2] = max; - mMinOutput[2] = minOut; - mMaxOutput[2] = maxOut; - updateUniforms(); - } - - public void setBlueMin(float min, float mid , float max ){ - setBlueMin(min, mid, max, 0, 1); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageLightenBlendFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageLightenBlendFilter.java deleted file mode 100755 index 77399cb..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageLightenBlendFilter.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -public class GPUImageLightenBlendFilter extends GPUImageTwoInputFilter { - public static final String LIGHTEN_BLEND_FRAGMENT_SHADER = "varying highp vec2 textureCoordinate;\n" + - " varying highp vec2 textureCoordinate2;\n" + - "\n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform sampler2D inputImageTexture2;\n" + - " \n" + - " void main()\n" + - " {\n" + - " lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + - " lowp vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);\n" + - " \n" + - " gl_FragColor = max(textureColor, textureColor2);\n" + - " }"; - - public GPUImageLightenBlendFilter() { - super(LIGHTEN_BLEND_FRAGMENT_SHADER); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageLinearBurnBlendFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageLinearBurnBlendFilter.java deleted file mode 100755 index 2623b52..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageLinearBurnBlendFilter.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -public class GPUImageLinearBurnBlendFilter extends GPUImageTwoInputFilter { - public static final String LINEAR_BURN_BLEND_FRAGMENT_SHADER = "varying highp vec2 textureCoordinate;\n" + - " varying highp vec2 textureCoordinate2;\n" + - " \n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform sampler2D inputImageTexture2;\n" + - " \n" + - " void main()\n" + - " {\n" + - " mediump vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + - " mediump vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);\n" + - " \n" + - " gl_FragColor = vec4(clamp(textureColor.rgb + textureColor2.rgb - vec3(1.0), vec3(0.0), vec3(1.0)), textureColor.a);\n" + - " }"; - - public GPUImageLinearBurnBlendFilter() { - super(LINEAR_BURN_BLEND_FRAGMENT_SHADER); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageLookupFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageLookupFilter.java deleted file mode 100755 index b9cfa2b..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageLookupFilter.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -public class GPUImageLookupFilter extends GPUImageTwoInputFilter { - - public static final String LOOKUP_FRAGMENT_SHADER = "varying highp vec2 textureCoordinate;\n" + - " varying highp vec2 textureCoordinate2; // TODO: This is not used\n" + - " \n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform sampler2D inputImageTexture2; // lookup texture\n" + - " \n" + - " void main()\n" + - " {\n" + - " lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + - " \n" + - " mediump float blueColor = textureColor.b * 63.0;\n" + - " \n" + - " mediump vec2 quad1;\n" + - " quad1.y = floor(floor(blueColor) / 8.0);\n" + - " quad1.x = floor(blueColor) - (quad1.y * 8.0);\n" + - " \n" + - " mediump vec2 quad2;\n" + - " quad2.y = floor(ceil(blueColor) / 8.0);\n" + - " quad2.x = ceil(blueColor) - (quad2.y * 8.0);\n" + - " \n" + - " highp vec2 texPos1;\n" + - " texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);\n" + - " texPos1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);\n" + - " \n" + - " highp vec2 texPos2;\n" + - " texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);\n" + - " texPos2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);\n" + - " \n" + - " lowp vec4 newColor1 = texture2D(inputImageTexture2, texPos1);\n" + - " lowp vec4 newColor2 = texture2D(inputImageTexture2, texPos2);\n" + - " \n" + - " lowp vec4 newColor = mix(newColor1, newColor2, fract(blueColor));\n" + - " gl_FragColor = vec4(newColor.rgb, textureColor.w);\n" + - " }"; - - - public GPUImageLookupFilter() { - super(LOOKUP_FRAGMENT_SHADER); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageLuminosityBlendFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageLuminosityBlendFilter.java deleted file mode 100755 index 85e7bfd..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageLuminosityBlendFilter.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -public class GPUImageLuminosityBlendFilter extends GPUImageTwoInputFilter { - public static final String LUMINOSITY_BLEND_FRAGMENT_SHADER = "varying highp vec2 textureCoordinate;\n" + - " varying highp vec2 textureCoordinate2;\n" + - " \n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform sampler2D inputImageTexture2;\n" + - " \n" + - " highp float lum(lowp vec3 c) {\n" + - " return dot(c, vec3(0.3, 0.59, 0.11));\n" + - " }\n" + - " \n" + - " lowp vec3 clipcolor(lowp vec3 c) {\n" + - " highp float l = lum(c);\n" + - " lowp float n = min(min(c.r, c.g), c.b);\n" + - " lowp float x = max(max(c.r, c.g), c.b);\n" + - " \n" + - " if (n < 0.0) {\n" + - " c.r = l + ((c.r - l) * l) / (l - n);\n" + - " c.g = l + ((c.g - l) * l) / (l - n);\n" + - " c.b = l + ((c.b - l) * l) / (l - n);\n" + - " }\n" + - " if (x > 1.0) {\n" + - " c.r = l + ((c.r - l) * (1.0 - l)) / (x - l);\n" + - " c.g = l + ((c.g - l) * (1.0 - l)) / (x - l);\n" + - " c.b = l + ((c.b - l) * (1.0 - l)) / (x - l);\n" + - " }\n" + - " \n" + - " return c;\n" + - " }\n" + - " \n" + - " lowp vec3 setlum(lowp vec3 c, highp float l) {\n" + - " highp float d = l - lum(c);\n" + - " c = c + vec3(d);\n" + - " return clipcolor(c);\n" + - " }\n" + - " \n" + - " void main()\n" + - " {\n" + - " highp vec4 baseColor = texture2D(inputImageTexture, textureCoordinate);\n" + - " highp vec4 overlayColor = texture2D(inputImageTexture2, textureCoordinate2);\n" + - " \n" + - " gl_FragColor = vec4(baseColor.rgb * (1.0 - overlayColor.a) + setlum(baseColor.rgb, lum(overlayColor.rgb)) * overlayColor.a, baseColor.a);\n" + - " }"; - - public GPUImageLuminosityBlendFilter() { - super(LUMINOSITY_BLEND_FRAGMENT_SHADER); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageMixBlendFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageMixBlendFilter.java deleted file mode 100755 index 7bf6885..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageMixBlendFilter.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; - -public class GPUImageMixBlendFilter extends GPUImageTwoInputFilter { - - private int mMixLocation; - private float mMix; - - public GPUImageMixBlendFilter(String fragmentShader) { - this(fragmentShader, 0.5f); - } - - public GPUImageMixBlendFilter(String fragmentShader, float mix) { - super(fragmentShader); - mMix = mix; - } - - @Override - public void onInit() { - super.onInit(); - mMixLocation = GLES20.glGetUniformLocation(getProgram(), "mixturePercent"); - } - - @Override - public void onInitialized() { - super.onInitialized(); - setMix(mMix); - } - - /** - * @param mix ranges from 0.0 (only image 1) to 1.0 (only image 2), with 0.5 (half of either) as the normal level - */ - public void setMix(final float mix) { - mMix = mix; - setFloat(mMixLocation, mMix); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageMonochromeFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageMonochromeFilter.java deleted file mode 100755 index e426a34..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageMonochromeFilter.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; - -/** - * Converts the image to a single-color version, based on the luminance of each pixel - * intensity: The degree to which the specific color replaces the normal image color (0.0 - 1.0, with 1.0 as the default) - * color: The color to use as the basis for the effect, with (0.6, 0.45, 0.3, 1.0) as the default. - */ -public class GPUImageMonochromeFilter extends GPUImageFilter { - public static final String MONOCHROME_FRAGMENT_SHADER = "" + - " precision lowp float;\n" + - " \n" + - " varying highp vec2 textureCoordinate;\n" + - " \n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform float intensity;\n" + - " uniform vec3 filterColor;\n" + - " \n" + - " const mediump vec3 luminanceWeighting = vec3(0.2125, 0.7154, 0.0721);\n" + - " \n" + - " void main()\n" + - " {\n" + - " //desat, then apply overlay blend\n" + - " lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + - " float luminance = dot(textureColor.rgb, luminanceWeighting);\n" + - " \n" + - " lowp vec4 desat = vec4(vec3(luminance), 1.0);\n" + - " \n" + - " //overlay\n" + - " lowp vec4 outputColor = vec4(\n" + - " (desat.r < 0.5 ? (2.0 * desat.r * filterColor.r) : (1.0 - 2.0 * (1.0 - desat.r) * (1.0 - filterColor.r))),\n" + - " (desat.g < 0.5 ? (2.0 * desat.g * filterColor.g) : (1.0 - 2.0 * (1.0 - desat.g) * (1.0 - filterColor.g))),\n" + - " (desat.b < 0.5 ? (2.0 * desat.b * filterColor.b) : (1.0 - 2.0 * (1.0 - desat.b) * (1.0 - filterColor.b))),\n" + - " 1.0\n" + - " );\n" + - " \n" + - " //which is better, or are they equal?\n" + - " gl_FragColor = vec4( mix(textureColor.rgb, outputColor.rgb, intensity), textureColor.a);\n" + - " }"; - - private int mIntensityLocation; - private float mIntensity; - private int mFilterColorLocation; - private float[] mColor; - - public GPUImageMonochromeFilter() { - this(1.0f, new float[] {0.6f, 0.45f, 0.3f, 1.0f}); - } - - public GPUImageMonochromeFilter(final float intensity, final float[] color) { - super(NO_FILTER_VERTEX_SHADER, MONOCHROME_FRAGMENT_SHADER); - mIntensity = intensity; - mColor = color; - } - - @Override - public void onInit() { - super.onInit(); - mIntensityLocation = GLES20.glGetUniformLocation(getProgram(), "intensity"); - mFilterColorLocation = GLES20.glGetUniformLocation(getProgram(), "filterColor"); - } - - @Override - public void onInitialized() { - super.onInitialized(); - setIntensity(1.0f); - setColor(new float[]{ 0.6f, 0.45f, 0.3f, 1.f }); - } - - public void setIntensity(final float intensity) { - mIntensity = intensity; - setFloat(mIntensityLocation, mIntensity); - } - - public void setColor(final float[] color) { - mColor = color; - setColorRed(mColor[0], mColor[1], mColor[2]); - - } - - public void setColorRed(final float red, final float green, final float blue) { - setFloatVec3(mFilterColorLocation, new float[]{ red, green, blue }); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageMultiplyBlendFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageMultiplyBlendFilter.java deleted file mode 100755 index 1e002e3..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageMultiplyBlendFilter.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -public class GPUImageMultiplyBlendFilter extends GPUImageTwoInputFilter { - public static final String MULTIPLY_BLEND_FRAGMENT_SHADER = "varying highp vec2 textureCoordinate;\n" + - " varying highp vec2 textureCoordinate2;\n" + - "\n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform sampler2D inputImageTexture2;\n" + - " \n" + - " void main()\n" + - " {\n" + - " lowp vec4 base = texture2D(inputImageTexture, textureCoordinate);\n" + - " lowp vec4 overlayer = texture2D(inputImageTexture2, textureCoordinate2);\n" + - " \n" + - " gl_FragColor = overlayer * base + overlayer * (1.0 - base.a) + base * (1.0 - overlayer.a);\n" + - " }"; - - public GPUImageMultiplyBlendFilter() { - super(MULTIPLY_BLEND_FRAGMENT_SHADER); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageNativeLibrary.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageNativeLibrary.java deleted file mode 100755 index ce8c31b..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageNativeLibrary.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -public class GPUImageNativeLibrary { - static { - System.loadLibrary("gpuimage-library"); - } - - public static native void YUVtoRBGA(byte[] yuv, int width, int height, int[] out); - - public static native void YUVtoARBG(byte[] yuv, int width, int height, int[] out); -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageNonMaximumSuppressionFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageNonMaximumSuppressionFilter.java deleted file mode 100755 index a6f5af4..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageNonMaximumSuppressionFilter.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -public class GPUImageNonMaximumSuppressionFilter extends GPUImage3x3TextureSamplingFilter { - public static final String NMS_FRAGMENT_SHADER = "" + - "uniform sampler2D inputImageTexture;\n" + - "\n" + - "varying highp vec2 textureCoordinate;\n" + - "varying highp vec2 leftTextureCoordinate;\n" + - "varying highp vec2 rightTextureCoordinate;\n" + - "\n" + - "varying highp vec2 topTextureCoordinate;\n" + - "varying highp vec2 topLeftTextureCoordinate;\n" + - "varying highp vec2 topRightTextureCoordinate;\n" + - "\n" + - "varying highp vec2 bottomTextureCoordinate;\n" + - "varying highp vec2 bottomLeftTextureCoordinate;\n" + - "varying highp vec2 bottomRightTextureCoordinate;\n" + - "\n" + - "void main()\n" + - "{\n" + - "lowp float bottomColor = texture2D(inputImageTexture, bottomTextureCoordinate).r;\n" + - "lowp float bottomLeftColor = texture2D(inputImageTexture, bottomLeftTextureCoordinate).r;\n" + - "lowp float bottomRightColor = texture2D(inputImageTexture, bottomRightTextureCoordinate).r;\n" + - "lowp vec4 centerColor = texture2D(inputImageTexture, textureCoordinate);\n" + - "lowp float leftColor = texture2D(inputImageTexture, leftTextureCoordinate).r;\n" + - "lowp float rightColor = texture2D(inputImageTexture, rightTextureCoordinate).r;\n" + - "lowp float topColor = texture2D(inputImageTexture, topTextureCoordinate).r;\n" + - "lowp float topRightColor = texture2D(inputImageTexture, topRightTextureCoordinate).r;\n" + - "lowp float topLeftColor = texture2D(inputImageTexture, topLeftTextureCoordinate).r;\n" + - "\n" + - "// Use a tiebreaker for pixels to the left and immediately above this one\n" + - "lowp float multiplier = 1.0 - step(centerColor.r, topColor);\n" + - "multiplier = multiplier * 1.0 - step(centerColor.r, topLeftColor);\n" + - "multiplier = multiplier * 1.0 - step(centerColor.r, leftColor);\n" + - "multiplier = multiplier * 1.0 - step(centerColor.r, bottomLeftColor);\n" + - "\n" + - "lowp float maxValue = max(centerColor.r, bottomColor);\n" + - "maxValue = max(maxValue, bottomRightColor);\n" + - "maxValue = max(maxValue, rightColor);\n" + - "maxValue = max(maxValue, topRightColor);\n" + - "\n" + - "gl_FragColor = vec4((centerColor.rgb * step(maxValue, centerColor.r) * multiplier), 1.0);\n" + - "}\n"; - - public GPUImageNonMaximumSuppressionFilter() { - super(NMS_FRAGMENT_SHADER); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageNormalBlendFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageNormalBlendFilter.java deleted file mode 100755 index a886bd4..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageNormalBlendFilter.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -/** - * This equation is a simplification of the general blending equation. It assumes the destination color is opaque, and therefore drops the destination color's alpha term. - * - * D = C1 * C1a + C2 * C2a * (1 - C1a) - * where D is the resultant color, C1 is the color of the first element, C1a is the alpha of the first element, C2 is the second element color, C2a is the alpha of the second element. The destination alpha is calculated with: - * - * Da = C1a + C2a * (1 - C1a) - * The resultant color is premultiplied with the alpha. To restore the color to the unmultiplied values, just divide by Da, the resultant alpha. - * - * http://stackoverflow.com/questions/1724946/blend-mode-on-a-transparent-and-semi-transparent-background - * - * For some reason Photoshop behaves - * D = C1 + C2 * C2a * (1 - C1a) - */ -public class GPUImageNormalBlendFilter extends GPUImageTwoInputFilter { - public static final String NORMAL_BLEND_FRAGMENT_SHADER = "varying highp vec2 textureCoordinate;\n" + - " varying highp vec2 textureCoordinate2;\n" + - " \n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform sampler2D inputImageTexture2;\n" + - " \n" + - " void main()\n" + - " {\n" + - " lowp vec4 c2 = texture2D(inputImageTexture, textureCoordinate);\n" + - "\t lowp vec4 c1 = texture2D(inputImageTexture2, textureCoordinate2);\n" + - " \n" + - " lowp vec4 outputColor;\n" + - " \n" + - " outputColor.r = c1.r + c2.r * c2.a * (1.0 - c1.a);\n" + - "\n" + - " outputColor.g = c1.g + c2.g * c2.a * (1.0 - c1.a);\n" + - " \n" + - " outputColor.b = c1.b + c2.b * c2.a * (1.0 - c1.a);\n" + - " \n" + - " outputColor.a = c1.a + c2.a * (1.0 - c1.a);\n" + - " \n" + - " gl_FragColor = outputColor;\n" + - " }"; - - public GPUImageNormalBlendFilter() { - super(NORMAL_BLEND_FRAGMENT_SHADER); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageOpacityFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageOpacityFilter.java deleted file mode 100755 index 55f198d..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageOpacityFilter.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; - -/** - * Adjusts the alpha channel of the incoming image - * opacity: The value to multiply the incoming alpha channel for each pixel by (0.0 - 1.0, with 1.0 as the default) -*/ -public class GPUImageOpacityFilter extends GPUImageFilter { - public static final String OPACITY_FRAGMENT_SHADER = "" + - " varying highp vec2 textureCoordinate;\n" + - " \n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform lowp float opacity;\n" + - " \n" + - " void main()\n" + - " {\n" + - " lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + - " \n" + - " gl_FragColor = vec4(textureColor.rgb, textureColor.a * opacity);\n" + - " }\n"; - - private int mOpacityLocation; - private float mOpacity; - - public GPUImageOpacityFilter() { - this(1.0f); - } - - public GPUImageOpacityFilter(final float opacity) { - super(NO_FILTER_VERTEX_SHADER, OPACITY_FRAGMENT_SHADER); - mOpacity = opacity; - } - - @Override - public void onInit() { - super.onInit(); - mOpacityLocation = GLES20.glGetUniformLocation(getProgram(), "opacity"); - } - - @Override - public void onInitialized() { - super.onInitialized(); - setOpacity(mOpacity); - } - - public void setOpacity(final float opacity) { - mOpacity = opacity; - setFloat(mOpacityLocation, mOpacity); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageOverlayBlendFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageOverlayBlendFilter.java deleted file mode 100755 index 4dba420..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageOverlayBlendFilter.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -public class GPUImageOverlayBlendFilter extends GPUImageTwoInputFilter { - public static final String OVERLAY_BLEND_FRAGMENT_SHADER = "varying highp vec2 textureCoordinate;\n" + - " varying highp vec2 textureCoordinate2;\n" + - "\n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform sampler2D inputImageTexture2;\n" + - " \n" + - " void main()\n" + - " {\n" + - " mediump vec4 base = texture2D(inputImageTexture, textureCoordinate);\n" + - " mediump vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);\n" + - " \n" + - " mediump float ra;\n" + - " if (2.0 * base.r < base.a) {\n" + - " ra = 2.0 * overlay.r * base.r + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);\n" + - " } else {\n" + - " ra = overlay.a * base.a - 2.0 * (base.a - base.r) * (overlay.a - overlay.r) + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);\n" + - " }\n" + - " \n" + - " mediump float ga;\n" + - " if (2.0 * base.g < base.a) {\n" + - " ga = 2.0 * overlay.g * base.g + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);\n" + - " } else {\n" + - " ga = overlay.a * base.a - 2.0 * (base.a - base.g) * (overlay.a - overlay.g) + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);\n" + - " }\n" + - " \n" + - " mediump float ba;\n" + - " if (2.0 * base.b < base.a) {\n" + - " ba = 2.0 * overlay.b * base.b + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);\n" + - " } else {\n" + - " ba = overlay.a * base.a - 2.0 * (base.a - base.b) * (overlay.a - overlay.b) + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);\n" + - " }\n" + - " \n" + - " gl_FragColor = vec4(ra, ga, ba, 1.0);\n" + - " }"; - - public GPUImageOverlayBlendFilter() { - super(OVERLAY_BLEND_FRAGMENT_SHADER); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImagePixelationFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImagePixelationFilter.java deleted file mode 100755 index c0ec15d..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImagePixelationFilter.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; -/** - * Applies a grayscale effect to the image. - */ -public class GPUImagePixelationFilter extends GPUImageFilter { - public static final String PIXELATION_FRAGMENT_SHADER = "" + - "precision highp float;\n" + - - "varying vec2 textureCoordinate;\n" + - - "uniform float imageWidthFactor;\n" + - "uniform float imageHeightFactor;\n" + - "uniform sampler2D inputImageTexture;\n" + - "uniform float pixel;\n" + - - "void main()\n" + - "{\n" + - " vec2 uv = textureCoordinate.xy;\n" + - " float dx = pixel * imageWidthFactor;\n" + - " float dy = pixel * imageHeightFactor;\n" + - " vec2 coord = vec2(dx * floor(uv.x / dx), dy * floor(uv.y / dy));\n" + - " vec3 tc = texture2D(inputImageTexture, coord).xyz;\n" + - " gl_FragColor = vec4(tc, 1.0);\n" + - "}"; - - private int mImageWidthFactorLocation; - private int mImageHeightFactorLocation; - private float mPixel; - private int mPixelLocation; - - public GPUImagePixelationFilter() { - super(NO_FILTER_VERTEX_SHADER, PIXELATION_FRAGMENT_SHADER); - mPixel = 1.0f; - } - - @Override - public void onInit() { - super.onInit(); - mImageWidthFactorLocation = GLES20.glGetUniformLocation(getProgram(), "imageWidthFactor"); - mImageHeightFactorLocation = GLES20.glGetUniformLocation(getProgram(), "imageHeightFactor"); - mPixelLocation = GLES20.glGetUniformLocation(getProgram(), "pixel"); - setPixel(mPixel); - } - - @Override - public void onOutputSizeChanged(final int width, final int height) { - super.onOutputSizeChanged(width, height); - setFloat(mImageWidthFactorLocation, 1.0f / width); - setFloat(mImageHeightFactorLocation, 1.0f / height); - } - - public void setPixel(final float pixel) { - mPixel = pixel; - setFloat(mPixelLocation, mPixel); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImagePosterizeFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImagePosterizeFilter.java deleted file mode 100755 index 3b7c8ff..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImagePosterizeFilter.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; - -/** - * Reduces the color range of the image.
    - *
    - * colorLevels: ranges from 1 to 256, with a default of 10 - */ -public class GPUImagePosterizeFilter extends GPUImageFilter { - public static final String POSTERIZE_FRAGMENT_SHADER = "" + - "varying highp vec2 textureCoordinate;\n" + - "\n" + - "uniform sampler2D inputImageTexture;\n" + - "uniform highp float colorLevels;\n" + - "\n" + - "void main()\n" + - "{\n" + - " highp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + - " \n" + - " gl_FragColor = floor((textureColor * colorLevels) + vec4(0.5)) / colorLevels;\n" + - "}"; - - private int mGLUniformColorLevels; - private int mColorLevels; - - public GPUImagePosterizeFilter() { - this(10); - } - - public GPUImagePosterizeFilter(final int colorLevels) { - super(GPUImageFilter.NO_FILTER_VERTEX_SHADER, POSTERIZE_FRAGMENT_SHADER); - mColorLevels = colorLevels; - } - - @Override - public void onInit() { - super.onInit(); - mGLUniformColorLevels = GLES20.glGetUniformLocation(getProgram(), "colorLevels"); - setColorLevels(mColorLevels); - } - - public void setColorLevels(final int colorLevels) { - mColorLevels = colorLevels; - setFloat(mGLUniformColorLevels, colorLevels); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageRGBDilationFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageRGBDilationFilter.java deleted file mode 100755 index 2d5e28c..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageRGBDilationFilter.java +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -/** - * For each pixel, this sets it to the maximum value of each color channel in a rectangular neighborhood extending - * out dilationRadius pixels from the center. - * This extends out brighter colors, and can be used for abstraction of color images. - */ -public class GPUImageRGBDilationFilter extends GPUImageTwoPassTextureSamplingFilter { - public static final String VERTEX_SHADER_1 = - "attribute vec4 position;\n" + - "attribute vec2 inputTextureCoordinate;\n" + - "\n" + - "uniform float texelWidthOffset; \n" + - "uniform float texelHeightOffset; \n" + - "\n" + - "varying vec2 centerTextureCoordinate;\n" + - "varying vec2 oneStepPositiveTextureCoordinate;\n" + - "varying vec2 oneStepNegativeTextureCoordinate;\n" + - "\n" + - "void main()\n" + - "{\n" + - "gl_Position = position;\n" + - "\n" + - "vec2 offset = vec2(texelWidthOffset, texelHeightOffset);\n" + - "\n" + - "centerTextureCoordinate = inputTextureCoordinate;\n" + - "oneStepNegativeTextureCoordinate = inputTextureCoordinate - offset;\n" + - "oneStepPositiveTextureCoordinate = inputTextureCoordinate + offset;\n" + - "}\n"; - - public static final String VERTEX_SHADER_2 = - "attribute vec4 position;\n" + - "attribute vec2 inputTextureCoordinate;\n" + - "\n" + - "uniform float texelWidthOffset;\n" + - "uniform float texelHeightOffset;\n" + - "\n" + - "varying vec2 centerTextureCoordinate;\n" + - "varying vec2 oneStepPositiveTextureCoordinate;\n" + - "varying vec2 oneStepNegativeTextureCoordinate;\n" + - "varying vec2 twoStepsPositiveTextureCoordinate;\n" + - "varying vec2 twoStepsNegativeTextureCoordinate;\n" + - "\n" + - "void main()\n" + - "{\n" + - "gl_Position = position;\n" + - "\n" + - "vec2 offset = vec2(texelWidthOffset, texelHeightOffset);\n" + - "\n" + - "centerTextureCoordinate = inputTextureCoordinate;\n" + - "oneStepNegativeTextureCoordinate = inputTextureCoordinate - offset;\n" + - "oneStepPositiveTextureCoordinate = inputTextureCoordinate + offset;\n" + - "twoStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 2.0);\n" + - "twoStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 2.0);\n" + - "}\n"; - - public static final String VERTEX_SHADER_3 = - "attribute vec4 position;\n" + - "attribute vec2 inputTextureCoordinate;\n" + - "\n" + - "uniform float texelWidthOffset;\n" + - "uniform float texelHeightOffset;\n" + - "\n" + - "varying vec2 centerTextureCoordinate;\n" + - "varying vec2 oneStepPositiveTextureCoordinate;\n" + - "varying vec2 oneStepNegativeTextureCoordinate;\n" + - "varying vec2 twoStepsPositiveTextureCoordinate;\n" + - "varying vec2 twoStepsNegativeTextureCoordinate;\n" + - "varying vec2 threeStepsPositiveTextureCoordinate;\n" + - "varying vec2 threeStepsNegativeTextureCoordinate;\n" + - "\n" + - "void main()\n" + - "{\n" + - "gl_Position = position;\n" + - "\n" + - "vec2 offset = vec2(texelWidthOffset, texelHeightOffset);\n" + - "\n" + - "centerTextureCoordinate = inputTextureCoordinate;\n" + - "oneStepNegativeTextureCoordinate = inputTextureCoordinate - offset;\n" + - "oneStepPositiveTextureCoordinate = inputTextureCoordinate + offset;\n" + - "twoStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 2.0);\n" + - "twoStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 2.0);\n" + - "threeStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 3.0);\n" + - "threeStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 3.0);\n" + - "}\n"; - - public static final String VERTEX_SHADER_4 = - "attribute vec4 position;\n" + - "attribute vec2 inputTextureCoordinate;\n" + - "\n" + - "uniform float texelWidthOffset;\n" + - "uniform float texelHeightOffset;\n" + - "\n" + - "varying vec2 centerTextureCoordinate;\n" + - "varying vec2 oneStepPositiveTextureCoordinate;\n" + - "varying vec2 oneStepNegativeTextureCoordinate;\n" + - "varying vec2 twoStepsPositiveTextureCoordinate;\n" + - "varying vec2 twoStepsNegativeTextureCoordinate;\n" + - "varying vec2 threeStepsPositiveTextureCoordinate;\n" + - "varying vec2 threeStepsNegativeTextureCoordinate;\n" + - "varying vec2 fourStepsPositiveTextureCoordinate;\n" + - "varying vec2 fourStepsNegativeTextureCoordinate;\n" + - "\n" + - "void main()\n" + - "{\n" + - "gl_Position = position;\n" + - "\n" + - "vec2 offset = vec2(texelWidthOffset, texelHeightOffset);\n" + - "\n" + - "centerTextureCoordinate = inputTextureCoordinate;\n" + - "oneStepNegativeTextureCoordinate = inputTextureCoordinate - offset;\n" + - "oneStepPositiveTextureCoordinate = inputTextureCoordinate + offset;\n" + - "twoStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 2.0);\n" + - "twoStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 2.0);\n" + - "threeStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 3.0);\n" + - "threeStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 3.0);\n" + - "fourStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 4.0);\n" + - "fourStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 4.0);\n" + - "}\n"; - - - public static final String FRAGMENT_SHADER_1 = - "precision highp float;\n" + - "\n" + - "varying vec2 centerTextureCoordinate;\n" + - "varying vec2 oneStepPositiveTextureCoordinate;\n" + - "varying vec2 oneStepNegativeTextureCoordinate;\n" + - "\n" + - "uniform sampler2D inputImageTexture;\n" + - "\n" + - "void main()\n" + - "{\n" + - "lowp vec4 centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate);\n" + - "lowp vec4 oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate);\n" + - "lowp vec4 oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate);\n" + - "\n" + - "lowp vec4 maxValue = max(centerIntensity, oneStepPositiveIntensity);\n" + - "\n" + - "gl_FragColor = max(maxValue, oneStepNegativeIntensity);\n" + - "}\n"; - - public static final String FRAGMENT_SHADER_2 = - "precision highp float;\n" + - "\n" + - "varying vec2 centerTextureCoordinate;\n" + - "varying vec2 oneStepPositiveTextureCoordinate;\n" + - "varying vec2 oneStepNegativeTextureCoordinate;\n" + - "varying vec2 twoStepsPositiveTextureCoordinate;\n" + - "varying vec2 twoStepsNegativeTextureCoordinate;\n" + - "\n" + - "uniform sampler2D inputImageTexture;\n" + - "\n" + - "void main()\n" + - "{\n" + - "lowp vec4 centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate);\n" + - "lowp vec4 oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate);\n" + - "lowp vec4 oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate);\n" + - "lowp vec4 twoStepsPositiveIntensity = texture2D(inputImageTexture, twoStepsPositiveTextureCoordinate);\n" + - "lowp vec4 twoStepsNegativeIntensity = texture2D(inputImageTexture, twoStepsNegativeTextureCoordinate);\n" + - "\n" + - "lowp vec4 maxValue = max(centerIntensity, oneStepPositiveIntensity);\n" + - "maxValue = max(maxValue, oneStepNegativeIntensity);\n" + - "maxValue = max(maxValue, twoStepsPositiveIntensity);\n" + - "maxValue = max(maxValue, twoStepsNegativeIntensity);\n" + - "\n" + - "gl_FragColor = max(maxValue, twoStepsNegativeIntensity);\n" + - "}\n"; - - public static final String FRAGMENT_SHADER_3 = - "precision highp float;\n" + - "\n" + - "varying vec2 centerTextureCoordinate;\n" + - "varying vec2 oneStepPositiveTextureCoordinate;\n" + - "varying vec2 oneStepNegativeTextureCoordinate;\n" + - "varying vec2 twoStepsPositiveTextureCoordinate;\n" + - "varying vec2 twoStepsNegativeTextureCoordinate;\n" + - "varying vec2 threeStepsPositiveTextureCoordinate;\n" + - "varying vec2 threeStepsNegativeTextureCoordinate;\n" + - "\n" + - "uniform sampler2D inputImageTexture;\n" + - "\n" + - "void main()\n" + - "{\n" + - "lowp vec4 centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate);\n" + - "lowp vec4 oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate);\n" + - "lowp vec4 oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate);\n" + - "lowp vec4 twoStepsPositiveIntensity = texture2D(inputImageTexture, twoStepsPositiveTextureCoordinate);\n" + - "lowp vec4 twoStepsNegativeIntensity = texture2D(inputImageTexture, twoStepsNegativeTextureCoordinate);\n" + - "lowp vec4 threeStepsPositiveIntensity = texture2D(inputImageTexture, threeStepsPositiveTextureCoordinate);\n" + - "lowp vec4 threeStepsNegativeIntensity = texture2D(inputImageTexture, threeStepsNegativeTextureCoordinate);\n" + - "\n" + - "lowp vec4 maxValue = max(centerIntensity, oneStepPositiveIntensity);\n" + - "maxValue = max(maxValue, oneStepNegativeIntensity);\n" + - "maxValue = max(maxValue, twoStepsPositiveIntensity);\n" + - "maxValue = max(maxValue, twoStepsNegativeIntensity);\n" + - "maxValue = max(maxValue, threeStepsPositiveIntensity);\n" + - "\n" + - "gl_FragColor = max(maxValue, threeStepsNegativeIntensity);\n" + - "}\n"; - - public static final String FRAGMENT_SHADER_4 = - "precision highp float;\n" + - "\n" + - "varying vec2 centerTextureCoordinate;\n" + - "varying vec2 oneStepPositiveTextureCoordinate;\n" + - "varying vec2 oneStepNegativeTextureCoordinate;\n" + - "varying vec2 twoStepsPositiveTextureCoordinate;\n" + - "varying vec2 twoStepsNegativeTextureCoordinate;\n" + - "varying vec2 threeStepsPositiveTextureCoordinate;\n" + - "varying vec2 threeStepsNegativeTextureCoordinate;\n" + - "varying vec2 fourStepsPositiveTextureCoordinate;\n" + - "varying vec2 fourStepsNegativeTextureCoordinate;\n" + - "\n" + - "uniform sampler2D inputImageTexture;\n" + - "\n" + - "void main()\n" + - "{\n" + - "lowp vec4 centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate);\n" + - "lowp vec4 oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate);\n" + - "lowp vec4 oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate);\n" + - "lowp vec4 twoStepsPositiveIntensity = texture2D(inputImageTexture, twoStepsPositiveTextureCoordinate);\n" + - "lowp vec4 twoStepsNegativeIntensity = texture2D(inputImageTexture, twoStepsNegativeTextureCoordinate);\n" + - "lowp vec4 threeStepsPositiveIntensity = texture2D(inputImageTexture, threeStepsPositiveTextureCoordinate);\n" + - "lowp vec4 threeStepsNegativeIntensity = texture2D(inputImageTexture, threeStepsNegativeTextureCoordinate);\n" + - "lowp vec4 fourStepsPositiveIntensity = texture2D(inputImageTexture, fourStepsPositiveTextureCoordinate);\n" + - "lowp vec4 fourStepsNegativeIntensity = texture2D(inputImageTexture, fourStepsNegativeTextureCoordinate);\n" + - "\n" + - "lowp vec4 maxValue = max(centerIntensity, oneStepPositiveIntensity);\n" + - "maxValue = max(maxValue, oneStepNegativeIntensity);\n" + - "maxValue = max(maxValue, twoStepsPositiveIntensity);\n" + - "maxValue = max(maxValue, twoStepsNegativeIntensity);\n" + - "maxValue = max(maxValue, threeStepsPositiveIntensity);\n" + - "maxValue = max(maxValue, threeStepsNegativeIntensity);\n" + - "maxValue = max(maxValue, fourStepsPositiveIntensity);\n" + - "\n" + - "gl_FragColor = max(maxValue, fourStepsNegativeIntensity);\n" + - "}\n"; - - - public GPUImageRGBDilationFilter() { - this(1); - } - - /** - * Acceptable values for dilationRadius, which sets the distance in pixels to sample out - * from the center, are 1, 2, 3, and 4. - * - * @param radius 1, 2, 3 or 4 - */ - public GPUImageRGBDilationFilter(int radius) { - this(getVertexShader(radius), getFragmentShader(radius)); - } - - private GPUImageRGBDilationFilter(String vertexShader, String fragmentShader) { - super(vertexShader, fragmentShader, vertexShader, fragmentShader); - } - - private static String getVertexShader(int radius) { - switch (radius) { - case 0: - case 1: - return VERTEX_SHADER_1; - case 2: - return VERTEX_SHADER_2; - case 3: - return VERTEX_SHADER_3; - default: - return VERTEX_SHADER_4; - } - } - - private static String getFragmentShader(int radius) { - switch (radius) { - case 0: - case 1: - return FRAGMENT_SHADER_1; - case 2: - return FRAGMENT_SHADER_2; - case 3: - return FRAGMENT_SHADER_3; - default: - return FRAGMENT_SHADER_4; - } - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageRGBFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageRGBFilter.java deleted file mode 100755 index f0af18c..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageRGBFilter.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; - -/** - * Adjusts the individual RGB channels of an image - * red: Normalized values by which each color channel is multiplied. The range is from 0.0 up, with 1.0 as the default. - * green: - * blue: - */ -public class GPUImageRGBFilter extends GPUImageFilter { - public static final String RGB_FRAGMENT_SHADER = "" + - " varying highp vec2 textureCoordinate;\n" + - " \n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform highp float red;\n" + - " uniform highp float green;\n" + - " uniform highp float blue;\n" + - " \n" + - " void main()\n" + - " {\n" + - " highp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + - " \n" + - " gl_FragColor = vec4(textureColor.r * red, textureColor.g * green, textureColor.b * blue, 1.0);\n" + - " }\n"; - - private int mRedLocation; - private float mRed; - private int mGreenLocation; - private float mGreen; - private int mBlueLocation; - private float mBlue; - private boolean mIsInitialized = false; - - public GPUImageRGBFilter() { - this(1.0f, 1.0f, 1.0f); - } - - public GPUImageRGBFilter(final float red, final float green, final float blue) { - super(NO_FILTER_VERTEX_SHADER, RGB_FRAGMENT_SHADER); - mRed = red; - mGreen = green; - mBlue = blue; - } - - @Override - public void onInit() { - super.onInit(); - mRedLocation = GLES20.glGetUniformLocation(getProgram(), "red"); - mGreenLocation = GLES20.glGetUniformLocation(getProgram(), "green"); - mBlueLocation = GLES20.glGetUniformLocation(getProgram(), "blue"); - mIsInitialized = true; - setRed(mRed); - setGreen(mGreen); - setBlue(mBlue); - } - - public void setRed(final float red) { - mRed = red; - if (mIsInitialized) { - setFloat(mRedLocation, mRed); - } - } - - public void setGreen(final float green) { - mGreen = green; - if (mIsInitialized) { - setFloat(mGreenLocation, mGreen); - } - } - - public void setBlue(final float blue) { - mBlue = blue; - if (mIsInitialized) { - setFloat(mBlueLocation, mBlue); - } - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageRenderer.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageRenderer.java deleted file mode 100755 index 9565b71..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageRenderer.java +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.annotation.TargetApi; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.SurfaceTexture; -import android.hardware.Camera; -import android.hardware.Camera.PreviewCallback; -import android.hardware.Camera.Size; -import android.opengl.GLES20; -import android.opengl.GLSurfaceView.Renderer; - -import jp.co.cyberagent.android.gpuimage.util.TextureRotationUtil; - -import javax.microedition.khronos.egl.EGLConfig; -import javax.microedition.khronos.opengles.GL10; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.FloatBuffer; -import java.nio.IntBuffer; -import java.util.LinkedList; -import java.util.Queue; - -import static jp.co.cyberagent.android.gpuimage.util.TextureRotationUtil.TEXTURE_NO_ROTATION; - -@TargetApi(11) -public class GPUImageRenderer implements Renderer, PreviewCallback { - public static final int NO_IMAGE = -1; - static final float CUBE[] = { - -1.0f, -1.0f, - 1.0f, -1.0f, - -1.0f, 1.0f, - 1.0f, 1.0f, - }; - - private GPUImageFilter mFilter; - - public final Object mSurfaceChangedWaiter = new Object(); - - private int mGLTextureId = NO_IMAGE; - private SurfaceTexture mSurfaceTexture = null; - private final FloatBuffer mGLCubeBuffer; - private final FloatBuffer mGLTextureBuffer; - private IntBuffer mGLRgbBuffer; - - private int mOutputWidth; - private int mOutputHeight; - private int mImageWidth; - private int mImageHeight; - private int mAddedPadding; - - private final Queue mRunOnDraw; - private final Queue mRunOnDrawEnd; - private Rotation mRotation; - private boolean mFlipHorizontal; - private boolean mFlipVertical; - private GPUImage.ScaleType mScaleType = GPUImage.ScaleType.CENTER_CROP; - - public GPUImageRenderer(final GPUImageFilter filter) { - mFilter = filter; - mRunOnDraw = new LinkedList(); - mRunOnDrawEnd = new LinkedList(); - - mGLCubeBuffer = ByteBuffer.allocateDirect(CUBE.length * 4) - .order(ByteOrder.nativeOrder()) - .asFloatBuffer(); - mGLCubeBuffer.put(CUBE).position(0); - - mGLTextureBuffer = ByteBuffer.allocateDirect(TEXTURE_NO_ROTATION.length * 4) - .order(ByteOrder.nativeOrder()) - .asFloatBuffer(); - setRotation(Rotation.NORMAL, false, false); - } - - @Override - public void onSurfaceCreated(final GL10 unused, final EGLConfig config) { - GLES20.glClearColor(0, 0, 0, 1); - GLES20.glDisable(GLES20.GL_DEPTH_TEST); - mFilter.init(); - } - - @Override - public void onSurfaceChanged(final GL10 gl, final int width, final int height) { - mOutputWidth = width; - mOutputHeight = height; - GLES20.glViewport(0, 0, width, height); - GLES20.glUseProgram(mFilter.getProgram()); - mFilter.onOutputSizeChanged(width, height); - adjustImageScaling(); - synchronized (mSurfaceChangedWaiter) { - mSurfaceChangedWaiter.notifyAll(); - } - } - - @Override - public void onDrawFrame(final GL10 gl) { - GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); - runAll(mRunOnDraw); - mFilter.onDraw(mGLTextureId, mGLCubeBuffer, mGLTextureBuffer); - runAll(mRunOnDrawEnd); - if (mSurfaceTexture != null) { - mSurfaceTexture.updateTexImage(); - } - } - - private void runAll(Queue queue) { - synchronized (queue) { - while (!queue.isEmpty()) { - queue.poll().run(); - } - } - } - - @Override - public void onPreviewFrame(final byte[] data, final Camera camera) { - final Size previewSize = camera.getParameters().getPreviewSize(); - if (mGLRgbBuffer == null) { - mGLRgbBuffer = IntBuffer.allocate(previewSize.width * previewSize.height); - } - if (mRunOnDraw.isEmpty()) { - runOnDraw(new Runnable() { - @Override - public void run() { - GPUImageNativeLibrary.YUVtoRBGA(data, previewSize.width, previewSize.height, - mGLRgbBuffer.array()); - mGLTextureId = OpenGlUtils.loadTexture(mGLRgbBuffer, previewSize, mGLTextureId); - camera.addCallbackBuffer(data); - - if (mImageWidth != previewSize.width) { - mImageWidth = previewSize.width; - mImageHeight = previewSize.height; - adjustImageScaling(); - } - } - }); - } - } - - public void setUpSurfaceTexture(final Camera camera) { - runOnDraw(new Runnable() { - @Override - public void run() { - int[] textures = new int[1]; - GLES20.glGenTextures(1, textures, 0); - mSurfaceTexture = new SurfaceTexture(textures[0]); - try { - camera.setPreviewTexture(mSurfaceTexture); - camera.setPreviewCallback(GPUImageRenderer.this); - camera.startPreview(); - } catch (IOException e) { - e.printStackTrace(); - } - } - }); - } - - public void setFilter(final GPUImageFilter filter) { - runOnDraw(new Runnable() { - - @Override - public void run() { - final GPUImageFilter oldFilter = mFilter; - mFilter = filter; - if (oldFilter != null) { - oldFilter.destroy(); - } - mFilter.init(); - GLES20.glUseProgram(mFilter.getProgram()); - mFilter.onOutputSizeChanged(mOutputWidth, mOutputHeight); - } - }); - } - - public void deleteImage() { - runOnDraw(new Runnable() { - - @Override - public void run() { - GLES20.glDeleteTextures(1, new int[]{ - mGLTextureId - }, 0); - mGLTextureId = NO_IMAGE; - } - }); - } - - public void setImageBitmap(final Bitmap bitmap) { - setImageBitmap(bitmap, true); - } - - public void setImageBitmap(final Bitmap bitmap, final boolean recycle) { - if (bitmap == null) { - return; - } - - runOnDraw(new Runnable() { - - @Override - public void run() { - Bitmap resizedBitmap = null; - if (bitmap.getWidth() % 2 == 1) { - resizedBitmap = Bitmap.createBitmap(bitmap.getWidth() + 1, bitmap.getHeight(), - Bitmap.Config.ARGB_8888); - Canvas can = new Canvas(resizedBitmap); - can.drawARGB(0x00, 0x00, 0x00, 0x00); - can.drawBitmap(bitmap, 0, 0, null); - mAddedPadding = 1; - } else { - mAddedPadding = 0; - } - - mGLTextureId = OpenGlUtils.loadTexture( - resizedBitmap != null ? resizedBitmap : bitmap, mGLTextureId, recycle); - if (resizedBitmap != null) { - resizedBitmap.recycle(); - } - mImageWidth = bitmap.getWidth(); - mImageHeight = bitmap.getHeight(); - adjustImageScaling(); - } - }); - } - - public void setScaleType(GPUImage.ScaleType scaleType) { - mScaleType = scaleType; - } - - protected int getFrameWidth() { - return mOutputWidth; - } - - protected int getFrameHeight() { - return mOutputHeight; - } - - private void adjustImageScaling() { - float outputWidth = mOutputWidth; - float outputHeight = mOutputHeight; - if (mRotation == Rotation.ROTATION_270 || mRotation == Rotation.ROTATION_90) { - outputWidth = mOutputHeight; - outputHeight = mOutputWidth; - } - - float ratio1 = outputWidth / mImageWidth; - float ratio2 = outputHeight / mImageHeight; - float ratioMax = Math.max(ratio1, ratio2); - int imageWidthNew = Math.round(mImageWidth * ratioMax); - int imageHeightNew = Math.round(mImageHeight * ratioMax); - - float ratioWidth = imageWidthNew / outputWidth; - float ratioHeight = imageHeightNew / outputHeight; - - float[] cube = CUBE; - float[] textureCords = TextureRotationUtil.getRotation(mRotation, mFlipHorizontal, mFlipVertical); - if (mScaleType == GPUImage.ScaleType.CENTER_CROP) { - float distHorizontal = (1 - 1 / ratioWidth) / 2; - float distVertical = (1 - 1 / ratioHeight) / 2; - textureCords = new float[]{ - addDistance(textureCords[0], distHorizontal), addDistance(textureCords[1], distVertical), - addDistance(textureCords[2], distHorizontal), addDistance(textureCords[3], distVertical), - addDistance(textureCords[4], distHorizontal), addDistance(textureCords[5], distVertical), - addDistance(textureCords[6], distHorizontal), addDistance(textureCords[7], distVertical), - }; - } else { - cube = new float[]{ - CUBE[0] / ratioHeight, CUBE[1] / ratioWidth, - CUBE[2] / ratioHeight, CUBE[3] / ratioWidth, - CUBE[4] / ratioHeight, CUBE[5] / ratioWidth, - CUBE[6] / ratioHeight, CUBE[7] / ratioWidth, - }; - } - - mGLCubeBuffer.clear(); - mGLCubeBuffer.put(cube).position(0); - mGLTextureBuffer.clear(); - mGLTextureBuffer.put(textureCords).position(0); - } - - private float addDistance(float coordinate, float distance) { - return coordinate == 0.0f ? distance : 1 - distance; - } - - public void setRotationCamera(final Rotation rotation, final boolean flipHorizontal, - final boolean flipVertical) { - setRotation(rotation, flipVertical, flipHorizontal); - } - - public void setRotation(final Rotation rotation) { - mRotation = rotation; - adjustImageScaling(); - } - - public void setRotation(final Rotation rotation, - final boolean flipHorizontal, final boolean flipVertical) { - mFlipHorizontal = flipHorizontal; - mFlipVertical = flipVertical; - setRotation(rotation); - } - - public Rotation getRotation() { - return mRotation; - } - - public boolean isFlippedHorizontally() { - return mFlipHorizontal; - } - - public boolean isFlippedVertically() { - return mFlipVertical; - } - - protected void runOnDraw(final Runnable runnable) { - synchronized (mRunOnDraw) { - mRunOnDraw.add(runnable); - } - } - - protected void runOnDrawEnd(final Runnable runnable) { - synchronized (mRunOnDrawEnd) { - mRunOnDrawEnd.add(runnable); - } - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSaturationBlendFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSaturationBlendFilter.java deleted file mode 100755 index 1c0f90d..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSaturationBlendFilter.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -public class GPUImageSaturationBlendFilter extends GPUImageTwoInputFilter { - public static final String SATURATION_BLEND_FRAGMENT_SHADER = "varying highp vec2 textureCoordinate;\n" + - " varying highp vec2 textureCoordinate2;\n" + - " \n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform sampler2D inputImageTexture2;\n" + - " \n" + - " highp float lum(lowp vec3 c) {\n" + - " return dot(c, vec3(0.3, 0.59, 0.11));\n" + - " }\n" + - " \n" + - " lowp vec3 clipcolor(lowp vec3 c) {\n" + - " highp float l = lum(c);\n" + - " lowp float n = min(min(c.r, c.g), c.b);\n" + - " lowp float x = max(max(c.r, c.g), c.b);\n" + - " \n" + - " if (n < 0.0) {\n" + - " c.r = l + ((c.r - l) * l) / (l - n);\n" + - " c.g = l + ((c.g - l) * l) / (l - n);\n" + - " c.b = l + ((c.b - l) * l) / (l - n);\n" + - " }\n" + - " if (x > 1.0) {\n" + - " c.r = l + ((c.r - l) * (1.0 - l)) / (x - l);\n" + - " c.g = l + ((c.g - l) * (1.0 - l)) / (x - l);\n" + - " c.b = l + ((c.b - l) * (1.0 - l)) / (x - l);\n" + - " }\n" + - " \n" + - " return c;\n" + - " }\n" + - " \n" + - " lowp vec3 setlum(lowp vec3 c, highp float l) {\n" + - " highp float d = l - lum(c);\n" + - " c = c + vec3(d);\n" + - " return clipcolor(c);\n" + - " }\n" + - " \n" + - " highp float sat(lowp vec3 c) {\n" + - " lowp float n = min(min(c.r, c.g), c.b);\n" + - " lowp float x = max(max(c.r, c.g), c.b);\n" + - " return x - n;\n" + - " }\n" + - " \n" + - " lowp float mid(lowp float cmin, lowp float cmid, lowp float cmax, highp float s) {\n" + - " return ((cmid - cmin) * s) / (cmax - cmin);\n" + - " }\n" + - " \n" + - " lowp vec3 setsat(lowp vec3 c, highp float s) {\n" + - " if (c.r > c.g) {\n" + - " if (c.r > c.b) {\n" + - " if (c.g > c.b) {\n" + - " /* g is mid, b is min */\n" + - " c.g = mid(c.b, c.g, c.r, s);\n" + - " c.b = 0.0;\n" + - " } else {\n" + - " /* b is mid, g is min */\n" + - " c.b = mid(c.g, c.b, c.r, s);\n" + - " c.g = 0.0;\n" + - " }\n" + - " c.r = s;\n" + - " } else {\n" + - " /* b is max, r is mid, g is min */\n" + - " c.r = mid(c.g, c.r, c.b, s);\n" + - " c.b = s;\n" + - " c.r = 0.0;\n" + - " }\n" + - " } else if (c.r > c.b) {\n" + - " /* g is max, r is mid, b is min */\n" + - " c.r = mid(c.b, c.r, c.g, s);\n" + - " c.g = s;\n" + - " c.b = 0.0;\n" + - " } else if (c.g > c.b) {\n" + - " /* g is max, b is mid, r is min */\n" + - " c.b = mid(c.r, c.b, c.g, s);\n" + - " c.g = s;\n" + - " c.r = 0.0;\n" + - " } else if (c.b > c.g) {\n" + - " /* b is max, g is mid, r is min */\n" + - " c.g = mid(c.r, c.g, c.b, s);\n" + - " c.b = s;\n" + - " c.r = 0.0;\n" + - " } else {\n" + - " c = vec3(0.0);\n" + - " }\n" + - " return c;\n" + - " }\n" + - " \n" + - " void main()\n" + - " {\n" + - " highp vec4 baseColor = texture2D(inputImageTexture, textureCoordinate);\n" + - " highp vec4 overlayColor = texture2D(inputImageTexture2, textureCoordinate2);\n" + - " \n" + - " gl_FragColor = vec4(baseColor.rgb * (1.0 - overlayColor.a) + setlum(setsat(baseColor.rgb, sat(overlayColor.rgb)), lum(baseColor.rgb)) * overlayColor.a, baseColor.a);\n" + - " }"; - - public GPUImageSaturationBlendFilter() { - super(SATURATION_BLEND_FRAGMENT_SHADER); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSaturationFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSaturationFilter.java deleted file mode 100755 index 0725953..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSaturationFilter.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; - -/** - * saturation: The degree of saturation or desaturation to apply to the image (0.0 - 2.0, with 1.0 as the default) - */ -public class GPUImageSaturationFilter extends GPUImageFilter { - public static final String SATURATION_FRAGMENT_SHADER = "" + - " varying highp vec2 textureCoordinate;\n" + - " \n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform lowp float saturation;\n" + - " \n" + - " // Values from \"Graphics Shaders: Theory and Practice\" by Bailey and Cunningham\n" + - " const mediump vec3 luminanceWeighting = vec3(0.2125, 0.7154, 0.0721);\n" + - " \n" + - " void main()\n" + - " {\n" + - " lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + - " lowp float luminance = dot(textureColor.rgb, luminanceWeighting);\n" + - " lowp vec3 greyScaleColor = vec3(luminance);\n" + - " \n" + - " gl_FragColor = vec4(mix(greyScaleColor, textureColor.rgb, saturation), textureColor.w);\n" + - " \n" + - " }"; - - private int mSaturationLocation; - private float mSaturation; - - public GPUImageSaturationFilter() { - this(1.0f); - } - - public GPUImageSaturationFilter(final float saturation) { - super(NO_FILTER_VERTEX_SHADER, SATURATION_FRAGMENT_SHADER); - mSaturation = saturation; - } - - @Override - public void onInit() { - super.onInit(); - mSaturationLocation = GLES20.glGetUniformLocation(getProgram(), "saturation"); - } - - @Override - public void onInitialized() { - super.onInitialized(); - setSaturation(mSaturation); - } - - public void setSaturation(final float saturation) { - mSaturation = saturation; - setFloat(mSaturationLocation, mSaturation); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageScreenBlendFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageScreenBlendFilter.java deleted file mode 100755 index 2c63a69..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageScreenBlendFilter.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -public class GPUImageScreenBlendFilter extends GPUImageTwoInputFilter { - public static final String SCREEN_BLEND_FRAGMENT_SHADER = "varying highp vec2 textureCoordinate;\n" + - " varying highp vec2 textureCoordinate2;\n" + - "\n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform sampler2D inputImageTexture2;\n" + - " \n" + - " void main()\n" + - " {\n" + - " mediump vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + - " mediump vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);\n" + - " mediump vec4 whiteColor = vec4(1.0);\n" + - " gl_FragColor = whiteColor - ((whiteColor - textureColor2) * (whiteColor - textureColor));\n" + - " }"; - - public GPUImageScreenBlendFilter() { - super(SCREEN_BLEND_FRAGMENT_SHADER); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSepiaFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSepiaFilter.java deleted file mode 100755 index cbcf353..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSepiaFilter.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -/** - * Applies a simple sepia effect. - */ -public class GPUImageSepiaFilter extends GPUImageColorMatrixFilter { - - public GPUImageSepiaFilter() { - this(1.0f); - } - - public GPUImageSepiaFilter(final float intensity) { - super(intensity, new float[] { - 0.3588f, 0.7044f, 0.1368f, 0.0f, - 0.2990f, 0.5870f, 0.1140f, 0.0f, - 0.2392f, 0.4696f, 0.0912f, 0.0f, - 0f, 0f, 0f, 1.0f - }); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSharpenFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSharpenFilter.java deleted file mode 100755 index 4317b66..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSharpenFilter.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; - -/** - * Sharpens the picture.
    - *
    - * sharpness: from -4.0 to 4.0, with 0.0 as the normal level - */ -public class GPUImageSharpenFilter extends GPUImageFilter { - public static final String SHARPEN_VERTEX_SHADER = "" + - "attribute vec4 position;\n" + - "attribute vec4 inputTextureCoordinate;\n" + - "\n" + - "uniform float imageWidthFactor; \n" + - "uniform float imageHeightFactor; \n" + - "uniform float sharpness;\n" + - "\n" + - "varying vec2 textureCoordinate;\n" + - "varying vec2 leftTextureCoordinate;\n" + - "varying vec2 rightTextureCoordinate; \n" + - "varying vec2 topTextureCoordinate;\n" + - "varying vec2 bottomTextureCoordinate;\n" + - "\n" + - "varying float centerMultiplier;\n" + - "varying float edgeMultiplier;\n" + - "\n" + - "void main()\n" + - "{\n" + - " gl_Position = position;\n" + - " \n" + - " mediump vec2 widthStep = vec2(imageWidthFactor, 0.0);\n" + - " mediump vec2 heightStep = vec2(0.0, imageHeightFactor);\n" + - " \n" + - " textureCoordinate = inputTextureCoordinate.xy;\n" + - " leftTextureCoordinate = inputTextureCoordinate.xy - widthStep;\n" + - " rightTextureCoordinate = inputTextureCoordinate.xy + widthStep;\n" + - " topTextureCoordinate = inputTextureCoordinate.xy + heightStep; \n" + - " bottomTextureCoordinate = inputTextureCoordinate.xy - heightStep;\n" + - " \n" + - " centerMultiplier = 1.0 + 4.0 * sharpness;\n" + - " edgeMultiplier = sharpness;\n" + - "}"; - - public static final String SHARPEN_FRAGMENT_SHADER = "" + - "precision highp float;\n" + - "\n" + - "varying highp vec2 textureCoordinate;\n" + - "varying highp vec2 leftTextureCoordinate;\n" + - "varying highp vec2 rightTextureCoordinate; \n" + - "varying highp vec2 topTextureCoordinate;\n" + - "varying highp vec2 bottomTextureCoordinate;\n" + - "\n" + - "varying highp float centerMultiplier;\n" + - "varying highp float edgeMultiplier;\n" + - "\n" + - "uniform sampler2D inputImageTexture;\n" + - "\n" + - "void main()\n" + - "{\n" + - " mediump vec3 textureColor = texture2D(inputImageTexture, textureCoordinate).rgb;\n" + - " mediump vec3 leftTextureColor = texture2D(inputImageTexture, leftTextureCoordinate).rgb;\n" + - " mediump vec3 rightTextureColor = texture2D(inputImageTexture, rightTextureCoordinate).rgb;\n" + - " mediump vec3 topTextureColor = texture2D(inputImageTexture, topTextureCoordinate).rgb;\n" + - " mediump vec3 bottomTextureColor = texture2D(inputImageTexture, bottomTextureCoordinate).rgb;\n" + - "\n" + - " gl_FragColor = vec4((textureColor * centerMultiplier - (leftTextureColor * edgeMultiplier + rightTextureColor * edgeMultiplier + topTextureColor * edgeMultiplier + bottomTextureColor * edgeMultiplier)), texture2D(inputImageTexture, bottomTextureCoordinate).w);\n" + - "}"; - - private int mSharpnessLocation; - private float mSharpness; - private int mImageWidthFactorLocation; - private int mImageHeightFactorLocation; - - public GPUImageSharpenFilter() { - this(0.0f); - } - - public GPUImageSharpenFilter(final float sharpness) { - super(SHARPEN_VERTEX_SHADER, SHARPEN_FRAGMENT_SHADER); - mSharpness = sharpness; - } - - @Override - public void onInit() { - super.onInit(); - mSharpnessLocation = GLES20.glGetUniformLocation(getProgram(), "sharpness"); - mImageWidthFactorLocation = GLES20.glGetUniformLocation(getProgram(), "imageWidthFactor"); - mImageHeightFactorLocation = GLES20.glGetUniformLocation(getProgram(), "imageHeightFactor"); - setSharpness(mSharpness); - } - - @Override - public void onOutputSizeChanged(final int width, final int height) { - super.onOutputSizeChanged(width, height); - setFloat(mImageWidthFactorLocation, 1.0f / width); - setFloat(mImageHeightFactorLocation, 1.0f / height); - } - - public void setSharpness(final float sharpness) { - mSharpness = sharpness; - setFloat(mSharpnessLocation, mSharpness); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSketchFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSketchFilter.java deleted file mode 100755 index dd78e70..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSketchFilter.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import java.util.ArrayList; -import java.util.List; - -/** - * Converts video to look like a sketch. - * This is just the Sobel edge detection filter with the colors inverted. - */ -public class GPUImageSketchFilter extends GPUImageFilterGroup { - public static final String SKETCH_FRAGMENT_SHADER = "" + - "precision mediump float;\n" + - "\n" + - "varying vec2 textureCoordinate;\n" + - "varying vec2 leftTextureCoordinate;\n" + - "varying vec2 rightTextureCoordinate;\n" + - "\n" + - "varying vec2 topTextureCoordinate;\n" + - "varying vec2 topLeftTextureCoordinate;\n" + - "varying vec2 topRightTextureCoordinate;\n" + - "\n" + - "varying vec2 bottomTextureCoordinate;\n" + - "varying vec2 bottomLeftTextureCoordinate;\n" + - "varying vec2 bottomRightTextureCoordinate;\n" + - "\n" + - "uniform sampler2D inputImageTexture;\n" + - "\n" + - "void main()\n" + - "{\n" + - "float bottomLeftIntensity = texture2D(inputImageTexture, bottomLeftTextureCoordinate).r;\n" + - "float topRightIntensity = texture2D(inputImageTexture, topRightTextureCoordinate).r;\n" + - "float topLeftIntensity = texture2D(inputImageTexture, topLeftTextureCoordinate).r;\n" + - "float bottomRightIntensity = texture2D(inputImageTexture, bottomRightTextureCoordinate).r;\n" + - "float leftIntensity = texture2D(inputImageTexture, leftTextureCoordinate).r;\n" + - "float rightIntensity = texture2D(inputImageTexture, rightTextureCoordinate).r;\n" + - "float bottomIntensity = texture2D(inputImageTexture, bottomTextureCoordinate).r;\n" + - "float topIntensity = texture2D(inputImageTexture, topTextureCoordinate).r;\n" + - "float h = -topLeftIntensity - 2.0 * topIntensity - topRightIntensity + bottomLeftIntensity + 2.0 * bottomIntensity + bottomRightIntensity;\n" + - "float v = -bottomLeftIntensity - 2.0 * leftIntensity - topLeftIntensity + bottomRightIntensity + 2.0 * rightIntensity + topRightIntensity;\n" + - "\n" + - "float mag = 1.0 - length(vec2(h, v));\n" + - "\n" + - "gl_FragColor = vec4(vec3(mag), 1.0);\n" + - "}\n"; - - public GPUImageSketchFilter() { - super(); - addFilter(new GPUImageGrayscaleFilter()); - addFilter(new GPUImage3x3TextureSamplingFilter(SKETCH_FRAGMENT_SHADER)); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSmoothToonFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSmoothToonFilter.java deleted file mode 100755 index a569ce9..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSmoothToonFilter.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; - -/** - * This uses a similar process as the GPUImageToonFilter, only it precedes the toon effect - * with a Gaussian blur to smooth out noise. - */ -public class GPUImageSmoothToonFilter extends GPUImageFilterGroup { - GPUImageGaussianBlurFilter blurFilter; - GPUImageToonFilter toonFilter; - - /** - * Setup and Tear down - */ - public GPUImageSmoothToonFilter() { - // First pass: apply a variable Gaussian blur - blurFilter = new GPUImageGaussianBlurFilter(); - addFilter(blurFilter); - - // Second pass: run the Sobel edge detection on this blurred image, along with a posterization effect - toonFilter = new GPUImageToonFilter(); - addFilter(toonFilter); - - getFilters().add(blurFilter); - - setBlurSize(0.5f); - setThreshold(0.2f); - setQuantizationLevels(10.0f); - } - - /** - * Accessors - */ - public void setTexelWidth(float value) { - toonFilter.setTexelWidth(value); - } - - public void setTexelHeight(float value) { - toonFilter.setTexelHeight(value); - } - - public void setBlurSize(float value) { - blurFilter.setBlurSize(value); - } - - public void setThreshold(float value) { - toonFilter.setThreshold(value); - } - - public void setQuantizationLevels(float value) { - toonFilter.setQuantizationLevels(value); - } - -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSobelEdgeDetection.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSobelEdgeDetection.java deleted file mode 100755 index 2a775d4..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSobelEdgeDetection.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import java.util.ArrayList; -import java.util.List; - -/** - * Applies sobel edge detection on the image. - */ -public class GPUImageSobelEdgeDetection extends GPUImageFilterGroup { - public static final String SOBEL_EDGE_DETECTION = "" + - "precision mediump float;\n" + - "\n" + - "varying vec2 textureCoordinate;\n" + - "varying vec2 leftTextureCoordinate;\n" + - "varying vec2 rightTextureCoordinate;\n" + - "\n" + - "varying vec2 topTextureCoordinate;\n" + - "varying vec2 topLeftTextureCoordinate;\n" + - "varying vec2 topRightTextureCoordinate;\n" + - "\n" + - "varying vec2 bottomTextureCoordinate;\n" + - "varying vec2 bottomLeftTextureCoordinate;\n" + - "varying vec2 bottomRightTextureCoordinate;\n" + - "\n" + - "uniform sampler2D inputImageTexture;\n" + - "\n" + - "void main()\n" + - "{\n" + - " float bottomLeftIntensity = texture2D(inputImageTexture, bottomLeftTextureCoordinate).r;\n" + - " float topRightIntensity = texture2D(inputImageTexture, topRightTextureCoordinate).r;\n" + - " float topLeftIntensity = texture2D(inputImageTexture, topLeftTextureCoordinate).r;\n" + - " float bottomRightIntensity = texture2D(inputImageTexture, bottomRightTextureCoordinate).r;\n" + - " float leftIntensity = texture2D(inputImageTexture, leftTextureCoordinate).r;\n" + - " float rightIntensity = texture2D(inputImageTexture, rightTextureCoordinate).r;\n" + - " float bottomIntensity = texture2D(inputImageTexture, bottomTextureCoordinate).r;\n" + - " float topIntensity = texture2D(inputImageTexture, topTextureCoordinate).r;\n" + - " float h = -topLeftIntensity - 2.0 * topIntensity - topRightIntensity + bottomLeftIntensity + 2.0 * bottomIntensity + bottomRightIntensity;\n" + - " float v = -bottomLeftIntensity - 2.0 * leftIntensity - topLeftIntensity + bottomRightIntensity + 2.0 * rightIntensity + topRightIntensity;\n" + - "\n" + - " float mag = length(vec2(h, v));\n" + - "\n" + - " gl_FragColor = vec4(vec3(mag), 1.0);\n" + - "}"; - - public GPUImageSobelEdgeDetection() { - super(); - addFilter(new GPUImageGrayscaleFilter()); - addFilter(new GPUImage3x3TextureSamplingFilter(SOBEL_EDGE_DETECTION)); - } - - public void setLineSize(final float size) { - ((GPUImage3x3TextureSamplingFilter) getFilters().get(1)).setLineSize(size); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSobelThresholdFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSobelThresholdFilter.java deleted file mode 100755 index f1dcf64..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSobelThresholdFilter.java +++ /dev/null @@ -1,74 +0,0 @@ -package jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; - -public class GPUImageSobelThresholdFilter extends - GPUImage3x3TextureSamplingFilter { - public static final String SOBEL_THRESHOLD_EDGE_DETECTION = "" + - "precision mediump float;\n" + - "\n" + - "varying vec2 textureCoordinate;\n" + - "varying vec2 leftTextureCoordinate;\n" + - "varying vec2 rightTextureCoordinate;\n" + - "\n" + - "varying vec2 topTextureCoordinate;\n" + - "varying vec2 topLeftTextureCoordinate;\n" + - "varying vec2 topRightTextureCoordinate;\n" + - "\n" + - "varying vec2 bottomTextureCoordinate;\n" + - "varying vec2 bottomLeftTextureCoordinate;\n" + - "varying vec2 bottomRightTextureCoordinate;\n" + - "\n" + - "uniform sampler2D inputImageTexture;\n" + - "uniform lowp float threshold;\n" + - "\n" + - "const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);\n" + - "\n" + - "void main()\n" + - "{\n" + - " float bottomLeftIntensity = texture2D(inputImageTexture, bottomLeftTextureCoordinate).r;\n" + - " float topRightIntensity = texture2D(inputImageTexture, topRightTextureCoordinate).r;\n" + - " float topLeftIntensity = texture2D(inputImageTexture, topLeftTextureCoordinate).r;\n" + - " float bottomRightIntensity = texture2D(inputImageTexture, bottomRightTextureCoordinate).r;\n" + - " float leftIntensity = texture2D(inputImageTexture, leftTextureCoordinate).r;\n" + - " float rightIntensity = texture2D(inputImageTexture, rightTextureCoordinate).r;\n" + - " float bottomIntensity = texture2D(inputImageTexture, bottomTextureCoordinate).r;\n" + - " float topIntensity = texture2D(inputImageTexture, topTextureCoordinate).r;\n" + - " float h = -topLeftIntensity - 2.0 * topIntensity - topRightIntensity + bottomLeftIntensity + 2.0 * bottomIntensity + bottomRightIntensity;\n" + - " float v = -bottomLeftIntensity - 2.0 * leftIntensity - topLeftIntensity + bottomRightIntensity + 2.0 * rightIntensity + topRightIntensity;\n" + - "\n" + - " float mag = 1.0 - length(vec2(h, v));\n" + - " mag = step(threshold, mag);\n" + - "\n" + - " gl_FragColor = vec4(vec3(mag), 1.0);\n" + - "}\n"; - - private int mUniformThresholdLocation; - private float mThreshold = 0.9f; - - public GPUImageSobelThresholdFilter() { - this(0.9f); - } - - public GPUImageSobelThresholdFilter(float threshold) { - super(SOBEL_THRESHOLD_EDGE_DETECTION); - mThreshold = threshold; - } - - @Override - public void onInit() { - super.onInit(); - mUniformThresholdLocation = GLES20.glGetUniformLocation(getProgram(), "threshold"); - } - - @Override - public void onInitialized() { - super.onInitialized(); - setThreshold(mThreshold); - } - - public void setThreshold(final float threshold) { - mThreshold = threshold; - setFloat(mUniformThresholdLocation, threshold); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSoftLightBlendFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSoftLightBlendFilter.java deleted file mode 100755 index 0e1b742..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSoftLightBlendFilter.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -public class GPUImageSoftLightBlendFilter extends GPUImageTwoInputFilter { - public static final String SOFT_LIGHT_BLEND_FRAGMENT_SHADER = "varying highp vec2 textureCoordinate;\n" + - " varying highp vec2 textureCoordinate2;\n" + - "\n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform sampler2D inputImageTexture2;\n" + - " \n" + - " void main()\n" + - " {\n" + - " mediump vec4 base = texture2D(inputImageTexture, textureCoordinate);\n" + - " mediump vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);\n" + - " \n" + - " gl_FragColor = base * (overlay.a * (base / base.a) + (2.0 * overlay * (1.0 - (base / base.a)))) + overlay * (1.0 - base.a) + base * (1.0 - overlay.a);\n" + - " }"; - - public GPUImageSoftLightBlendFilter() { - super(SOFT_LIGHT_BLEND_FRAGMENT_SHADER); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSourceOverBlendFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSourceOverBlendFilter.java deleted file mode 100755 index fd6a7b9..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSourceOverBlendFilter.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -public class GPUImageSourceOverBlendFilter extends GPUImageTwoInputFilter { - public static final String SOURCE_OVER_BLEND_FRAGMENT_SHADER = "varying highp vec2 textureCoordinate;\n" + - " varying highp vec2 textureCoordinate2;\n" + - " \n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform sampler2D inputImageTexture2;\n" + - " \n" + - " void main()\n" + - " {\n" + - " lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + - " lowp vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);\n" + - " \n" + - " gl_FragColor = mix(textureColor, textureColor2, textureColor2.a);\n" + - " }"; - - public GPUImageSourceOverBlendFilter() { - super(SOURCE_OVER_BLEND_FRAGMENT_SHADER); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSphereRefractionFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSphereRefractionFilter.java deleted file mode 100755 index 6314cf1..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSphereRefractionFilter.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.graphics.PointF; -import android.opengl.GLES20; - -public class GPUImageSphereRefractionFilter extends GPUImageFilter { - public static final String SPHERE_FRAGMENT_SHADER = "" + - "varying highp vec2 textureCoordinate;\n" + - "\n" + - "uniform sampler2D inputImageTexture;\n" + - "\n" + - "uniform highp vec2 center;\n" + - "uniform highp float radius;\n" + - "uniform highp float aspectRatio;\n" + - "uniform highp float refractiveIndex;\n" + - "\n" + - "void main()\n" + - "{\n" + - "highp vec2 textureCoordinateToUse = vec2(textureCoordinate.x, (textureCoordinate.y * aspectRatio + 0.5 - 0.5 * aspectRatio));\n" + - "highp float distanceFromCenter = distance(center, textureCoordinateToUse);\n" + - "lowp float checkForPresenceWithinSphere = step(distanceFromCenter, radius);\n" + - "\n" + - "distanceFromCenter = distanceFromCenter / radius;\n" + - "\n" + - "highp float normalizedDepth = radius * sqrt(1.0 - distanceFromCenter * distanceFromCenter);\n" + - "highp vec3 sphereNormal = normalize(vec3(textureCoordinateToUse - center, normalizedDepth));\n" + - "\n" + - "highp vec3 refractedVector = refract(vec3(0.0, 0.0, -1.0), sphereNormal, refractiveIndex);\n" + - "\n" + - "gl_FragColor = texture2D(inputImageTexture, (refractedVector.xy + 1.0) * 0.5) * checkForPresenceWithinSphere; \n" + - "}\n"; - - private PointF mCenter; - private int mCenterLocation; - private float mRadius; - private int mRadiusLocation; - private float mAspectRatio; - private int mAspectRatioLocation; - private float mRefractiveIndex; - private int mRefractiveIndexLocation; - - public GPUImageSphereRefractionFilter() { - this(new PointF(0.5f, 0.5f), 0.25f, 0.71f); - } - - public GPUImageSphereRefractionFilter(PointF center, float radius, float refractiveIndex) { - super(NO_FILTER_VERTEX_SHADER, SPHERE_FRAGMENT_SHADER); - mCenter = center; - mRadius = radius; - mRefractiveIndex = refractiveIndex; - } - - @Override - public void onInit() { - super.onInit(); - mCenterLocation = GLES20.glGetUniformLocation(getProgram(), "center"); - mRadiusLocation = GLES20.glGetUniformLocation(getProgram(), "radius"); - mAspectRatioLocation = GLES20.glGetUniformLocation(getProgram(), "aspectRatio"); - mRefractiveIndexLocation = GLES20.glGetUniformLocation(getProgram(), "refractiveIndex"); - } - - @Override - public void onInitialized() { - super.onInitialized(); - setRadius(mRadius); - setCenter(mCenter); - setRefractiveIndex(mRefractiveIndex); - } - - @Override - public void onOutputSizeChanged(int width, int height) { - mAspectRatio = (float) height / width; - setAspectRatio(mAspectRatio); - super.onOutputSizeChanged(width, height); - } - - private void setAspectRatio(float aspectRatio) { - mAspectRatio = aspectRatio; - setFloat(mAspectRatioLocation, aspectRatio); - } - - /** - * The index of refraction for the sphere, with a default of 0.71 - * - * @param refractiveIndex default 0.71 - */ - public void setRefractiveIndex(float refractiveIndex) { - mRefractiveIndex = refractiveIndex; - setFloat(mRefractiveIndexLocation, refractiveIndex); - } - - /** - * The center about which to apply the distortion, with a default of (0.5, 0.5) - * - * @param center default (0.5, 0.5) - */ - public void setCenter(PointF center) { - mCenter = center; - setPoint(mCenterLocation, center); - } - - /** - * The radius of the distortion, ranging from 0.0 to 1.0, with a default of 0.25 - * - * @param radius from 0.0 to 1.0, default 0.25 - */ - public void setRadius(float radius) { - mRadius = radius; - setFloat(mRadiusLocation, radius); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSubtractBlendFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSubtractBlendFilter.java deleted file mode 100755 index 52b54ec..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSubtractBlendFilter.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -public class GPUImageSubtractBlendFilter extends GPUImageTwoInputFilter { - public static final String SUBTRACT_BLEND_FRAGMENT_SHADER = "varying highp vec2 textureCoordinate;\n" + - " varying highp vec2 textureCoordinate2;\n" + - "\n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform sampler2D inputImageTexture2;\n" + - " \n" + - " void main()\n" + - " {\n" + - " lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + - " lowp vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);\n" + - "\n" + - " gl_FragColor = vec4(textureColor.rgb - textureColor2.rgb, textureColor.a);\n" + - " }"; - - public GPUImageSubtractBlendFilter() { - super(SUBTRACT_BLEND_FRAGMENT_SHADER); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSwirlFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSwirlFilter.java deleted file mode 100755 index d4947b9..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageSwirlFilter.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.graphics.PointF; -import android.opengl.GLES20; - -/** - * Creates a swirl distortion on the image. - */ -public class GPUImageSwirlFilter extends GPUImageFilter { - public static final String SWIRL_FRAGMENT_SHADER = "" + - "varying highp vec2 textureCoordinate;\n" + - "\n" + - "uniform sampler2D inputImageTexture;\n" + - "\n" + - "uniform highp vec2 center;\n" + - "uniform highp float radius;\n" + - "uniform highp float angle;\n" + - "\n" + - "void main()\n" + - "{\n" + - "highp vec2 textureCoordinateToUse = textureCoordinate;\n" + - "highp float dist = distance(center, textureCoordinate);\n" + - "if (dist < radius)\n" + - "{\n" + - "textureCoordinateToUse -= center;\n" + - "highp float percent = (radius - dist) / radius;\n" + - "highp float theta = percent * percent * angle * 8.0;\n" + - "highp float s = sin(theta);\n" + - "highp float c = cos(theta);\n" + - "textureCoordinateToUse = vec2(dot(textureCoordinateToUse, vec2(c, -s)), dot(textureCoordinateToUse, vec2(s, c)));\n" + - "textureCoordinateToUse += center;\n" + - "}\n" + - "\n" + - "gl_FragColor = texture2D(inputImageTexture, textureCoordinateToUse );\n" + - "\n" + - "}\n"; - - private float mAngle; - private int mAngleLocation; - private float mRadius; - private int mRadiusLocation; - private PointF mCenter; - private int mCenterLocation; - - public GPUImageSwirlFilter() { - this(0.5f, 1.0f, new PointF(0.5f, 0.5f)); - } - - public GPUImageSwirlFilter(float radius, float angle, PointF center) { - super(NO_FILTER_VERTEX_SHADER, SWIRL_FRAGMENT_SHADER); - mRadius = radius; - mAngle = angle; - mCenter = center; - } - - @Override - public void onInit() { - super.onInit(); - mAngleLocation = GLES20.glGetUniformLocation(getProgram(), "angle"); - mRadiusLocation = GLES20.glGetUniformLocation(getProgram(), "radius"); - mCenterLocation = GLES20.glGetUniformLocation(getProgram(), "center"); - } - - @Override - public void onInitialized() { - super.onInitialized(); - setRadius(mRadius); - setAngle(mAngle); - setCenter(mCenter); - } - - /** - * The radius of the distortion, ranging from 0.0 to 1.0, with a default of 0.5. - * - * @param radius from 0.0 to 1.0, default 0.5 - */ - public void setRadius(float radius) { - mRadius = radius; - setFloat(mRadiusLocation, radius); - } - - /** - * The amount of distortion to apply, with a minimum of 0.0 and a default of 1.0. - * - * @param angle minimum 0.0, default 1.0 - */ - public void setAngle(float angle) { - mAngle = angle; - setFloat(mAngleLocation, angle); - } - - /** - * The center about which to apply the distortion, with a default of (0.5, 0.5). - * - * @param center default (0.5, 0.5) - */ - public void setCenter(PointF center) { - mCenter = center; - setPoint(mCenterLocation, center); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageThresholdEdgeDetection.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageThresholdEdgeDetection.java deleted file mode 100755 index c136155..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageThresholdEdgeDetection.java +++ /dev/null @@ -1,20 +0,0 @@ -package jp.co.cyberagent.android.gpuimage; - -/** - * Applies sobel edge detection on the image. - */ -public class GPUImageThresholdEdgeDetection extends GPUImageFilterGroup { - public GPUImageThresholdEdgeDetection() { - super(); - addFilter(new GPUImageGrayscaleFilter()); - addFilter(new GPUImageSobelThresholdFilter()); - } - - public void setLineSize(final float size) { - ((GPUImage3x3TextureSamplingFilter) getFilters().get(1)).setLineSize(size); - } - - public void setThreshold(final float threshold) { - ((GPUImageSobelThresholdFilter) getFilters().get(1)).setThreshold(threshold); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageToneCurveFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageToneCurveFilter.java deleted file mode 100755 index 0f6e1d0..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageToneCurveFilter.java +++ /dev/null @@ -1,364 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.graphics.Point; -import android.graphics.PointF; -import android.opengl.GLES20; - -import java.io.*; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; - -public class GPUImageToneCurveFilter extends GPUImageFilter { - public static final String TONE_CURVE_FRAGMENT_SHADER = "" + - " varying highp vec2 textureCoordinate;\n" + - " uniform sampler2D inputImageTexture;\n" + - " uniform sampler2D toneCurveTexture;\n" + - "\n" + - " void main()\n" + - " {\n" + - " lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + - " lowp float redCurveValue = texture2D(toneCurveTexture, vec2(textureColor.r, 0.0)).r;\n" + - " lowp float greenCurveValue = texture2D(toneCurveTexture, vec2(textureColor.g, 0.0)).g;\n" + - " lowp float blueCurveValue = texture2D(toneCurveTexture, vec2(textureColor.b, 0.0)).b;\n" + - "\n" + - " gl_FragColor = vec4(redCurveValue, greenCurveValue, blueCurveValue, textureColor.a);\n" + - " }"; - - private int[] mToneCurveTexture = new int[]{OpenGlUtils.NO_TEXTURE}; - private int mToneCurveTextureUniformLocation; - - private PointF[] mRgbCompositeControlPoints; - private PointF[] mRedControlPoints; - private PointF[] mGreenControlPoints; - private PointF[] mBlueControlPoints; - - private ArrayList mRgbCompositeCurve; - private ArrayList mRedCurve; - private ArrayList mGreenCurve; - private ArrayList mBlueCurve; - - - public GPUImageToneCurveFilter() { - super(NO_FILTER_VERTEX_SHADER, TONE_CURVE_FRAGMENT_SHADER); - - PointF[] defaultCurvePoints = new PointF[]{new PointF(0.0f, 0.0f), new PointF(0.5f, 0.5f), new PointF(1.0f, 1.0f)}; - mRgbCompositeControlPoints = defaultCurvePoints; - mRedControlPoints = defaultCurvePoints; - mGreenControlPoints = defaultCurvePoints; - mBlueControlPoints = defaultCurvePoints; - } - - @Override - public void onInit() { - super.onInit(); - mToneCurveTextureUniformLocation = GLES20.glGetUniformLocation(getProgram(), "toneCurveTexture"); - GLES20.glActiveTexture(GLES20.GL_TEXTURE3); - GLES20.glGenTextures(1, mToneCurveTexture, 0); - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]); - GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); - GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); - GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); - GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); - } - - @Override - public void onInitialized() { - super.onInitialized(); - setRgbCompositeControlPoints(mRgbCompositeControlPoints); - setRedControlPoints(mRedControlPoints); - setGreenControlPoints(mGreenControlPoints); - setBlueControlPoints(mBlueControlPoints); - } - - @Override - protected void onDrawArraysPre() { - if (mToneCurveTexture[0] != OpenGlUtils.NO_TEXTURE) { - GLES20.glActiveTexture(GLES20.GL_TEXTURE3); - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]); - GLES20.glUniform1i(mToneCurveTextureUniformLocation, 3); - } - } - - public void setFromCurveFileInputStream(InputStream input) { - try { - int version = readShort(input); - int totalCurves = readShort(input); - - ArrayList curves = new ArrayList(totalCurves); - float pointRate = 1.0f / 255; - - for (int i = 0; i < totalCurves; i++) { - // 2 bytes, Count of points in the curve (short integer from 2...19) - short pointCount = readShort(input); - - PointF[] points = new PointF[pointCount]; - - // point count * 4 - // Curve points. Each curve point is a pair of short integers where - // the first number is the output value (vertical coordinate on the - // Curves dialog graph) and the second is the input value. All coordinates have range 0 to 255. - for (int j = 0; j < pointCount; j++) { - short y = readShort(input); - short x = readShort(input); - - points[j] = new PointF(x * pointRate, y * pointRate); - } - - curves.add(points); - } - input.close(); - - mRgbCompositeControlPoints = curves.get(0); - mRedControlPoints = curves.get(1); - mGreenControlPoints = curves.get(2); - mBlueControlPoints = curves.get(3); - } catch (IOException e) { - e.printStackTrace(); - } - } - - private short readShort(InputStream input) throws IOException { - return (short) (input.read() << 8 | input.read()); - } - - public void setRgbCompositeControlPoints(PointF[] points) { - mRgbCompositeControlPoints = points; - mRgbCompositeCurve = createSplineCurve(mRgbCompositeControlPoints); - updateToneCurveTexture(); - } - - public void setRedControlPoints(PointF[] points) { - mRedControlPoints = points; - mRedCurve = createSplineCurve(mRedControlPoints); - updateToneCurveTexture(); - } - - public void setGreenControlPoints(PointF[] points) { - mGreenControlPoints = points; - mGreenCurve = createSplineCurve(mGreenControlPoints); - updateToneCurveTexture(); - } - - public void setBlueControlPoints(PointF[] points) { - mBlueControlPoints = points; - mBlueCurve = createSplineCurve(mBlueControlPoints); - updateToneCurveTexture(); - } - - private void updateToneCurveTexture() { - runOnDraw(new Runnable() { - @Override - public void run() { - GLES20.glActiveTexture(GLES20.GL_TEXTURE3); - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mToneCurveTexture[0]); - - if ((mRedCurve.size() >= 256) && (mGreenCurve.size() >= 256) && (mBlueCurve.size() >= 256) && (mRgbCompositeCurve.size() >= 256)) { - byte[] toneCurveByteArray = new byte[256 * 4]; - for (int currentCurveIndex = 0; currentCurveIndex < 256; currentCurveIndex++) { - // BGRA for upload to texture - toneCurveByteArray[currentCurveIndex * 4 + 2] = (byte) ((int) Math.min(Math.max(currentCurveIndex + mBlueCurve.get(currentCurveIndex) + mRgbCompositeCurve.get(currentCurveIndex), 0), 255) & 0xff); - toneCurveByteArray[currentCurveIndex * 4 + 1] = (byte) ((int) Math.min(Math.max(currentCurveIndex + mGreenCurve.get(currentCurveIndex) + mRgbCompositeCurve.get(currentCurveIndex), 0), 255) & 0xff); - toneCurveByteArray[currentCurveIndex * 4] = (byte) ((int) Math.min(Math.max(currentCurveIndex + mRedCurve.get(currentCurveIndex) + mRgbCompositeCurve.get(currentCurveIndex), 0), 255) & 0xff); - toneCurveByteArray[currentCurveIndex * 4 + 3] = (byte) (255 & 0xff); - } - - GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, 256 /*width*/, 1 /*height*/, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, ByteBuffer.wrap(toneCurveByteArray)); - } -// Buffer pixels! -// GLES20.glTexImage2D(int target, -// int level, -// int internalformat, -// int width, -// int height, -// int border, -// int format, -// int type, -// java.nio.Buffer pixels); - } - }); - } - - private ArrayList createSplineCurve(PointF[] points) { - if (points == null || points.length <= 0) { - return null; - } - - // Sort the array - PointF[] pointsSorted = points.clone(); - Arrays.sort(pointsSorted, new Comparator() { - @Override - public int compare(PointF point1, PointF point2) { - if (point1.x < point2.x) { - return -1; - } else if (point1.x > point2.x) { - return 1; - } else { - return 0; - } - } - }); - - // Convert from (0, 1) to (0, 255). - Point[] convertedPoints = new Point[pointsSorted.length]; - for (int i = 0; i < points.length; i++) { - PointF point = pointsSorted[i]; - convertedPoints[i] = new Point((int) (point.x * 255), (int) (point.y * 255)); - } - - ArrayList splinePoints = createSplineCurve2(convertedPoints); - - // If we have a first point like (0.3, 0) we'll be missing some points at the beginning - // that should be 0. - Point firstSplinePoint = splinePoints.get(0); - if (firstSplinePoint.x > 0) { - for (int i = firstSplinePoint.x; i >= 0; i--) { - splinePoints.add(0, new Point(i, 0)); - } - } - - // Insert points similarly at the end, if necessary. - Point lastSplinePoint = splinePoints.get(splinePoints.size() - 1); - if (lastSplinePoint.x < 255) { - for (int i = lastSplinePoint.x + 1; i <= 255; i++) { - splinePoints.add(new Point(i, 255)); - } - } - - // Prepare the spline points. - ArrayList preparedSplinePoints = new ArrayList(splinePoints.size()); - for (Point newPoint : splinePoints) { - Point origPoint = new Point(newPoint.x, newPoint.x); - - float distance = (float) Math.sqrt(Math.pow((origPoint.x - newPoint.x), 2.0) + Math.pow((origPoint.y - newPoint.y), 2.0)); - - if (origPoint.y > newPoint.y) { - distance = -distance; - } - - preparedSplinePoints.add(distance); - } - - return preparedSplinePoints; - } - - private ArrayList createSplineCurve2(Point[] points) { - ArrayList sdA = createSecondDerivative(points); - - // Is [points count] equal to [sdA count]? -// int n = [points count]; - int n = sdA.size(); - if (n < 1) { - return null; - } - double sd[] = new double[n]; - - // From NSMutableArray to sd[n]; - for (int i = 0; i < n; i++) { - sd[i] = sdA.get(i); - } - - - ArrayList output = new ArrayList(n + 1); - - for (int i = 0; i < n - 1; i++) { - Point cur = points[i]; - Point next = points[i + 1]; - - for (int x = cur.x; x < next.x; x++) { - double t = (double) (x - cur.x) / (next.x - cur.x); - - double a = 1 - t; - double b = t; - double h = next.x - cur.x; - - double y = a * cur.y + b * next.y + (h * h / 6) * ((a * a * a - a) * sd[i] + (b * b * b - b) * sd[i + 1]); - - if (y > 255.0) { - y = 255.0; - } else if (y < 0.0) { - y = 0.0; - } - - output.add(new Point(x, (int) Math.round(y))); - } - } - - // If the last point is (255, 255) it doesn't get added. - if (output.size() == 255) { - output.add(points[points.length - 1]); - } - return output; - } - - private ArrayList createSecondDerivative(Point[] points) { - int n = points.length; - if (n <= 1) { - return null; - } - - double matrix[][] = new double[n][3]; - double result[] = new double[n]; - matrix[0][1] = 1; - // What about matrix[0][1] and matrix[0][0]? Assuming 0 for now (Brad L.) - matrix[0][0] = 0; - matrix[0][2] = 0; - - for (int i = 1; i < n - 1; i++) { - Point P1 = points[i - 1]; - Point P2 = points[i]; - Point P3 = points[i + 1]; - - matrix[i][0] = (double) (P2.x - P1.x) / 6; - matrix[i][1] = (double) (P3.x - P1.x) / 3; - matrix[i][2] = (double) (P3.x - P2.x) / 6; - result[i] = (double) (P3.y - P2.y) / (P3.x - P2.x) - (double) (P2.y - P1.y) / (P2.x - P1.x); - } - - // What about result[0] and result[n-1]? Assuming 0 for now (Brad L.) - result[0] = 0; - result[n - 1] = 0; - - matrix[n - 1][1] = 1; - // What about matrix[n-1][0] and matrix[n-1][2]? For now, assuming they are 0 (Brad L.) - matrix[n - 1][0] = 0; - matrix[n - 1][2] = 0; - - // solving pass1 (up->down) - for (int i = 1; i < n; i++) { - double k = matrix[i][0] / matrix[i - 1][1]; - matrix[i][1] -= k * matrix[i - 1][2]; - matrix[i][0] = 0; - result[i] -= k * result[i - 1]; - } - // solving pass2 (down->up) - for (int i = n - 2; i >= 0; i--) { - double k = matrix[i][2] / matrix[i + 1][1]; - matrix[i][1] -= k * matrix[i + 1][0]; - matrix[i][2] = 0; - result[i] -= k * result[i + 1]; - } - - ArrayList output = new ArrayList(n); - for (int i = 0; i < n; i++) output.add(result[i] / matrix[i][1]); - - return output; - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageToonFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageToonFilter.java deleted file mode 100755 index 5148d1d..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageToonFilter.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; - -/** - * This uses Sobel edge detection to place a black border around objects, - * and then it quantizes the colors present in the image to give a cartoon-like quality to the image. - */ -public class GPUImageToonFilter extends GPUImage3x3TextureSamplingFilter { - public static final String TOON_FRAGMENT_SHADER = "" + - "precision highp float;\n" + - "\n" + - "varying vec2 textureCoordinate;\n" + - "varying vec2 leftTextureCoordinate;\n" + - "varying vec2 rightTextureCoordinate;\n" + - "\n" + - "varying vec2 topTextureCoordinate;\n" + - "varying vec2 topLeftTextureCoordinate;\n" + - "varying vec2 topRightTextureCoordinate;\n" + - "\n" + - "varying vec2 bottomTextureCoordinate;\n" + - "varying vec2 bottomLeftTextureCoordinate;\n" + - "varying vec2 bottomRightTextureCoordinate;\n" + - "\n" + - "uniform sampler2D inputImageTexture;\n" + - "\n" + - "uniform highp float intensity;\n" + - "uniform highp float threshold;\n" + - "uniform highp float quantizationLevels;\n" + - "\n" + - "const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);\n" + - "\n" + - "void main()\n" + - "{\n" + - "vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\n" + - "\n" + - "float bottomLeftIntensity = texture2D(inputImageTexture, bottomLeftTextureCoordinate).r;\n" + - "float topRightIntensity = texture2D(inputImageTexture, topRightTextureCoordinate).r;\n" + - "float topLeftIntensity = texture2D(inputImageTexture, topLeftTextureCoordinate).r;\n" + - "float bottomRightIntensity = texture2D(inputImageTexture, bottomRightTextureCoordinate).r;\n" + - "float leftIntensity = texture2D(inputImageTexture, leftTextureCoordinate).r;\n" + - "float rightIntensity = texture2D(inputImageTexture, rightTextureCoordinate).r;\n" + - "float bottomIntensity = texture2D(inputImageTexture, bottomTextureCoordinate).r;\n" + - "float topIntensity = texture2D(inputImageTexture, topTextureCoordinate).r;\n" + - "float h = -topLeftIntensity - 2.0 * topIntensity - topRightIntensity + bottomLeftIntensity + 2.0 * bottomIntensity + bottomRightIntensity;\n" + - "float v = -bottomLeftIntensity - 2.0 * leftIntensity - topLeftIntensity + bottomRightIntensity + 2.0 * rightIntensity + topRightIntensity;\n" + - "\n" + - "float mag = length(vec2(h, v));\n" + - "\n" + - "vec3 posterizedImageColor = floor((textureColor.rgb * quantizationLevels) + 0.5) / quantizationLevels;\n" + - "\n" + - "float thresholdTest = 1.0 - step(threshold, mag);\n" + - "\n" + - "gl_FragColor = vec4(posterizedImageColor * thresholdTest, textureColor.a);\n" + - "}\n"; - - float mThreshold; - int mThresholdLocation; - float mQuantizationLevels; - int mQuantizationLevelsLocation; - - public GPUImageToonFilter() { - this(0.2f, 10.0f); - } - - public GPUImageToonFilter(float threshold, float quantizationLevels) { - super(TOON_FRAGMENT_SHADER); - mThreshold = threshold; - mQuantizationLevels = quantizationLevels; - } - - @Override - public void onInit() { - super.onInit(); - mThresholdLocation = GLES20.glGetUniformLocation(getProgram(), "threshold"); - mQuantizationLevelsLocation = GLES20.glGetUniformLocation(getProgram(), "quantizationLevels"); - } - - @Override - public void onInitialized() { - super.onInitialized(); - setThreshold(mThreshold); - setQuantizationLevels(mQuantizationLevels); - } - - /** - * The threshold at which to apply the edges, default of 0.2. - * - * @param threshold default 0.2 - */ - public void setThreshold(final float threshold) { - mThreshold = threshold; - setFloat(mThresholdLocation, threshold); - } - - /** - * The levels of quantization for the posterization of colors within the scene, with a default of 10.0. - * - * @param quantizationLevels default 10.0 - */ - public void setQuantizationLevels(final float quantizationLevels) { - mQuantizationLevels = quantizationLevels; - setFloat(mQuantizationLevelsLocation, quantizationLevels); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageTwoInputFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageTwoInputFilter.java deleted file mode 100755 index afc3b86..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageTwoInputFilter.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.FloatBuffer; - -import jp.co.cyberagent.android.gpuimage.util.TextureRotationUtil; -import android.graphics.Bitmap; -import android.opengl.GLES20; - -public class GPUImageTwoInputFilter extends GPUImageFilter { - private static final String VERTEX_SHADER = "attribute vec4 position;\n" + - "attribute vec4 inputTextureCoordinate;\n" + - "attribute vec4 inputTextureCoordinate2;\n" + - " \n" + - "varying vec2 textureCoordinate;\n" + - "varying vec2 textureCoordinate2;\n" + - " \n" + - "void main()\n" + - "{\n" + - " gl_Position = position;\n" + - " textureCoordinate = inputTextureCoordinate.xy;\n" + - " textureCoordinate2 = inputTextureCoordinate2.xy;\n" + - "}"; - - public int mFilterSecondTextureCoordinateAttribute; - public int mFilterInputTextureUniform2; - public int mFilterSourceTexture2 = OpenGlUtils.NO_TEXTURE; - private ByteBuffer mTexture2CoordinatesBuffer; - private Bitmap mBitmap; - - public GPUImageTwoInputFilter(String fragmentShader) { - this(VERTEX_SHADER, fragmentShader); - } - - public GPUImageTwoInputFilter(String vertexShader, String fragmentShader) { - super(vertexShader, fragmentShader); - setRotation(Rotation.NORMAL, false, false); - } - - @Override - public void onInit() { - super.onInit(); - - mFilterSecondTextureCoordinateAttribute = GLES20.glGetAttribLocation(getProgram(), "inputTextureCoordinate2"); - mFilterInputTextureUniform2 = GLES20.glGetUniformLocation(getProgram(), "inputImageTexture2"); // This does assume a name of "inputImageTexture2" for second input texture in the fragment shader - GLES20.glEnableVertexAttribArray(mFilterSecondTextureCoordinateAttribute); - - if (mBitmap != null&&!mBitmap.isRecycled()) { - setBitmap(mBitmap); - } - } - - public void setBitmap(final Bitmap bitmap) { - if (bitmap != null && bitmap.isRecycled()) { - return; - } - mBitmap = bitmap; - if (mBitmap == null) { - return; - } - runOnDraw(new Runnable() { - public void run() { - if (mFilterSourceTexture2 == OpenGlUtils.NO_TEXTURE) { - if (bitmap == null || bitmap.isRecycled()) { - return; - } - GLES20.glActiveTexture(GLES20.GL_TEXTURE3); - mFilterSourceTexture2 = OpenGlUtils.loadTexture(bitmap, OpenGlUtils.NO_TEXTURE, false); - } - } - }); - } - - public Bitmap getBitmap() { - return mBitmap; - } - - public void recycleBitmap() { - if (mBitmap != null && !mBitmap.isRecycled()) { - mBitmap.recycle(); - mBitmap = null; - } - } - - public void onDestroy() { - super.onDestroy(); - GLES20.glDeleteTextures(1, new int[]{ - mFilterSourceTexture2 - }, 0); - mFilterSourceTexture2 = OpenGlUtils.NO_TEXTURE; - } - - @Override - protected void onDrawArraysPre() { - GLES20.glEnableVertexAttribArray(mFilterSecondTextureCoordinateAttribute); - GLES20.glActiveTexture(GLES20.GL_TEXTURE3); - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mFilterSourceTexture2); - GLES20.glUniform1i(mFilterInputTextureUniform2, 3); - - mTexture2CoordinatesBuffer.position(0); - GLES20.glVertexAttribPointer(mFilterSecondTextureCoordinateAttribute, 2, GLES20.GL_FLOAT, false, 0, mTexture2CoordinatesBuffer); - } - - public void setRotation(final Rotation rotation, final boolean flipHorizontal, final boolean flipVertical) { - float[] buffer = TextureRotationUtil.getRotation(rotation, flipHorizontal, flipVertical); - - ByteBuffer bBuffer = ByteBuffer.allocateDirect(32).order(ByteOrder.nativeOrder()); - FloatBuffer fBuffer = bBuffer.asFloatBuffer(); - fBuffer.put(buffer); - fBuffer.flip(); - - mTexture2CoordinatesBuffer = bBuffer; - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageTwoPassFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageTwoPassFilter.java deleted file mode 100755 index bf3fbf1..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageTwoPassFilter.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -public class GPUImageTwoPassFilter extends GPUImageFilterGroup { - public GPUImageTwoPassFilter(String firstVertexShader, String firstFragmentShader, - String secondVertexShader, String secondFragmentShader) { - super(null); - addFilter(new GPUImageFilter(firstVertexShader, firstFragmentShader)); - addFilter(new GPUImageFilter(secondVertexShader, secondFragmentShader)); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageTwoPassTextureSamplingFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageTwoPassTextureSamplingFilter.java deleted file mode 100755 index 19c0365..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageTwoPassTextureSamplingFilter.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; - -public class GPUImageTwoPassTextureSamplingFilter extends GPUImageTwoPassFilter { - public GPUImageTwoPassTextureSamplingFilter(String firstVertexShader, String firstFragmentShader, - String secondVertexShader, String secondFragmentShader) { - super(firstVertexShader, firstFragmentShader, - secondVertexShader, secondFragmentShader); - } - - @Override - public void onInit() { - super.onInit(); - initTexelOffsets(); - } - - protected void initTexelOffsets() { - float ratio = getHorizontalTexelOffsetRatio(); - GPUImageFilter filter = mFilters.get(0); - int texelWidthOffsetLocation = GLES20.glGetUniformLocation(filter.getProgram(), "texelWidthOffset"); - int texelHeightOffsetLocation = GLES20.glGetUniformLocation(filter.getProgram(), "texelHeightOffset"); - filter.setFloat(texelWidthOffsetLocation, ratio / mOutputWidth); - filter.setFloat(texelHeightOffsetLocation, 0); - - ratio = getVerticalTexelOffsetRatio(); - filter = mFilters.get(1); - texelWidthOffsetLocation = GLES20.glGetUniformLocation(filter.getProgram(), "texelWidthOffset"); - texelHeightOffsetLocation = GLES20.glGetUniformLocation(filter.getProgram(), "texelHeightOffset"); - filter.setFloat(texelWidthOffsetLocation, 0); - filter.setFloat(texelHeightOffsetLocation, ratio / mOutputHeight); - } - - @Override - public void onOutputSizeChanged(int width, int height) { - super.onOutputSizeChanged(width, height); - initTexelOffsets(); - } - - public float getVerticalTexelOffsetRatio() { - return 1f; - } - - public float getHorizontalTexelOffsetRatio() { - return 1f; - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageView.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageView.java deleted file mode 100755 index ff32e5d..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageView.java +++ /dev/null @@ -1,456 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Color; -import android.media.MediaScannerConnection; -import android.net.Uri; -import android.opengl.GLES20; -import android.opengl.GLSurfaceView; -import android.os.*; -import android.util.AttributeSet; -import android.view.Gravity; -import android.view.ViewTreeObserver; -import android.widget.FrameLayout; -import android.widget.ProgressBar; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.nio.IntBuffer; -import java.util.concurrent.Semaphore; - -public class GPUImageView extends FrameLayout { - - private GLSurfaceView mGLSurfaceView; - private GPUImage mGPUImage; - private GPUImageFilter mFilter; - public Size mForceSize = null; - private float mRatio = 0.0f; - - public GPUImageView(Context context) { - super(context); - init(context, null); - } - - public GPUImageView(Context context, AttributeSet attrs) { - super(context, attrs); - init(context, attrs); - } - - private void init(Context context, AttributeSet attrs) { - mGLSurfaceView = new GPUImageGLSurfaceView(context, attrs); - addView(mGLSurfaceView); - mGPUImage = new GPUImage(getContext()); - mGPUImage.setGLSurfaceView(mGLSurfaceView); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - if (mRatio != 0.0f) { - int width = MeasureSpec.getSize(widthMeasureSpec); - int height = MeasureSpec.getSize(heightMeasureSpec); - - int newHeight; - int newWidth; - if (width / mRatio < height) { - newWidth = width; - newHeight = Math.round(width / mRatio); - } else { - newHeight = height; - newWidth = Math.round(height * mRatio); - } - - int newWidthSpec = MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY); - int newHeightSpec = MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.EXACTLY); - super.onMeasure(newWidthSpec, newHeightSpec); - } else { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - } - } - - /** - * Retrieve the GPUImage instance used by this view. - * - * @return used GPUImage instance - */ - public GPUImage getGPUImage() { - return mGPUImage; - } - - // TODO Should be an xml attribute. But then GPUImage can not be distributed as .jar anymore. - public void setRatio(float ratio) { - mRatio = ratio; - mGLSurfaceView.requestLayout(); - mGPUImage.deleteImage(); - } - - /** - * Set the scale type of GPUImage. - * - * @param scaleType the new ScaleType - */ - public void setScaleType(GPUImage.ScaleType scaleType) { - mGPUImage.setScaleType(scaleType); - } - - /** - * Sets the rotation of the displayed image. - * - * @param rotation new rotation - */ - public void setRotation(Rotation rotation) { - mGPUImage.setRotation(rotation); - requestRender(); - } - - /** - * Set the filter to be applied on the image. - * - * @param filter Filter that should be applied on the image. - */ - public void setFilter(GPUImageFilter filter) { - mFilter = filter; - mGPUImage.setFilter(filter); - requestRender(); - } - - /** - * Get the current applied filter. - * - * @return the current filter - */ - public GPUImageFilter getFilter() { - return mFilter; - } - - /** - * Sets the image on which the filter should be applied. - * - * @param bitmap the new image - */ - public void setImage(final Bitmap bitmap) { - mGPUImage.setImage(bitmap); - } - - /** - * Sets the image on which the filter should be applied from a Uri. - * - * @param uri the uri of the new image - */ - public void setImage(final Uri uri) { - mGPUImage.setImage(uri); - } - - /** - * Sets the image on which the filter should be applied from a File. - * - * @param file the file of the new image - */ - public void setImage(final File file) { - mGPUImage.setImage(file); - } - - public void requestRender() { - mGLSurfaceView.requestRender(); - } - - /** - * Save current image with applied filter to Pictures. It will be stored on - * the default Picture folder on the phone below the given folderName and - * fileName.
    - * This method is async and will notify when the image was saved through the - * listener. - * - * @param folderName the folder name - * @param fileName the file name - * @param listener the listener - */ - public void saveToPictures(final String folderName, final String fileName, - final OnPictureSavedListener listener) { - new SaveTask(folderName, fileName, listener).execute(); - } - - /** - * Save current image with applied filter to Pictures. It will be stored on - * the default Picture folder on the phone below the given folderName and - * fileName.
    - * This method is async and will notify when the image was saved through the - * listener. - * - * @param folderName the folder name - * @param fileName the file name - * @param width requested output width - * @param height requested output height - * @param listener the listener - */ - public void saveToPictures(final String folderName, final String fileName, - int width, int height, - final OnPictureSavedListener listener) { - new SaveTask(folderName, fileName, width, height, listener).execute(); - } - - /** - * Retrieve current image with filter applied and given size as Bitmap. - * - * @param width requested Bitmap width - * @param height requested Bitmap height - * @return Bitmap of picture with given size - * @throws InterruptedException - */ - public Bitmap capture(final int width, final int height) throws InterruptedException { - // This method needs to run on a background thread because it will take a longer time - if (Looper.myLooper() == Looper.getMainLooper()) { - throw new IllegalStateException("Do not call this method from the UI thread!"); - } - - mForceSize = new Size(width, height); - - final Semaphore waiter = new Semaphore(0); - - // Layout with new size - getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { - @Override - public void onGlobalLayout() { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { - getViewTreeObserver().removeGlobalOnLayoutListener(this); - } else { - getViewTreeObserver().removeOnGlobalLayoutListener(this); - } - waiter.release(); - } - }); - post(new Runnable() { - @Override - public void run() { - // Show loading - addView(new LoadingView(getContext())); - - mGLSurfaceView.requestLayout(); - } - }); - waiter.acquire(); - - // Run one render pass - mGPUImage.runOnGLThread(new Runnable() { - @Override - public void run() { - waiter.release(); - } - }); - requestRender(); - waiter.acquire(); - Bitmap bitmap = capture(); - - - mForceSize = null; - post(new Runnable() { - @Override - public void run() { - mGLSurfaceView.requestLayout(); - } - }); - requestRender(); - - postDelayed(new Runnable() { - @Override - public void run() { - // Remove loading view - removeViewAt(1); - } - }, 300); - - return bitmap; - } - - /** - * Capture the current image with the size as it is displayed and retrieve it as Bitmap. - * @return current output as Bitmap - * @throws InterruptedException - */ - public Bitmap capture() throws InterruptedException { - final Semaphore waiter = new Semaphore(0); - - final int width = mGLSurfaceView.getMeasuredWidth(); - final int height = mGLSurfaceView.getMeasuredHeight(); - - // Take picture on OpenGL thread - final int[] pixelMirroredArray = new int[width * height]; - mGPUImage.runOnGLThread(new Runnable() { - @Override - public void run() { - final IntBuffer pixelBuffer = IntBuffer.allocate(width * height); - GLES20.glReadPixels(0, 0, width, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, pixelBuffer); - int[] pixelArray = pixelBuffer.array(); - - // Convert upside down mirror-reversed image to right-side up normal image. - for (int i = 0; i < height; i++) { - for (int j = 0; j < width; j++) { - pixelMirroredArray[(height - i - 1) * width + j] = pixelArray[i * width + j]; - } - } - waiter.release(); - } - }); - requestRender(); - waiter.acquire(); - - Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - bitmap.copyPixelsFromBuffer(IntBuffer.wrap(pixelMirroredArray)); - return bitmap; - } - - /** - * Pauses the GLSurfaceView. - */ - public void onPause() { - mGLSurfaceView.onPause(); - } - - /** - * Resumes the GLSurfaceView. - */ - public void onResume() { - mGLSurfaceView.onResume(); - } - - public static class Size { - int width; - int height; - - public Size(int width, int height) { - this.width = width; - this.height = height; - } - } - - private class GPUImageGLSurfaceView extends GLSurfaceView { - public GPUImageGLSurfaceView(Context context) { - super(context); - } - - public GPUImageGLSurfaceView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - if (mForceSize != null) { - super.onMeasure(MeasureSpec.makeMeasureSpec(mForceSize.width, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(mForceSize.height, MeasureSpec.EXACTLY)); - } else { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - } - } - } - - private class LoadingView extends FrameLayout { - public LoadingView(Context context) { - super(context); - init(); - } - - public LoadingView(Context context, AttributeSet attrs) { - super(context, attrs); - init(); - } - - public LoadingView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - init(); - } - - private void init() { - ProgressBar view = new ProgressBar(getContext()); - view.setLayoutParams( - new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, Gravity.CENTER)); - addView(view); - setBackgroundColor(Color.BLACK); - } - } - - private class SaveTask extends AsyncTask { - private final String mFolderName; - private final String mFileName; - private final int mWidth; - private final int mHeight; - private final OnPictureSavedListener mListener; - private final Handler mHandler; - - public SaveTask(final String folderName, final String fileName, - final OnPictureSavedListener listener) { - this(folderName, fileName, 0, 0, listener); - } - - public SaveTask(final String folderName, final String fileName, int width, int height, - final OnPictureSavedListener listener) { - mFolderName = folderName; - mFileName = fileName; - mWidth = width; - mHeight = height; - mListener = listener; - mHandler = new Handler(); - } - - @Override - protected Void doInBackground(final Void... params) { - try { - Bitmap result = mWidth != 0 ? capture(mWidth, mHeight) : capture(); - saveImage(mFolderName, mFileName, result); - } catch (InterruptedException e) { - e.printStackTrace(); - } - return null; - } - - private void saveImage(final String folderName, final String fileName, final Bitmap image) { - File path = Environment - .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); - File file = new File(path, folderName + "/" + fileName); - try { - file.getParentFile().mkdirs(); - image.compress(Bitmap.CompressFormat.JPEG, 80, new FileOutputStream(file)); - MediaScannerConnection.scanFile(getContext(), - new String[]{ - file.toString() - }, null, - new MediaScannerConnection.OnScanCompletedListener() { - @Override - public void onScanCompleted(final String path, final Uri uri) { - if (mListener != null) { - mHandler.post(new Runnable() { - - @Override - public void run() { - mListener.onPictureSaved(uri); - } - }); - } - } - }); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } - } - } - - public interface OnPictureSavedListener { - void onPictureSaved(Uri uri); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageVignetteFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageVignetteFilter.java deleted file mode 100755 index 439e8bd..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageVignetteFilter.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.graphics.PointF; -import android.opengl.GLES20; - -/** - * Performs a vignetting effect, fading out the image at the edges - * x: - * y: The directional intensity of the vignetting, with a default of x = 0.75, y = 0.5 - */ -public class GPUImageVignetteFilter extends GPUImageFilter { - public static final String VIGNETTING_FRAGMENT_SHADER = "" + - " uniform sampler2D inputImageTexture;\n" + - " varying highp vec2 textureCoordinate;\n" + - " \n" + - " uniform lowp vec2 vignetteCenter;\n" + - " uniform lowp vec3 vignetteColor;\n" + - " uniform highp float vignetteStart;\n" + - " uniform highp float vignetteEnd;\n" + - " \n" + - " void main()\n" + - " {\n" + - " /*\n" + - " lowp vec3 rgb = texture2D(inputImageTexture, textureCoordinate).rgb;\n" + - " lowp float d = distance(textureCoordinate, vec2(0.5,0.5));\n" + - " rgb *= (1.0 - smoothstep(vignetteStart, vignetteEnd, d));\n" + - " gl_FragColor = vec4(vec3(rgb),1.0);\n" + - " */\n" + - " \n" + - " lowp vec3 rgb = texture2D(inputImageTexture, textureCoordinate).rgb;\n" + - " lowp float d = distance(textureCoordinate, vec2(vignetteCenter.x, vignetteCenter.y));\n" + - " lowp float percent = smoothstep(vignetteStart, vignetteEnd, d);\n" + - " gl_FragColor = vec4(mix(rgb.x, vignetteColor.x, percent), mix(rgb.y, vignetteColor.y, percent), mix(rgb.z, vignetteColor.z, percent), 1.0);\n" + - " }"; - - private int mVignetteCenterLocation; - private PointF mVignetteCenter; - private int mVignetteColorLocation; - private float[] mVignetteColor; - private int mVignetteStartLocation; - private float mVignetteStart; - private int mVignetteEndLocation; - private float mVignetteEnd; - - public GPUImageVignetteFilter() { - this(new PointF(), new float[] {0.0f, 0.0f, 0.0f}, 0.3f, 0.75f); - } - - public GPUImageVignetteFilter(final PointF vignetteCenter, final float[] vignetteColor, final float vignetteStart, final float vignetteEnd) { - super(NO_FILTER_VERTEX_SHADER, VIGNETTING_FRAGMENT_SHADER); - mVignetteCenter = vignetteCenter; - mVignetteColor = vignetteColor; - mVignetteStart = vignetteStart; - mVignetteEnd = vignetteEnd; - - } - - @Override - public void onInit() { - super.onInit(); - mVignetteCenterLocation = GLES20.glGetUniformLocation(getProgram(), "vignetteCenter"); - mVignetteColorLocation = GLES20.glGetUniformLocation(getProgram(), "vignetteColor"); - mVignetteStartLocation = GLES20.glGetUniformLocation(getProgram(), "vignetteStart"); - mVignetteEndLocation = GLES20.glGetUniformLocation(getProgram(), "vignetteEnd"); - - setVignetteCenter(mVignetteCenter); - setVignetteColor(mVignetteColor); - setVignetteStart(mVignetteStart); - setVignetteEnd(mVignetteEnd); - } - - - public void setVignetteCenter(final PointF vignetteCenter) { - mVignetteCenter = vignetteCenter; - setPoint(mVignetteCenterLocation, mVignetteCenter); - } - - public void setVignetteColor(final float[] vignetteColor) { - mVignetteColor = vignetteColor; - setFloatVec3(mVignetteColorLocation, mVignetteColor); - } - - public void setVignetteStart(final float vignetteStart) { - mVignetteStart = vignetteStart; - setFloat(mVignetteStartLocation, mVignetteStart); - } - - public void setVignetteEnd(final float vignetteEnd) { - mVignetteEnd = vignetteEnd; - setFloat(mVignetteEndLocation, mVignetteEnd); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageWeakPixelInclusionFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageWeakPixelInclusionFilter.java deleted file mode 100755 index 3e1b8f0..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageWeakPixelInclusionFilter.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -public class GPUImageWeakPixelInclusionFilter extends GPUImage3x3TextureSamplingFilter { - public static final String WEAKPIXEL_FRAGMENT_SHADER = "" + - "precision lowp float;\n" + - "\n" + - "varying vec2 textureCoordinate;\n" + - "varying vec2 leftTextureCoordinate;\n" + - "varying vec2 rightTextureCoordinate;\n" + - "\n" + - "varying vec2 topTextureCoordinate;\n" + - "varying vec2 topLeftTextureCoordinate;\n" + - "varying vec2 topRightTextureCoordinate;\n" + - "\n" + - "varying vec2 bottomTextureCoordinate;\n" + - "varying vec2 bottomLeftTextureCoordinate;\n" + - "varying vec2 bottomRightTextureCoordinate;\n" + - "\n" + - "uniform sampler2D inputImageTexture;\n" + - "\n" + - "void main()\n" + - "{\n" + - "float bottomLeftIntensity = texture2D(inputImageTexture, bottomLeftTextureCoordinate).r;\n" + - "float topRightIntensity = texture2D(inputImageTexture, topRightTextureCoordinate).r;\n" + - "float topLeftIntensity = texture2D(inputImageTexture, topLeftTextureCoordinate).r;\n" + - "float bottomRightIntensity = texture2D(inputImageTexture, bottomRightTextureCoordinate).r;\n" + - "float leftIntensity = texture2D(inputImageTexture, leftTextureCoordinate).r;\n" + - "float rightIntensity = texture2D(inputImageTexture, rightTextureCoordinate).r;\n" + - "float bottomIntensity = texture2D(inputImageTexture, bottomTextureCoordinate).r;\n" + - "float topIntensity = texture2D(inputImageTexture, topTextureCoordinate).r;\n" + - "float centerIntensity = texture2D(inputImageTexture, textureCoordinate).r;\n" + - "\n" + - "float pixelIntensitySum = bottomLeftIntensity + topRightIntensity + topLeftIntensity + bottomRightIntensity + leftIntensity + rightIntensity + bottomIntensity + topIntensity + centerIntensity;\n" + - "float sumTest = step(1.5, pixelIntensitySum);\n" + - "float pixelTest = step(0.01, centerIntensity);\n" + - "\n" + - "gl_FragColor = vec4(vec3(sumTest * pixelTest), 1.0);\n" + - "}\n"; - - public GPUImageWeakPixelInclusionFilter() { - super(WEAKPIXEL_FRAGMENT_SHADER); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageWhiteBalanceFilter.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageWhiteBalanceFilter.java deleted file mode 100755 index 1818da9..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/GPUImageWhiteBalanceFilter.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import android.opengl.GLES20; - -/** - * Adjusts the white balance of incoming image.
    - *
    - * temperature: - * tint: - */ -public class GPUImageWhiteBalanceFilter extends GPUImageFilter { - public static final String WHITE_BALANCE_FRAGMENT_SHADER = "" + - "uniform sampler2D inputImageTexture;\n" + - "varying highp vec2 textureCoordinate;\n" + - " \n" + - "uniform lowp float temperature;\n" + - "uniform lowp float tint;\n" + - "\n" + - "const lowp vec3 warmFilter = vec3(0.93, 0.54, 0.0);\n" + - "\n" + - "const mediump mat3 RGBtoYIQ = mat3(0.299, 0.587, 0.114, 0.596, -0.274, -0.322, 0.212, -0.523, 0.311);\n" + - "const mediump mat3 YIQtoRGB = mat3(1.0, 0.956, 0.621, 1.0, -0.272, -0.647, 1.0, -1.105, 1.702);\n" + - "\n" + - "void main()\n" + - "{\n" + - " lowp vec4 source = texture2D(inputImageTexture, textureCoordinate);\n" + - " \n" + - " mediump vec3 yiq = RGBtoYIQ * source.rgb; //adjusting tint\n" + - " yiq.b = clamp(yiq.b + tint*0.5226*0.1, -0.5226, 0.5226);\n" + - " lowp vec3 rgb = YIQtoRGB * yiq;\n" + - "\n" + - " lowp vec3 processed = vec3(\n" + - " (rgb.r < 0.5 ? (2.0 * rgb.r * warmFilter.r) : (1.0 - 2.0 * (1.0 - rgb.r) * (1.0 - warmFilter.r))), //adjusting temperature\n" + - " (rgb.g < 0.5 ? (2.0 * rgb.g * warmFilter.g) : (1.0 - 2.0 * (1.0 - rgb.g) * (1.0 - warmFilter.g))), \n" + - " (rgb.b < 0.5 ? (2.0 * rgb.b * warmFilter.b) : (1.0 - 2.0 * (1.0 - rgb.b) * (1.0 - warmFilter.b))));\n" + - "\n" + - " gl_FragColor = vec4(mix(rgb, processed, temperature), source.a);\n" + - "}"; - - private int mTemperatureLocation; - private float mTemperature; - private int mTintLocation; - private float mTint; - - public GPUImageWhiteBalanceFilter() { - this(5000.0f, 0.0f); - } - - public GPUImageWhiteBalanceFilter(final float temperature, final float tint) { - super(NO_FILTER_VERTEX_SHADER, WHITE_BALANCE_FRAGMENT_SHADER); - mTemperature = temperature; - mTint = tint; - } - - @Override - public void onInit() { - super.onInit(); - mTemperatureLocation = GLES20.glGetUniformLocation(getProgram(), "temperature"); - mTintLocation = GLES20.glGetUniformLocation(getProgram(), "tint"); - - setTemperature(mTemperature); - setTint(mTint); - } - - - public void setTemperature(final float temperature) { - mTemperature = temperature; - setFloat(mTemperatureLocation, mTemperature < 5000 ? (float)(0.0004 * (mTemperature-5000.0)) : (float)(0.00006 * (mTemperature-5000.0))); - } - - public void setTint(final float tint) { - mTint = tint; - setFloat(mTintLocation, (float)(mTint/100.0)); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/OpenGlUtils.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/OpenGlUtils.java deleted file mode 100755 index e858970..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/OpenGlUtils.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -import java.nio.IntBuffer; - -import android.graphics.Bitmap; -import android.graphics.Bitmap.Config; -import android.hardware.Camera.Size; -import android.opengl.GLES20; -import android.opengl.GLUtils; -import android.util.Log; - -public class OpenGlUtils { - public static final int NO_TEXTURE = -1; - - public static int loadTexture(final Bitmap img, final int usedTexId) { - return loadTexture(img, usedTexId, true); - } - - public static int loadTexture(final Bitmap img, final int usedTexId, final boolean recycle) { - int textures[] = new int[1]; - if (usedTexId == NO_TEXTURE) { - GLES20.glGenTextures(1, textures, 0); - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]); - GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, - GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); - GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, - GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); - GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, - GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); - GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, - GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); - - GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, img, 0); - } else { - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, usedTexId); - GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, img); - textures[0] = usedTexId; - } - if (recycle) { - img.recycle(); - } - return textures[0]; - } - - public static int loadTexture(final IntBuffer data, final Size size, final int usedTexId) { - int textures[] = new int[1]; - if (usedTexId == NO_TEXTURE) { - GLES20.glGenTextures(1, textures, 0); - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]); - GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, - GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); - GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, - GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); - GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, - GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); - GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, - GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); - GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, size.width, size.height, - 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, data); - } else { - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, usedTexId); - GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, size.width, - size.height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, data); - textures[0] = usedTexId; - } - return textures[0]; - } - - public static int loadTextureAsBitmap(final IntBuffer data, final Size size, final int usedTexId) { - Bitmap bitmap = Bitmap - .createBitmap(data.array(), size.width, size.height, Config.ARGB_8888); - return loadTexture(bitmap, usedTexId); - } - - public static int loadShader(final String strSource, final int iType) { - int[] compiled = new int[1]; - int iShader = GLES20.glCreateShader(iType); - GLES20.glShaderSource(iShader, strSource); - GLES20.glCompileShader(iShader); - GLES20.glGetShaderiv(iShader, GLES20.GL_COMPILE_STATUS, compiled, 0); - if (compiled[0] == 0) { - Log.d("Load Shader Failed", "Compilation\n" + GLES20.glGetShaderInfoLog(iShader)); - return 0; - } - return iShader; - } - - public static int loadProgram(final String strVSource, final String strFSource) { - int iVShader; - int iFShader; - int iProgId; - int[] link = new int[1]; - iVShader = loadShader(strVSource, GLES20.GL_VERTEX_SHADER); - if (iVShader == 0) { - Log.d("Load Program", "Vertex Shader Failed"); - return 0; - } - iFShader = loadShader(strFSource, GLES20.GL_FRAGMENT_SHADER); - if (iFShader == 0) { - Log.d("Load Program", "Fragment Shader Failed"); - return 0; - } - - iProgId = GLES20.glCreateProgram(); - - GLES20.glAttachShader(iProgId, iVShader); - GLES20.glAttachShader(iProgId, iFShader); - - GLES20.glLinkProgram(iProgId); - - GLES20.glGetProgramiv(iProgId, GLES20.GL_LINK_STATUS, link, 0); - if (link[0] <= 0) { - Log.d("Load Program", "Linking Failed"); - return 0; - } - GLES20.glDeleteShader(iVShader); - GLES20.glDeleteShader(iFShader); - return iProgId; - } - - public static float rnd(final float min, final float max) { - float fRandNum = (float) Math.random(); - return min + (max - min) * fRandNum; - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/PixelBuffer.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/PixelBuffer.java deleted file mode 100755 index 45317a1..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/PixelBuffer.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * Copyright (C) 2010 jsemler - * - * Original publication without License - * http://www.anddev.org/android-2d-3d-graphics-opengl-tutorials-f2/possible-to-do-opengl-off-screen-rendering-in-android-t13232.html#p41662 - */ - -package jp.co.cyberagent.android.gpuimage; - -import static javax.microedition.khronos.egl.EGL10.EGL_ALPHA_SIZE; -import static javax.microedition.khronos.egl.EGL10.EGL_BLUE_SIZE; -import static javax.microedition.khronos.egl.EGL10.EGL_DEFAULT_DISPLAY; -import static javax.microedition.khronos.egl.EGL10.EGL_DEPTH_SIZE; -import static javax.microedition.khronos.egl.EGL10.EGL_GREEN_SIZE; -import static javax.microedition.khronos.egl.EGL10.EGL_HEIGHT; -import static javax.microedition.khronos.egl.EGL10.EGL_NONE; -import static javax.microedition.khronos.egl.EGL10.EGL_NO_CONTEXT; -import static javax.microedition.khronos.egl.EGL10.EGL_RED_SIZE; -import static javax.microedition.khronos.egl.EGL10.EGL_STENCIL_SIZE; -import static javax.microedition.khronos.egl.EGL10.EGL_WIDTH; -import static javax.microedition.khronos.opengles.GL10.GL_RGBA; -import static javax.microedition.khronos.opengles.GL10.GL_UNSIGNED_BYTE; - -import java.nio.IntBuffer; - -import javax.microedition.khronos.egl.EGL10; -import javax.microedition.khronos.egl.EGLConfig; -import javax.microedition.khronos.egl.EGLContext; -import javax.microedition.khronos.egl.EGLDisplay; -import javax.microedition.khronos.egl.EGLSurface; -import javax.microedition.khronos.opengles.GL10; - -import android.graphics.Bitmap; -import android.opengl.GLSurfaceView; -import android.util.Log; - -public class PixelBuffer { - final static String TAG = "PixelBuffer"; - final static boolean LIST_CONFIGS = false; - - GLSurfaceView.Renderer mRenderer; // borrow this interface - int mWidth, mHeight; - Bitmap mBitmap; - - EGL10 mEGL; - EGLDisplay mEGLDisplay; - EGLConfig[] mEGLConfigs; - EGLConfig mEGLConfig; - EGLContext mEGLContext; - EGLSurface mEGLSurface; - GL10 mGL; - - String mThreadOwner; - - public PixelBuffer(final int width, final int height) { - mWidth = width; - mHeight = height; - - int[] version = new int[2]; - int[] attribList = new int[] { - EGL_WIDTH, mWidth, - EGL_HEIGHT, mHeight, - EGL_NONE - }; - - // No error checking performed, minimum required code to elucidate logic - mEGL = (EGL10) EGLContext.getEGL(); - mEGLDisplay = mEGL.eglGetDisplay(EGL_DEFAULT_DISPLAY); - mEGL.eglInitialize(mEGLDisplay, version); - mEGLConfig = chooseConfig(); // Choosing a config is a little more - // complicated - - // mEGLContext = mEGL.eglCreateContext(mEGLDisplay, mEGLConfig, - // EGL_NO_CONTEXT, null); - int EGL_CONTEXT_CLIENT_VERSION = 0x3098; - int[] attrib_list = { - EGL_CONTEXT_CLIENT_VERSION, 2, - EGL10.EGL_NONE - }; - mEGLContext = mEGL.eglCreateContext(mEGLDisplay, mEGLConfig, EGL_NO_CONTEXT, attrib_list); - - mEGLSurface = mEGL.eglCreatePbufferSurface(mEGLDisplay, mEGLConfig, attribList); - mEGL.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext); - - mGL = (GL10) mEGLContext.getGL(); - - // Record thread owner of OpenGL context - mThreadOwner = Thread.currentThread().getName(); - } - - public void setRenderer(final GLSurfaceView.Renderer renderer) { - mRenderer = renderer; - - // Does this thread own the OpenGL context? - if (!Thread.currentThread().getName().equals(mThreadOwner)) { - Log.e(TAG, "setRenderer: This thread does not own the OpenGL context."); - return; - } - - // Call the renderer initialization routines - mRenderer.onSurfaceCreated(mGL, mEGLConfig); - mRenderer.onSurfaceChanged(mGL, mWidth, mHeight); - } - - public Bitmap getBitmap() { - // Do we have a renderer? - if (mRenderer == null) { - Log.e(TAG, "getBitmap: Renderer was not set."); - return null; - } - - // Does this thread own the OpenGL context? - if (!Thread.currentThread().getName().equals(mThreadOwner)) { - Log.e(TAG, "getBitmap: This thread does not own the OpenGL context."); - return null; - } - - // Call the renderer draw routine (it seems that some filters do not - // work if this is only called once) - mRenderer.onDrawFrame(mGL); - mRenderer.onDrawFrame(mGL); - convertToBitmap(); - return mBitmap; - } - - public void destroy() { - mRenderer.onDrawFrame(mGL); - mRenderer.onDrawFrame(mGL); - mEGL.eglMakeCurrent(mEGLDisplay, EGL10.EGL_NO_SURFACE, - EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); - - mEGL.eglDestroySurface(mEGLDisplay, mEGLSurface); - mEGL.eglDestroyContext(mEGLDisplay, mEGLContext); - mEGL.eglTerminate(mEGLDisplay); - } - - private EGLConfig chooseConfig() { - int[] attribList = new int[] { - EGL_DEPTH_SIZE, 0, - EGL_STENCIL_SIZE, 0, - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_ALPHA_SIZE, 8, - EGL10.EGL_RENDERABLE_TYPE, 4, - EGL_NONE - }; - - // No error checking performed, minimum required code to elucidate logic - // Expand on this logic to be more selective in choosing a configuration - int[] numConfig = new int[1]; - mEGL.eglChooseConfig(mEGLDisplay, attribList, null, 0, numConfig); - int configSize = numConfig[0]; - mEGLConfigs = new EGLConfig[configSize]; - mEGL.eglChooseConfig(mEGLDisplay, attribList, mEGLConfigs, configSize, numConfig); - - if (LIST_CONFIGS) { - listConfig(); - } - - return mEGLConfigs[0]; // Best match is probably the first configuration - } - - private void listConfig() { - Log.i(TAG, "Config List {"); - - for (EGLConfig config : mEGLConfigs) { - int d, s, r, g, b, a; - - // Expand on this logic to dump other attributes - d = getConfigAttrib(config, EGL_DEPTH_SIZE); - s = getConfigAttrib(config, EGL_STENCIL_SIZE); - r = getConfigAttrib(config, EGL_RED_SIZE); - g = getConfigAttrib(config, EGL_GREEN_SIZE); - b = getConfigAttrib(config, EGL_BLUE_SIZE); - a = getConfigAttrib(config, EGL_ALPHA_SIZE); - Log.i(TAG, " = <" + d + "," + s + "," + - r + "," + g + "," + b + "," + a + ">"); - } - - Log.i(TAG, "}"); - } - - private int getConfigAttrib(final EGLConfig config, final int attribute) { - int[] value = new int[1]; - return mEGL.eglGetConfigAttrib(mEGLDisplay, config, - attribute, value) ? value[0] : 0; - } - - private void convertToBitmap() { - int[] iat = new int[mWidth * mHeight]; - IntBuffer ib = IntBuffer.allocate(mWidth * mHeight); - mGL.glReadPixels(0, 0, mWidth, mHeight, GL_RGBA, GL_UNSIGNED_BYTE, ib); - int[] ia = ib.array(); - - // Convert upside down mirror-reversed image to right-side up normal - // image. - for (int i = 0; i < mHeight; i++) { - for (int j = 0; j < mWidth; j++) { - iat[(mHeight - i - 1) * mWidth + j] = ia[i * mWidth + j]; - } - } - - - mBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888); - mBitmap.copyPixelsFromBuffer(IntBuffer.wrap(iat)); - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/Rotation.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/Rotation.java deleted file mode 100755 index bd2e840..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/Rotation.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage; - -public enum Rotation { - NORMAL, ROTATION_90, ROTATION_180, ROTATION_270; - - /** - * Retrieves the int representation of the Rotation. - * - * @return 0, 90, 180 or 270 - */ - public int asInt() { - switch (this) { - case NORMAL: return 0; - case ROTATION_90: return 90; - case ROTATION_180: return 180; - case ROTATION_270: return 270; - default: throw new IllegalStateException("Unknown Rotation!"); - } - } - - /** - * Create a Rotation from an integer. Needs to be either 0, 90, 180 or 270. - * - * @param rotation 0, 90, 180 or 270 - * @return Rotation object - */ - public static Rotation fromInt(int rotation) { - switch (rotation) { - case 0: return NORMAL; - case 90: return ROTATION_90; - case 180: return ROTATION_180; - case 270: return ROTATION_270; - case 360: return NORMAL; - default: throw new IllegalStateException( - rotation + " is an unknown rotation. Needs to be either 0, 90, 180 or 270!"); - } - } -} diff --git a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/util/TextureRotationUtil.java b/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/util/TextureRotationUtil.java deleted file mode 100755 index c439d91..0000000 --- a/Gpu-Image/src/jp/co/cyberagent/android/gpuimage/util/TextureRotationUtil.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2012 CyberAgent - * - * 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 jp.co.cyberagent.android.gpuimage.util; - -import jp.co.cyberagent.android.gpuimage.Rotation; - -public class TextureRotationUtil { - - public static final float TEXTURE_NO_ROTATION[] = { - 0.0f, 1.0f, - 1.0f, 1.0f, - 0.0f, 0.0f, - 1.0f, 0.0f, - }; - - public static final float TEXTURE_ROTATED_90[] = { - 1.0f, 1.0f, - 1.0f, 0.0f, - 0.0f, 1.0f, - 0.0f, 0.0f, - }; - public static final float TEXTURE_ROTATED_180[] = { - 1.0f, 0.0f, - 0.0f, 0.0f, - 1.0f, 1.0f, - 0.0f, 1.0f, - }; - public static final float TEXTURE_ROTATED_270[] = { - 0.0f, 0.0f, - 0.0f, 1.0f, - 1.0f, 0.0f, - 1.0f, 1.0f, - }; - - private TextureRotationUtil() { - } - - public static float[] getRotation(final Rotation rotation, final boolean flipHorizontal, - final boolean flipVertical) { - float[] rotatedTex; - switch (rotation) { - case ROTATION_90: - rotatedTex = TEXTURE_ROTATED_90; - break; - case ROTATION_180: - rotatedTex = TEXTURE_ROTATED_180; - break; - case ROTATION_270: - rotatedTex = TEXTURE_ROTATED_270; - break; - case NORMAL: - default: - rotatedTex = TEXTURE_NO_ROTATION; - break; - } - if (flipHorizontal) { - rotatedTex = new float[]{ - flip(rotatedTex[0]), rotatedTex[1], - flip(rotatedTex[2]), rotatedTex[3], - flip(rotatedTex[4]), rotatedTex[5], - flip(rotatedTex[6]), rotatedTex[7], - }; - } - if (flipVertical) { - rotatedTex = new float[]{ - rotatedTex[0], flip(rotatedTex[1]), - rotatedTex[2], flip(rotatedTex[3]), - rotatedTex[4], flip(rotatedTex[5]), - rotatedTex[6], flip(rotatedTex[7]), - }; - } - return rotatedTex; - } - - - private static float flip(final float i) { - if (i == 0.0f) { - return 1.0f; - } - return 0.0f; - } -} diff --git a/app/build.gradle b/app/build.gradle index b8636b6..3f5d0f3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -52,6 +52,6 @@ dependencies { implementation 'com.alibaba:fastjson:1.2.83' implementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.5' implementation 'org.greenrobot:eventbus:3.3.1' - implementation project(':Gpu-Image') + implementation 'jp.co.cyberagent.android:gpuimage:2.1.0' implementation project(':ImageViewTouch') } diff --git a/app/src/main/java/com/common/util/AppUtils.java b/app/src/main/java/com/common/util/AppUtils.java deleted file mode 100644 index 89a1d4d..0000000 --- a/app/src/main/java/com/common/util/AppUtils.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.common.util; - -import java.util.List; - -import android.app.ActivityManager; -import android.app.ActivityManager.RunningAppProcessInfo; -import android.app.ActivityManager.RunningTaskInfo; -import android.content.ComponentName; -import android.content.Context; - -/** - * AppUtils - *
      - *
    • {@link AppUtils#isNamedProcess(Context, String)}
    • - *
    - * - * @author
    Trinea 2014-5-07 - */ -public class AppUtils { - - private AppUtils() { - throw new AssertionError(); - } - - /** - * whether this process is named with processName - * - * @param context - * @param processName - * @return
      - * return whether this process is named with processName - *
    • if context is null, return false
    • - *
    • if {@link ActivityManager#getRunningAppProcesses()} is null, return false
    • - *
    • if one process of {@link ActivityManager#getRunningAppProcesses()} is equal to processName, return - * true, otherwise return false
    • - *
    - */ - public static boolean isNamedProcess(Context context, String processName) { - if (context == null) { - return false; - } - - int pid = android.os.Process.myPid(); - ActivityManager manager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE); - List processInfoList = manager.getRunningAppProcesses(); - if (ListUtils.isEmpty(processInfoList)) { - return false; - } - - for (RunningAppProcessInfo processInfo : processInfoList) { - if (processInfo != null && processInfo.pid == pid - && ObjectUtils.isEquals(processName, processInfo.processName)) { - return true; - } - } - return false; - } - - /** - * whether application is in background - *
      - *
    • need use permission android.permission.GET_TASKS in Manifest.xml
    • - *
    - * - * @param context - * @return if application is in background return true, otherwise return false - */ - public static boolean isApplicationInBackground(Context context) { - ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE); - List taskList = am.getRunningTasks(1); - if (taskList != null && !taskList.isEmpty()) { - ComponentName topActivity = taskList.get(0).topActivity; - if (topActivity != null && !topActivity.getPackageName().equals(context.getPackageName())) { - return true; - } - } - return false; - } -} diff --git a/app/src/main/java/com/common/util/ArrayUtils.java b/app/src/main/java/com/common/util/ArrayUtils.java deleted file mode 100644 index 1c59371..0000000 --- a/app/src/main/java/com/common/util/ArrayUtils.java +++ /dev/null @@ -1,179 +0,0 @@ -package com.common.util; - -/** - * Array Utils - *
      - *
    • {@link #isEmpty(Object[])} is null or its length is 0
    • - *
    • {@link #getLast(Object[], Object, Object, boolean)} get last element of the target element, before the first one - * that match the target element front to back
    • - *
    • {@link #getNext(Object[], Object, Object, boolean)} get next element of the target element, after the first one - * that match the target element front to back
    • - *
    • {@link #getLast(Object[], Object, boolean)}
    • - *
    • {@link #getLast(int[], int, int, boolean)}
    • - *
    • {@link #getLast(long[], long, long, boolean)}
    • - *
    • {@link #getNext(Object[], Object, boolean)}
    • - *
    • {@link #getNext(int[], int, int, boolean)}
    • - *
    • {@link #getNext(long[], long, long, boolean)}
    • - *
    - * - * @author Trinea 2011-10-24 - */ -public class ArrayUtils { - - private ArrayUtils() { - throw new AssertionError(); - } - - /** - * is null or its length is 0 - * - * @param - * @param sourceArray - * @return - */ - public static boolean isEmpty(V[] sourceArray) { - return (sourceArray == null || sourceArray.length == 0); - } - - /** - * get last element of the target element, before the first one that match the target element front to back - *
      - *
    • if array is empty, return defaultValue
    • - *
    • if target element is not exist in array, return defaultValue
    • - *
    • if target element exist in array and its index is not 0, return the last element
    • - *
    • if target element exist in array and its index is 0, return the last one in array if isCircle is true, else - * return defaultValue
    • - *
    - * - * @param - * @param sourceArray - * @param value value of target element - * @param defaultValue default return value - * @param isCircle whether is circle - * @return - */ - public static V getLast(V[] sourceArray, V value, V defaultValue, boolean isCircle) { - if (isEmpty(sourceArray)) { - return defaultValue; - } - - int currentPosition = -1; - for (int i = 0; i < sourceArray.length; i++) { - if (ObjectUtils.isEquals(value, sourceArray[i])) { - currentPosition = i; - break; - } - } - if (currentPosition == -1) { - return defaultValue; - } - - if (currentPosition == 0) { - return isCircle ? sourceArray[sourceArray.length - 1] : defaultValue; - } - return sourceArray[currentPosition - 1]; - } - - /** - * get next element of the target element, after the first one that match the target element front to back - *
      - *
    • if array is empty, return defaultValue
    • - *
    • if target element is not exist in array, return defaultValue
    • - *
    • if target element exist in array and not the last one in array, return the next element
    • - *
    • if target element exist in array and the last one in array, return the first one in array if isCircle is - * true, else return defaultValue
    • - *
    - * - * @param - * @param sourceArray - * @param value value of target element - * @param defaultValue default return value - * @param isCircle whether is circle - * @return - */ - public static V getNext(V[] sourceArray, V value, V defaultValue, boolean isCircle) { - if (isEmpty(sourceArray)) { - return defaultValue; - } - - int currentPosition = -1; - for (int i = 0; i < sourceArray.length; i++) { - if (ObjectUtils.isEquals(value, sourceArray[i])) { - currentPosition = i; - break; - } - } - if (currentPosition == -1) { - return defaultValue; - } - - if (currentPosition == sourceArray.length - 1) { - return isCircle ? sourceArray[0] : defaultValue; - } - return sourceArray[currentPosition + 1]; - } - - /** - * @see {@link ArrayUtils#getLast(Object[], Object, Object, boolean)} defaultValue is null - */ - public static V getLast(V[] sourceArray, V value, boolean isCircle) { - return getLast(sourceArray, value, null, isCircle); - } - - /** - * @see {@link ArrayUtils#getNext(Object[], Object, Object, boolean)} defaultValue is null - */ - public static V getNext(V[] sourceArray, V value, boolean isCircle) { - return getNext(sourceArray, value, null, isCircle); - } - - /** - * @see {@link ArrayUtils#getLast(Object[], Object, Object, boolean)} Object is Long - */ - public static long getLast(long[] sourceArray, long value, long defaultValue, boolean isCircle) { - if (sourceArray.length == 0) { - throw new IllegalArgumentException("The length of source array must be greater than 0."); - } - - Long[] array = ObjectUtils.transformLongArray(sourceArray); - return getLast(array, value, defaultValue, isCircle); - - } - - /** - * @see {@link ArrayUtils#getNext(Object[], Object, Object, boolean)} Object is Long - */ - public static long getNext(long[] sourceArray, long value, long defaultValue, boolean isCircle) { - if (sourceArray.length == 0) { - throw new IllegalArgumentException("The length of source array must be greater than 0."); - } - - Long[] array = ObjectUtils.transformLongArray(sourceArray); - return getNext(array, value, defaultValue, isCircle); - } - - /** - * @see {@link ArrayUtils#getLast(Object[], Object, Object, boolean)} Object is Integer - */ - public static int getLast(int[] sourceArray, int value, int defaultValue, boolean isCircle) { - if (sourceArray.length == 0) { - throw new IllegalArgumentException("The length of source array must be greater than 0."); - } - - Integer[] array = ObjectUtils.transformIntArray(sourceArray); - return getLast(array, value, defaultValue, isCircle); - - } - - /** - * @see {@link ArrayUtils#getNext(Object[], Object, Object, boolean)} Object is Integer - */ - public static int getNext(int[] sourceArray, int value, int defaultValue, boolean isCircle) { - if (sourceArray.length == 0) { - throw new IllegalArgumentException("The length of source array must be greater than 0."); - } - - Integer[] array = ObjectUtils.transformIntArray(sourceArray); - return getNext(array, value, defaultValue, isCircle); - } -} diff --git a/app/src/main/java/com/common/util/CollectionUtils.java b/app/src/main/java/com/common/util/CollectionUtils.java deleted file mode 100644 index 06b7e33..0000000 --- a/app/src/main/java/com/common/util/CollectionUtils.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.common.util; - -import java.util.Collection; - -import android.text.TextUtils; - -/** - * CollectionUtils - * - * @author Trinea 2012-7-22 - */ -public class CollectionUtils { - - /** default join separator **/ - public static final CharSequence DEFAULT_JOIN_SEPARATOR = ","; - - private CollectionUtils() { - throw new AssertionError(); - } - - /** - * is null or its size is 0 - * - *
    -     * isEmpty(null)   =   true;
    -     * isEmpty({})     =   true;
    -     * isEmpty({1})    =   false;
    -     * 
    - * - * @param - * @param c - * @return if collection is null or its size is 0, return true, else return false. - */ - public static boolean isEmpty(Collection c) { - return (c == null || c.size() == 0); - } - - /** - * join collection to string, separator is {@link #DEFAULT_JOIN_SEPARATOR} - * - *
    -     * join(null)      =   "";
    -     * join({})        =   "";
    -     * join({a,b})     =   "a,b";
    -     * 
    - * - * @param collection - * @return join collection to string, separator is {@link #DEFAULT_JOIN_SEPARATOR}. if collection is empty, return - * "" - */ - public static String join(Iterable collection) { - return collection == null ? "" : TextUtils.join(DEFAULT_JOIN_SEPARATOR, collection); - } -} diff --git a/app/src/main/java/com/common/util/ListUtils.java b/app/src/main/java/com/common/util/ListUtils.java deleted file mode 100644 index 18f3eef..0000000 --- a/app/src/main/java/com/common/util/ListUtils.java +++ /dev/null @@ -1,253 +0,0 @@ -package com.common.util; - -import java.util.ArrayList; -import java.util.List; - -import android.text.TextUtils; - -/** - * List Utils - * - * @author Trinea 2011-7-22 - */ -public class ListUtils { - - /** default join separator **/ - public static final String DEFAULT_JOIN_SEPARATOR = ","; - - private ListUtils() { - throw new AssertionError(); - } - - /** - * get size of list - * - *
    -     * getSize(null)   =   0;
    -     * getSize({})     =   0;
    -     * getSize({1})    =   1;
    -     * 
    - * - * @param - * @param sourceList - * @return if list is null or empty, return 0, else return {@link List#size()}. - */ - public static int getSize(List sourceList) { - return sourceList == null ? 0 : sourceList.size(); - } - - /** - * is null or its size is 0 - * - *
    -     * isEmpty(null)   =   true;
    -     * isEmpty({})     =   true;
    -     * isEmpty({1})    =   false;
    -     * 
    - * - * @param - * @param sourceList - * @return if list is null or its size is 0, return true, else return false. - */ - public static boolean isEmpty(List sourceList) { - return (sourceList == null || sourceList.size() == 0); - } - - /** - * compare two list - * - *
    -     * isEquals(null, null) = true;
    -     * isEquals(new ArrayList<String>(), null) = false;
    -     * isEquals(null, new ArrayList<String>()) = false;
    -     * isEquals(new ArrayList<String>(), new ArrayList<String>()) = true;
    -     * 
    - * - * @param - * @param actual - * @param expected - * @return - */ - public static boolean isEquals(ArrayList actual, ArrayList expected) { - if (actual == null) { - return expected == null; - } - if (expected == null) { - return false; - } - if (actual.size() != expected.size()) { - return false; - } - - for (int i = 0; i < actual.size(); i++) { - if (!ObjectUtils.isEquals(actual.get(i), expected.get(i))) { - return false; - } - } - return true; - } - - /** - * join list to string, separator is "," - * - *
    -     * join(null)      =   "";
    -     * join({})        =   "";
    -     * join({a,b})     =   "a,b";
    -     * 
    - * - * @param list - * @return join list to string, separator is ",". if list is empty, return "" - */ - public static String join(List list) { - return join(list, DEFAULT_JOIN_SEPARATOR); - } - - /** - * join list to string - * - *
    -     * join(null, '#')     =   "";
    -     * join({}, '#')       =   "";
    -     * join({a,b,c}, ' ')  =   "abc";
    -     * join({a,b,c}, '#')  =   "a#b#c";
    -     * 
    - * - * @param list - * @param separator - * @return join list to string. if list is empty, return "" - */ - public static String join(List list, char separator) { - return join(list, new String(new char[] {separator})); - } - - /** - * join list to string. if separator is null, use {@link #DEFAULT_JOIN_SEPARATOR} - * - *
    -     * join(null, "#")     =   "";
    -     * join({}, "#$")      =   "";
    -     * join({a,b,c}, null) =   "a,b,c";
    -     * join({a,b,c}, "")   =   "abc";
    -     * join({a,b,c}, "#")  =   "a#b#c";
    -     * join({a,b,c}, "#$") =   "a#$b#$c";
    -     * 
    - * - * @param list - * @param separator - * @return join list to string with separator. if list is empty, return "" - */ - public static String join(List list, String separator) { - return list == null ? "" : TextUtils.join(separator, list); - } - - /** - * add distinct entry to list - * - * @param - * @param sourceList - * @param entry - * @return if entry already exist in sourceList, return false, else add it and return true. - */ - public static boolean addDistinctEntry(List sourceList, V entry) { - return (sourceList != null && !sourceList.contains(entry)) ? sourceList.add(entry) : false; - } - - /** - * add all distinct entry to list1 from list2 - * - * @param - * @param sourceList - * @param entryList - * @return the count of entries be added - */ - public static int addDistinctList(List sourceList, List entryList) { - if (sourceList == null || isEmpty(entryList)) { - return 0; - } - - int sourceCount = sourceList.size(); - for (V entry : entryList) { - if (!sourceList.contains(entry)) { - sourceList.add(entry); - } - } - return sourceList.size() - sourceCount; - } - - /** - * remove duplicate entries in list - * - * @param - * @param sourceList - * @return the count of entries be removed - */ - public static int distinctList(List sourceList) { - if (isEmpty(sourceList)) { - return 0; - } - - int sourceCount = sourceList.size(); - int sourceListSize = sourceList.size(); - for (int i = 0; i < sourceListSize; i++) { - for (int j = (i + 1); j < sourceListSize; j++) { - if (sourceList.get(i).equals(sourceList.get(j))) { - sourceList.remove(j); - sourceListSize = sourceList.size(); - j--; - } - } - } - return sourceCount - sourceList.size(); - } - - /** - * add not null entry to list - * - * @param sourceList - * @param value - * @return
      - *
    • if sourceList is null, return false
    • - *
    • if value is null, return false
    • - *
    • return {@link List#add(Object)}
    • - *
    - */ - public static boolean addListNotNullValue(List sourceList, V value) { - return (sourceList != null && value != null) ? sourceList.add(value) : false; - } - - /** - * @see {@link ArrayUtils#getLast(Object[], Object, Object, boolean)} defaultValue is null, isCircle is true - */ - @SuppressWarnings("unchecked") - public static V getLast(List sourceList, V value) { - return (sourceList == null) ? null : (V)ArrayUtils.getLast(sourceList.toArray(), value, true); - } - - /** - * @see {@link ArrayUtils#getNext(Object[], Object, Object, boolean)} defaultValue is null, isCircle is true - */ - @SuppressWarnings("unchecked") - public static V getNext(List sourceList, V value) { - return (sourceList == null) ? null : (V)ArrayUtils.getNext(sourceList.toArray(), value, true); - } - - /** - * invert list - * - * @param - * @param sourceList - * @return - */ - public static List invertList(List sourceList) { - if (isEmpty(sourceList)) { - return sourceList; - } - - List invertList = new ArrayList(sourceList.size()); - for (int i = sourceList.size() - 1; i >= 0; i--) { - invertList.add(sourceList.get(i)); - } - return invertList; - } -} diff --git a/app/src/main/java/com/common/util/MapUtils.java b/app/src/main/java/com/common/util/MapUtils.java deleted file mode 100644 index b8866c5..0000000 --- a/app/src/main/java/com/common/util/MapUtils.java +++ /dev/null @@ -1,289 +0,0 @@ -package com.common.util; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; - -/** - * Map Utils - * - * @author Trinea 2011-7-22 - */ -public class MapUtils { - - /** default separator between key and value **/ - public static final String DEFAULT_KEY_AND_VALUE_SEPARATOR = ":"; - /** default separator between key-value pairs **/ - public static final String DEFAULT_KEY_AND_VALUE_PAIR_SEPARATOR = ","; - - private MapUtils() { - throw new AssertionError(); - } - /** - * is null or its size is 0 - * - *
    -     * isEmpty(null)   =   true;
    -     * isEmpty({})     =   true;
    -     * isEmpty({1, 2})    =   false;
    -     * 
    - * - * @param sourceMap - * @return if map is null or its size is 0, return true, else return false. - */ - public static boolean isEmpty(Map sourceMap) { - return (sourceMap == null || sourceMap.size() == 0); - } - - /** - * add key-value pair to map, and key need not null or empty - * - * @param map - * @param key - * @param value - * @return
      - *
    • if map is null, return false
    • - *
    • if key is null or empty, return false
    • - *
    • return {@link Map#put(Object, Object)}
    • - *
    - */ - public static boolean putMapNotEmptyKey(Map map, String key, String value) { - if (map == null || StringUtils.isEmpty(key)) { - return false; - } - - map.put(key, value); - return true; - } - - /** - * add key-value pair to map, both key and value need not null or empty - * - * @param map - * @param key - * @param value - * @return
      - *
    • if map is null, return false
    • - *
    • if key is null or empty, return false
    • - *
    • if value is null or empty, return false
    • - *
    • return {@link Map#put(Object, Object)}
    • - *
    - */ - public static boolean putMapNotEmptyKeyAndValue(Map map, String key, String value) { - if (map == null || StringUtils.isEmpty(key) || StringUtils.isEmpty(value)) { - return false; - } - - map.put(key, value); - return true; - } - - /** - * add key-value pair to map, key need not null or empty - * - * @param map - * @param key - * @param value - * @param defaultValue - * @return
      - *
    • if map is null, return false
    • - *
    • if key is null or empty, return false
    • - *
    • if value is null or empty, put defaultValue, return true
    • - *
    • if value is neither null nor empty,put value, return true
    • - *
    - */ - public static boolean putMapNotEmptyKeyAndValue(Map map, String key, String value, - String defaultValue) { - if (map == null || StringUtils.isEmpty(key)) { - return false; - } - - map.put(key, StringUtils.isEmpty(value) ? defaultValue : value); - return true; - } - - /** - * add key-value pair to map, key need not null - * - * @param map - * @param key - * @param value - * @return
      - *
    • if map is null, return false
    • - *
    • if key is null, return false
    • - *
    • return {@link Map#put(Object, Object)}
    • - *
    - */ - public static boolean putMapNotNullKey(Map map, K key, V value) { - if (map == null || key == null) { - return false; - } - - map.put(key, value); - return true; - } - - /** - * add key-value pair to map, both key and value need not null - * - * @param map - * @param key - * @param value - * @return
      - *
    • if map is null, return false
    • - *
    • if key is null, return false
    • - *
    • if value is null, return false
    • - *
    • return {@link Map#put(Object, Object)}
    • - *
    - */ - public static boolean putMapNotNullKeyAndValue(Map map, K key, V value) { - if (map == null || key == null || value == null) { - return false; - } - - map.put(key, value); - return true; - } - - /** - * get key by value, match the first entry front to back - *
      - * Attentions: - *
    • for HashMap, the order of entry not same to put order, so you may need to use TreeMap
    • - *
    - * - * @param - * @param map - * @param value - * @return
      - *
    • if map is null, return null
    • - *
    • if value exist, return key
    • - *
    • return null
    • - *
    - */ - public static K getKeyByValue(Map map, V value) { - if (isEmpty(map)) { - return null; - } - - for (Entry entry : map.entrySet()) { - if (ObjectUtils.isEquals(entry.getValue(), value)) { - return entry.getKey(); - } - } - return null; - } - - /** - * parse key-value pairs to map, ignore empty key - * - *
    -     * parseKeyAndValueToMap("","","",true)=null
    -     * parseKeyAndValueToMap(null,"","",true)=null
    -     * parseKeyAndValueToMap("a:b,:","","",true)={(a,b)}
    -     * parseKeyAndValueToMap("a:b,:d","","",true)={(a,b)}
    -     * parseKeyAndValueToMap("a:b,c:d","","",true)={(a,b),(c,d)}
    -     * parseKeyAndValueToMap("a=b, c = d","=",",",true)={(a,b),(c,d)}
    -     * parseKeyAndValueToMap("a=b, c = d","=",",",false)={(a, b),( c , d)}
    -     * parseKeyAndValueToMap("a=b, c=d","=", ",", false)={(a,b),( c,d)}
    -     * parseKeyAndValueToMap("a=b; c=d","=", ";", false)={(a,b),( c,d)}
    -     * parseKeyAndValueToMap("a=b, c=d", ",", ";", false)={(a=b, c=d)}
    -     * 
    - * - * @param source key-value pairs - * @param keyAndValueSeparator separator between key and value - * @param keyAndValuePairSeparator separator between key-value pairs - * @param ignoreSpace whether ignore space at the begging or end of key and value - * @return - */ - public static Map parseKeyAndValueToMap(String source, String keyAndValueSeparator, - String keyAndValuePairSeparator, boolean ignoreSpace) { - if (StringUtils.isEmpty(source)) { - return null; - } - - if (StringUtils.isEmpty(keyAndValueSeparator)) { - keyAndValueSeparator = DEFAULT_KEY_AND_VALUE_SEPARATOR; - } - if (StringUtils.isEmpty(keyAndValuePairSeparator)) { - keyAndValuePairSeparator = DEFAULT_KEY_AND_VALUE_PAIR_SEPARATOR; - } - Map keyAndValueMap = new HashMap(); - String[] keyAndValueArray = source.split(keyAndValuePairSeparator); - if (keyAndValueArray == null) { - return null; - } - - int seperator; - for (String valueEntity : keyAndValueArray) { - if (!StringUtils.isEmpty(valueEntity)) { - seperator = valueEntity.indexOf(keyAndValueSeparator); - if (seperator != -1) { - if (ignoreSpace) { - MapUtils.putMapNotEmptyKey(keyAndValueMap, valueEntity.substring(0, seperator).trim(), - valueEntity.substring(seperator + 1).trim()); - } else { - MapUtils.putMapNotEmptyKey(keyAndValueMap, valueEntity.substring(0, seperator), - valueEntity.substring(seperator + 1)); - } - } - } - } - return keyAndValueMap; - } - - /** - * parse key-value pairs to map, ignore empty key - * - * @param source key-value pairs - * @param ignoreSpace whether ignore space at the begging or end of key and value - * @return - * @see {@link MapUtils#parseKeyAndValueToMap(String, String, String, boolean)}, keyAndValueSeparator is - * {@link #DEFAULT_KEY_AND_VALUE_SEPARATOR}, keyAndValuePairSeparator is - * {@link #DEFAULT_KEY_AND_VALUE_PAIR_SEPARATOR} - */ - public static Map parseKeyAndValueToMap(String source, boolean ignoreSpace) { - return parseKeyAndValueToMap(source, DEFAULT_KEY_AND_VALUE_SEPARATOR, DEFAULT_KEY_AND_VALUE_PAIR_SEPARATOR, - ignoreSpace); - } - - /** - * parse key-value pairs to map, ignore empty key, ignore space at the begging or end of key and value - * - * @param source key-value pairs - * @return - * @see {@link MapUtils#parseKeyAndValueToMap(String, String, String, boolean)}, keyAndValueSeparator is - * {@link #DEFAULT_KEY_AND_VALUE_SEPARATOR}, keyAndValuePairSeparator is - * {@link #DEFAULT_KEY_AND_VALUE_PAIR_SEPARATOR}, ignoreSpace is true - */ - public static Map parseKeyAndValueToMap(String source) { - return parseKeyAndValueToMap(source, DEFAULT_KEY_AND_VALUE_SEPARATOR, DEFAULT_KEY_AND_VALUE_PAIR_SEPARATOR, - true); - } - - /** - * join map - * - * @param map - * @return - */ - public static String toJson(Map map) { - if (map == null || map.size() == 0) { - return null; - } - - StringBuilder paras = new StringBuilder(); - paras.append("{"); - Iterator> ite = map.entrySet().iterator(); - while (ite.hasNext()) { - Entry entry = (Entry)ite.next(); - paras.append("\"").append(entry.getKey()).append("\":\"").append(entry.getValue()).append("\""); - if (ite.hasNext()) { - paras.append(","); - } - } - paras.append("}"); - return paras.toString(); - } -} diff --git a/app/src/main/java/com/common/util/NetWorkUtils.java b/app/src/main/java/com/common/util/NetWorkUtils.java deleted file mode 100644 index b10572f..0000000 --- a/app/src/main/java/com/common/util/NetWorkUtils.java +++ /dev/null @@ -1,118 +0,0 @@ -package com.common.util; - -import android.content.Context; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.telephony.TelephonyManager; -import android.text.TextUtils; - -/** - * NetWork Utils - *
      - * Attentions - *
    • You should add android.permission.ACCESS_NETWORK_STATE in manifest, to get network status.
    • - *
    - * - * @author Trinea 2014-11-03 - */ -public class NetWorkUtils { - - public static final String NETWORK_TYPE_WIFI = "wifi"; - public static final String NETWORK_TYPE_3G = "eg"; - public static final String NETWORK_TYPE_2G = "2g"; - public static final String NETWORK_TYPE_WAP = "wap"; - public static final String NETWORK_TYPE_UNKNOWN = "unknown"; - public static final String NETWORK_TYPE_DISCONNECT = "disconnect"; - - /** - * Get network type - * - * @param context - * @return - */ - public static int getNetworkType(Context context) { - ConnectivityManager connectivityManager = (ConnectivityManager)context - .getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo networkInfo = connectivityManager == null ? null : connectivityManager.getActiveNetworkInfo(); - return networkInfo == null ? -1 : networkInfo.getType(); - } - - /** - * Get network type name - * - * @param context - * @return - */ - public static String getNetworkTypeName(Context context) { - ConnectivityManager manager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo networkInfo; - String type = NETWORK_TYPE_DISCONNECT; - if (manager == null || (networkInfo = manager.getActiveNetworkInfo()) == null) { - return type; - }; - - if (networkInfo.isConnected()) { - String typeName = networkInfo.getTypeName(); - if ("WIFI".equalsIgnoreCase(typeName)) { - type = NETWORK_TYPE_WIFI; - } else if ("MOBILE".equalsIgnoreCase(typeName)) { - String proxyHost = android.net.Proxy.getDefaultHost(); - type = TextUtils.isEmpty(proxyHost) ? (isFastMobileNetwork(context) ? NETWORK_TYPE_3G : NETWORK_TYPE_2G) - : NETWORK_TYPE_WAP; - } else { - type = NETWORK_TYPE_UNKNOWN; - } - } - return type; - } - - /** - * Whether is fast mobile network - * - * @param context - * @return - */ - private static boolean isFastMobileNetwork(Context context) { - TelephonyManager telephonyManager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE); - if (telephonyManager == null) { - return false; - } - - switch (telephonyManager.getNetworkType()) { - case TelephonyManager.NETWORK_TYPE_1xRTT: - return false; - case TelephonyManager.NETWORK_TYPE_CDMA: - return false; - case TelephonyManager.NETWORK_TYPE_EDGE: - return false; - case TelephonyManager.NETWORK_TYPE_EVDO_0: - return true; - case TelephonyManager.NETWORK_TYPE_EVDO_A: - return true; - case TelephonyManager.NETWORK_TYPE_GPRS: - return false; - case TelephonyManager.NETWORK_TYPE_HSDPA: - return true; - case TelephonyManager.NETWORK_TYPE_HSPA: - return true; - case TelephonyManager.NETWORK_TYPE_HSUPA: - return true; - case TelephonyManager.NETWORK_TYPE_UMTS: - return true; - case TelephonyManager.NETWORK_TYPE_EHRPD: - return true; - case TelephonyManager.NETWORK_TYPE_EVDO_B: - return true; - case TelephonyManager.NETWORK_TYPE_HSPAP: - return true; - case TelephonyManager.NETWORK_TYPE_IDEN: - return false; - case TelephonyManager.NETWORK_TYPE_LTE: - return true; - case TelephonyManager.NETWORK_TYPE_UNKNOWN: - return false; - default: - return false; - } - } -} diff --git a/app/src/main/java/com/common/util/ObjectUtils.java b/app/src/main/java/com/common/util/ObjectUtils.java deleted file mode 100644 index 268a8b4..0000000 --- a/app/src/main/java/com/common/util/ObjectUtils.java +++ /dev/null @@ -1,124 +0,0 @@ -package com.common.util; - -/** - * Object Utils - * - * @author Trinea 2011-10-24 - */ -public class ObjectUtils { - - private ObjectUtils() { - throw new AssertionError(); - } - - /** - * compare two object - * - * @param actual - * @param expected - * @return
      - *
    • if both are null, return true
    • - *
    • return actual.{@link Object#equals(Object)}
    • - *
    - */ - public static boolean isEquals(Object actual, Object expected) { - return actual == expected || (actual == null ? expected == null : actual.equals(expected)); - } - - /** - * null Object to empty string - * - *
    -     * nullStrToEmpty(null) = "";
    -     * nullStrToEmpty("") = "";
    -     * nullStrToEmpty("aa") = "aa";
    -     * 
    - * - * @param str - * @return - */ - public static String nullStrToEmpty(Object str) { - return (str == null ? "" : (str instanceof String ? (String)str : str.toString())); - } - - /** - * convert long array to Long array - * - * @param source - * @return - */ - public static Long[] transformLongArray(long[] source) { - Long[] destin = new Long[source.length]; - for (int i = 0; i < source.length; i++) { - destin[i] = source[i]; - } - return destin; - } - - /** - * convert Long array to long array - * - * @param source - * @return - */ - public static long[] transformLongArray(Long[] source) { - long[] destin = new long[source.length]; - for (int i = 0; i < source.length; i++) { - destin[i] = source[i]; - } - return destin; - } - - /** - * convert int array to Integer array - * - * @param source - * @return - */ - public static Integer[] transformIntArray(int[] source) { - Integer[] destin = new Integer[source.length]; - for (int i = 0; i < source.length; i++) { - destin[i] = source[i]; - } - return destin; - } - - /** - * convert Integer array to int array - * - * @param source - * @return - */ - public static int[] transformIntArray(Integer[] source) { - int[] destin = new int[source.length]; - for (int i = 0; i < source.length; i++) { - destin[i] = source[i]; - } - return destin; - } - - /** - * compare two object - *
      - * About result - *
    • if v1 > v2, return 1
    • - *
    • if v1 = v2, return 0
    • - *
    • if v1 < v2, return -1
    • - *
    - *
      - * About rule - *
    • if v1 is null, v2 is null, then return 0
    • - *
    • if v1 is null, v2 is not null, then return -1
    • - *
    • if v1 is not null, v2 is null, then return 1
    • - *
    • return v1.{@link Comparable#compareTo(Object)}
    • - *
    - * - * @param v1 - * @param v2 - * @return - */ - @SuppressWarnings({"unchecked", "rawtypes"}) - public static int compare(V v1, V v2) { - return v1 == null ? (v2 == null ? 0 : -1) : (v2 == null ? 1 : ((Comparable)v1).compareTo(v2)); - } -} diff --git a/app/src/main/java/com/common/util/PackageUtils.java b/app/src/main/java/com/common/util/PackageUtils.java deleted file mode 100644 index 3554ab1..0000000 --- a/app/src/main/java/com/common/util/PackageUtils.java +++ /dev/null @@ -1,770 +0,0 @@ -package com.common.util; - -import java.io.File; -import java.util.List; - -import android.app.ActivityManager; -import android.app.ActivityManager.RunningTaskInfo; -import android.content.Context; -import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.net.Uri; -import android.os.Build; -import android.provider.Settings; -import android.util.Log; -import com.common.util.ShellUtils.CommandResult; - - -public class PackageUtils { - - public static final String TAG = "PackageUtils"; - - private PackageUtils() { - throw new AssertionError(); - } - - /** - * App installation location settings values, same to {@link #PackageHelper} - */ - public static final int APP_INSTALL_AUTO = 0; - public static final int APP_INSTALL_INTERNAL = 1; - public static final int APP_INSTALL_EXTERNAL = 2; - - /** - * install according conditions - *
      - *
    • if system application or rooted, see {@link #installSilent(Context, String)}
    • - *
    • else see {@link #installNormal(Context, String)}
    • - *
    - * - * @param context - * @param filePath - * @return - */ - public static final int install(Context context, String filePath) { - if (PackageUtils.isSystemApplication(context) || ShellUtils.checkRootPermission()) { - return installSilent(context, filePath); - } - return installNormal(context, filePath) ? INSTALL_SUCCEEDED : INSTALL_FAILED_INVALID_URI; - } - - /** - * install package normal by system intent - * - * @param context - * @param filePath file path of package - * @return whether apk exist - */ - public static boolean installNormal(Context context, String filePath) { - Intent i = new Intent(Intent.ACTION_VIEW); - File file = new File(filePath); - if (file == null || !file.exists() || !file.isFile() || file.length() <= 0) { - return false; - } - - i.setDataAndType(Uri.parse("file://" + filePath), "application/vnd.android.package-archive"); - i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(i); - return true; - } - - /** - * install package silent by root - *
      - * Attentions: - *
    • Don't call this on the ui thread, it may costs some times.
    • - *
    • You should add android.permission.INSTALL_PACKAGES in manifest, so no need to request root - * permission, if you are system app.
    • - *
    • Default pm install params is "-r".
    • - *
    - * - * @param context - * @param filePath file path of package - * @return {@link PackageUtils#INSTALL_SUCCEEDED} means install success, other means failed. details see - * {@link PackageUtils}.INSTALL_FAILED_*. same to {@link PackageManager}.INSTALL_* - * @see #installSilent(Context, String, String) - */ - public static int installSilent(Context context, String filePath) { - return installSilent(context, filePath, " -r " + getInstallLocationParams()); - } - - /** - * install package silent by root - *
      - * Attentions: - *
    • Don't call this on the ui thread, it may costs some times.
    • - *
    • You should add android.permission.INSTALL_PACKAGES in manifest, so no need to request root - * permission, if you are system app.
    • - *
    - * - * @param context - * @param filePath file path of package - * @param pmParams pm install params - * @return {@link PackageUtils#INSTALL_SUCCEEDED} means install success, other means failed. details see - * {@link PackageUtils}.INSTALL_FAILED_*. same to {@link PackageManager}.INSTALL_* - */ - public static int installSilent(Context context, String filePath, String pmParams) { - if (filePath == null || filePath.length() == 0) { - return INSTALL_FAILED_INVALID_URI; - } - - File file = new File(filePath); - if (file == null || file.length() <= 0 || !file.exists() || !file.isFile()) { - return INSTALL_FAILED_INVALID_URI; - } - - /** - * if context is system app, don't need root permission, but should add in mainfest - **/ - StringBuilder command = new StringBuilder().append("LD_LIBRARY_PATH=/vendor/lib:/system/lib pm install ") - .append(pmParams == null ? "" : pmParams).append(" ").append(filePath.replace(" ", "\\ ")); - CommandResult commandResult = ShellUtils.execCommand(command.toString(), !isSystemApplication(context), true); - if (commandResult.successMsg != null - && (commandResult.successMsg.contains("Success") || commandResult.successMsg.contains("success"))) { - return INSTALL_SUCCEEDED; - } - - Log.e(TAG, - new StringBuilder().append("installSilent successMsg:").append(commandResult.successMsg) - .append(", ErrorMsg:").append(commandResult.errorMsg).toString()); - if (commandResult.errorMsg == null) { - return INSTALL_FAILED_OTHER; - } - if (commandResult.errorMsg.contains("INSTALL_FAILED_ALREADY_EXISTS")) { - return INSTALL_FAILED_ALREADY_EXISTS; - } - if (commandResult.errorMsg.contains("INSTALL_FAILED_INVALID_APK")) { - return INSTALL_FAILED_INVALID_APK; - } - if (commandResult.errorMsg.contains("INSTALL_FAILED_INVALID_URI")) { - return INSTALL_FAILED_INVALID_URI; - } - if (commandResult.errorMsg.contains("INSTALL_FAILED_INSUFFICIENT_STORAGE")) { - return INSTALL_FAILED_INSUFFICIENT_STORAGE; - } - if (commandResult.errorMsg.contains("INSTALL_FAILED_DUPLICATE_PACKAGE")) { - return INSTALL_FAILED_DUPLICATE_PACKAGE; - } - if (commandResult.errorMsg.contains("INSTALL_FAILED_NO_SHARED_USER")) { - return INSTALL_FAILED_NO_SHARED_USER; - } - if (commandResult.errorMsg.contains("INSTALL_FAILED_UPDATE_INCOMPATIBLE")) { - return INSTALL_FAILED_UPDATE_INCOMPATIBLE; - } - if (commandResult.errorMsg.contains("INSTALL_FAILED_SHARED_USER_INCOMPATIBLE")) { - return INSTALL_FAILED_SHARED_USER_INCOMPATIBLE; - } - if (commandResult.errorMsg.contains("INSTALL_FAILED_MISSING_SHARED_LIBRARY")) { - return INSTALL_FAILED_MISSING_SHARED_LIBRARY; - } - if (commandResult.errorMsg.contains("INSTALL_FAILED_REPLACE_COULDNT_DELETE")) { - return INSTALL_FAILED_REPLACE_COULDNT_DELETE; - } - if (commandResult.errorMsg.contains("INSTALL_FAILED_DEXOPT")) { - return INSTALL_FAILED_DEXOPT; - } - if (commandResult.errorMsg.contains("INSTALL_FAILED_OLDER_SDK")) { - return INSTALL_FAILED_OLDER_SDK; - } - if (commandResult.errorMsg.contains("INSTALL_FAILED_CONFLICTING_PROVIDER")) { - return INSTALL_FAILED_CONFLICTING_PROVIDER; - } - if (commandResult.errorMsg.contains("INSTALL_FAILED_NEWER_SDK")) { - return INSTALL_FAILED_NEWER_SDK; - } - if (commandResult.errorMsg.contains("INSTALL_FAILED_TEST_ONLY")) { - return INSTALL_FAILED_TEST_ONLY; - } - if (commandResult.errorMsg.contains("INSTALL_FAILED_CPU_ABI_INCOMPATIBLE")) { - return INSTALL_FAILED_CPU_ABI_INCOMPATIBLE; - } - if (commandResult.errorMsg.contains("INSTALL_FAILED_MISSING_FEATURE")) { - return INSTALL_FAILED_MISSING_FEATURE; - } - if (commandResult.errorMsg.contains("INSTALL_FAILED_CONTAINER_ERROR")) { - return INSTALL_FAILED_CONTAINER_ERROR; - } - if (commandResult.errorMsg.contains("INSTALL_FAILED_INVALID_INSTALL_LOCATION")) { - return INSTALL_FAILED_INVALID_INSTALL_LOCATION; - } - if (commandResult.errorMsg.contains("INSTALL_FAILED_MEDIA_UNAVAILABLE")) { - return INSTALL_FAILED_MEDIA_UNAVAILABLE; - } - if (commandResult.errorMsg.contains("INSTALL_FAILED_VERIFICATION_TIMEOUT")) { - return INSTALL_FAILED_VERIFICATION_TIMEOUT; - } - if (commandResult.errorMsg.contains("INSTALL_FAILED_VERIFICATION_FAILURE")) { - return INSTALL_FAILED_VERIFICATION_FAILURE; - } - if (commandResult.errorMsg.contains("INSTALL_FAILED_PACKAGE_CHANGED")) { - return INSTALL_FAILED_PACKAGE_CHANGED; - } - if (commandResult.errorMsg.contains("INSTALL_FAILED_UID_CHANGED")) { - return INSTALL_FAILED_UID_CHANGED; - } - if (commandResult.errorMsg.contains("INSTALL_PARSE_FAILED_NOT_APK")) { - return INSTALL_PARSE_FAILED_NOT_APK; - } - if (commandResult.errorMsg.contains("INSTALL_PARSE_FAILED_BAD_MANIFEST")) { - return INSTALL_PARSE_FAILED_BAD_MANIFEST; - } - if (commandResult.errorMsg.contains("INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION")) { - return INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; - } - if (commandResult.errorMsg.contains("INSTALL_PARSE_FAILED_NO_CERTIFICATES")) { - return INSTALL_PARSE_FAILED_NO_CERTIFICATES; - } - if (commandResult.errorMsg.contains("INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES")) { - return INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; - } - if (commandResult.errorMsg.contains("INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING")) { - return INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING; - } - if (commandResult.errorMsg.contains("INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME")) { - return INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; - } - if (commandResult.errorMsg.contains("INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID")) { - return INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID; - } - if (commandResult.errorMsg.contains("INSTALL_PARSE_FAILED_MANIFEST_MALFORMED")) { - return INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; - } - if (commandResult.errorMsg.contains("INSTALL_PARSE_FAILED_MANIFEST_EMPTY")) { - return INSTALL_PARSE_FAILED_MANIFEST_EMPTY; - } - if (commandResult.errorMsg.contains("INSTALL_FAILED_INTERNAL_ERROR")) { - return INSTALL_FAILED_INTERNAL_ERROR; - } - return INSTALL_FAILED_OTHER; - } - - /** - * uninstall according conditions - *
      - *
    • if system application or rooted, see {@link #uninstallSilent(Context, String)}
    • - *
    • else see {@link #uninstallNormal(Context, String)}
    • - *
    - * - * @param context - * @param packageName package name of app - * @return whether package name is empty - * @return - */ - public static final int uninstall(Context context, String packageName) { - if (PackageUtils.isSystemApplication(context) || ShellUtils.checkRootPermission()) { - return uninstallSilent(context, packageName); - } - return uninstallNormal(context, packageName) ? DELETE_SUCCEEDED : DELETE_FAILED_INVALID_PACKAGE; - } - - /** - * uninstall package normal by system intent - * - * @param context - * @param packageName package name of app - * @return whether package name is empty - */ - public static boolean uninstallNormal(Context context, String packageName) { - if (packageName == null || packageName.length() == 0) { - return false; - } - - Intent i = new Intent(Intent.ACTION_DELETE, Uri.parse(new StringBuilder(32).append("package:") - .append(packageName).toString())); - i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(i); - return true; - } - - /** - * uninstall package and clear data of app silent by root - * - * @param context - * @param packageName package name of app - * @return - * @see #uninstallSilent(Context, String, boolean) - */ - public static int uninstallSilent(Context context, String packageName) { - return uninstallSilent(context, packageName, true); - } - - /** - * uninstall package silent by root - *
      - * Attentions: - *
    • Don't call this on the ui thread, it may costs some times.
    • - *
    • You should add android.permission.DELETE_PACKAGES in manifest, so no need to request root - * permission, if you are system app.
    • - *
    - * - * @param context file path of package - * @param packageName package name of app - * @param isKeepData whether keep the data and cache directories around after package removal - * @return
      - *
    • {@link #DELETE_SUCCEEDED} means uninstall success
    • - *
    • {@link #DELETE_FAILED_INTERNAL_ERROR} means internal error
    • - *
    • {@link #DELETE_FAILED_INVALID_PACKAGE} means package name error
    • - *
    • {@link #DELETE_FAILED_PERMISSION_DENIED} means permission denied
    • - */ - public static int uninstallSilent(Context context, String packageName, boolean isKeepData) { - if (packageName == null || packageName.length() == 0) { - return DELETE_FAILED_INVALID_PACKAGE; - } - - /** - * if context is system app, don't need root permission, but should add in mainfest - **/ - StringBuilder command = new StringBuilder().append("LD_LIBRARY_PATH=/vendor/lib:/system/lib pm uninstall") - .append(isKeepData ? " -k " : " ").append(packageName.replace(" ", "\\ ")); - CommandResult commandResult = ShellUtils.execCommand(command.toString(), !isSystemApplication(context), true); - if (commandResult.successMsg != null - && (commandResult.successMsg.contains("Success") || commandResult.successMsg.contains("success"))) { - return DELETE_SUCCEEDED; - } - Log.e(TAG, - new StringBuilder().append("uninstallSilent successMsg:").append(commandResult.successMsg) - .append(", ErrorMsg:").append(commandResult.errorMsg).toString()); - if (commandResult.errorMsg == null) { - return DELETE_FAILED_INTERNAL_ERROR; - } - if (commandResult.errorMsg.contains("Permission denied")) { - return DELETE_FAILED_PERMISSION_DENIED; - } - return DELETE_FAILED_INTERNAL_ERROR; - } - - /** - * whether context is system application - * - * @param context - * @return - */ - public static boolean isSystemApplication(Context context) { - if (context == null) { - return false; - } - - return isSystemApplication(context, context.getPackageName()); - } - - /** - * whether packageName is system application - * - * @param context - * @param packageName - * @return - */ - public static boolean isSystemApplication(Context context, String packageName) { - if (context == null) { - return false; - } - - return isSystemApplication(context.getPackageManager(), packageName); - } - - /** - * whether packageName is system application - * - * @param packageManager - * @param packageName - * @return
        - *
      • if packageManager is null, return false
      • - *
      • if package name is null or is empty, return false
      • - *
      • if package name not exit, return false
      • - *
      • if package name exit, but not system app, return false
      • - *
      • else return true
      • - *
      - */ - public static boolean isSystemApplication(PackageManager packageManager, String packageName) { - if (packageManager == null || packageName == null || packageName.length() == 0) { - return false; - } - - try { - ApplicationInfo app = packageManager.getApplicationInfo(packageName, 0); - return (app != null && (app.flags & ApplicationInfo.FLAG_SYSTEM) > 0); - } catch (NameNotFoundException e) { - e.printStackTrace(); - } - return false; - } - - /** - * whether the app whost package's name is packageName is on the top of the stack - *
        - * Attentions: - *
      • You should add android.permission.GET_TASKS in manifest
      • - *
      - * - * @param context - * @param packageName - * @return if params error or task stack is null, return null, otherwise retun whether the app is on the top of - * stack - */ - public static Boolean isTopActivity(Context context, String packageName) { - if (context == null || StringUtils.isEmpty(packageName)) { - return null; - } - - ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE); - List tasksInfo = activityManager.getRunningTasks(1); - if (ListUtils.isEmpty(tasksInfo)) { - return null; - } - try { - return packageName.equals(tasksInfo.get(0).topActivity.getPackageName()); - } catch (Exception e) { - e.printStackTrace(); - return false; - } - } - - /** - * get app version code - * - * @param context - * @return - */ - public static int getAppVersionCode(Context context) { - if (context != null) { - PackageManager pm = context.getPackageManager(); - if (pm != null) { - PackageInfo pi; - try { - pi = pm.getPackageInfo(context.getPackageName(), 0); - if (pi != null) { - return pi.versionCode; - } - } catch (NameNotFoundException e) { - e.printStackTrace(); - } - } - } - return -1; - } - - /** - * get system install location
      - * can be set by System Menu Setting->Storage->Prefered install location - * - * @return - * @see {@link IPackageManager#getInstallLocation()} - */ - public static int getInstallLocation() { - CommandResult commandResult = ShellUtils.execCommand( - "LD_LIBRARY_PATH=/vendor/lib:/system/lib pm get-install-location", false, true); - if (commandResult.result == 0 && commandResult.successMsg != null && commandResult.successMsg.length() > 0) { - try { - int location = Integer.parseInt(commandResult.successMsg.substring(0, 1)); - switch (location) { - case APP_INSTALL_INTERNAL: - return APP_INSTALL_INTERNAL; - case APP_INSTALL_EXTERNAL: - return APP_INSTALL_EXTERNAL; - } - } catch (NumberFormatException e) { - e.printStackTrace(); - Log.e(TAG, "pm get-install-location error"); - } - } - return APP_INSTALL_AUTO; - } - - /** - * get params for pm install location - * - * @return - */ - private static String getInstallLocationParams() { - int location = getInstallLocation(); - switch (location) { - case APP_INSTALL_INTERNAL: - return "-f"; - case APP_INSTALL_EXTERNAL: - return "-s"; - } - return ""; - } - - /** - * start InstalledAppDetails Activity - * - * @param context - * @param packageName - */ - public static void startInstalledAppDetails(Context context, String packageName) { - Intent intent = new Intent(); - int sdkVersion = Build.VERSION.SDK_INT; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { - intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); - intent.setData(Uri.fromParts("package", packageName, null)); - } else { - intent.setAction(Intent.ACTION_VIEW); - intent.setClassName("com.android.settings", "com.android.settings.InstalledAppDetails"); - intent.putExtra((sdkVersion == Build.VERSION_CODES.FROYO ? "pkg" - : "com.android.settings.ApplicationPkgName"), packageName); - } - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(intent); - } - - /** - * Installation return code
      - * install success. - */ - public static final int INSTALL_SUCCEEDED = 1; - /** - * Installation return code
      - * the package is already installed. - */ - public static final int INSTALL_FAILED_ALREADY_EXISTS = -1; - - /** - * Installation return code
      - * the package archive file is invalid. - */ - public static final int INSTALL_FAILED_INVALID_APK = -2; - - /** - * Installation return code
      - * the URI passed in is invalid. - */ - public static final int INSTALL_FAILED_INVALID_URI = -3; - - /** - * Installation return code
      - * the package manager service found that the device didn't have enough storage space to install the app. - */ - public static final int INSTALL_FAILED_INSUFFICIENT_STORAGE = -4; - - /** - * Installation return code
      - * a package is already installed with the same name. - */ - public static final int INSTALL_FAILED_DUPLICATE_PACKAGE = -5; - - /** - * Installation return code
      - * the requested shared user does not exist. - */ - public static final int INSTALL_FAILED_NO_SHARED_USER = -6; - - /** - * Installation return code
      - * a previously installed package of the same name has a different signature than the new package (and the old - * package's data was not removed). - */ - public static final int INSTALL_FAILED_UPDATE_INCOMPATIBLE = -7; - - /** - * Installation return code
      - * the new package is requested a shared user which is already installed on the device and does not have matching - * signature. - */ - public static final int INSTALL_FAILED_SHARED_USER_INCOMPATIBLE = -8; - - /** - * Installation return code
      - * the new package uses a shared library that is not available. - */ - public static final int INSTALL_FAILED_MISSING_SHARED_LIBRARY = -9; - - /** - * Installation return code
      - * the new package uses a shared library that is not available. - */ - public static final int INSTALL_FAILED_REPLACE_COULDNT_DELETE = -10; - - /** - * Installation return code
      - * the new package failed while optimizing and validating its dex files, either because there was not enough storage - * or the validation failed. - */ - public static final int INSTALL_FAILED_DEXOPT = -11; - - /** - * Installation return code
      - * the new package failed because the current SDK version is older than that required by the package. - */ - public static final int INSTALL_FAILED_OLDER_SDK = -12; - - /** - * Installation return code
      - * the new package failed because it contains a content provider with the same authority as a provider already - * installed in the system. - */ - public static final int INSTALL_FAILED_CONFLICTING_PROVIDER = -13; - - /** - * Installation return code
      - * the new package failed because the current SDK version is newer than that required by the package. - */ - public static final int INSTALL_FAILED_NEWER_SDK = -14; - - /** - * Installation return code
      - * the new package failed because it has specified that it is a test-only package and the caller has not supplied - * the {@link #INSTALL_ALLOW_TEST} flag. - */ - public static final int INSTALL_FAILED_TEST_ONLY = -15; - - /** - * Installation return code
      - * the package being installed contains native code, but none that is compatible with the the device's CPU_ABI. - */ - public static final int INSTALL_FAILED_CPU_ABI_INCOMPATIBLE = -16; - - /** - * Installation return code
      - * the new package uses a feature that is not available. - */ - public static final int INSTALL_FAILED_MISSING_FEATURE = -17; - - /** - * Installation return code
      - * a secure container mount point couldn't be accessed on external media. - */ - public static final int INSTALL_FAILED_CONTAINER_ERROR = -18; - - /** - * Installation return code
      - * the new package couldn't be installed in the specified install location. - */ - public static final int INSTALL_FAILED_INVALID_INSTALL_LOCATION = -19; - - /** - * Installation return code
      - * the new package couldn't be installed in the specified install location because the media is not available. - */ - public static final int INSTALL_FAILED_MEDIA_UNAVAILABLE = -20; - - /** - * Installation return code
      - * the new package couldn't be installed because the verification timed out. - */ - public static final int INSTALL_FAILED_VERIFICATION_TIMEOUT = -21; - - /** - * Installation return code
      - * the new package couldn't be installed because the verification did not succeed. - */ - public static final int INSTALL_FAILED_VERIFICATION_FAILURE = -22; - - /** - * Installation return code
      - * the package changed from what the calling program expected. - */ - public static final int INSTALL_FAILED_PACKAGE_CHANGED = -23; - - /** - * Installation return code
      - * the new package is assigned a different UID than it previously held. - */ - public static final int INSTALL_FAILED_UID_CHANGED = -24; - - /** - * Installation return code
      - * if the parser was given a path that is not a file, or does not end with the expected '.apk' extension. - */ - public static final int INSTALL_PARSE_FAILED_NOT_APK = -100; - - /** - * Installation return code
      - * if the parser was unable to retrieve the AndroidManifest.xml file. - */ - public static final int INSTALL_PARSE_FAILED_BAD_MANIFEST = -101; - - /** - * Installation return code
      - * if the parser encountered an unexpected exception. - */ - public static final int INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION = -102; - - /** - * Installation return code
      - * if the parser did not find any certificates in the .apk. - */ - public static final int INSTALL_PARSE_FAILED_NO_CERTIFICATES = -103; - - /** - * Installation return code
      - * if the parser found inconsistent certificates on the files in the .apk. - */ - public static final int INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES = -104; - - /** - * Installation return code
      - * if the parser encountered a CertificateEncodingException in one of the files in the .apk. - */ - public static final int INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING = -105; - - /** - * Installation return code
      - * if the parser encountered a bad or missing package name in the manifest. - */ - public static final int INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME = -106; - - /** - * Installation return code
      - * if the parser encountered a bad shared user id name in the manifest. - */ - public static final int INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID = -107; - - /** - * Installation return code
      - * if the parser encountered some structural problem in the manifest. - */ - public static final int INSTALL_PARSE_FAILED_MANIFEST_MALFORMED = -108; - - /** - * Installation return code
      - * if the parser did not find any actionable tags (instrumentation or application) in the manifest. - */ - public static final int INSTALL_PARSE_FAILED_MANIFEST_EMPTY = -109; - - /** - * Installation return code
      - * if the system failed to install the package because of system issues. - */ - public static final int INSTALL_FAILED_INTERNAL_ERROR = -110; - /** - * Installation return code
      - * other reason - */ - public static final int INSTALL_FAILED_OTHER = -1000000; - - /** - * Uninstall return code
      - * uninstall success. - */ - public static final int DELETE_SUCCEEDED = 1; - - /** - * Uninstall return code
      - * uninstall fail if the system failed to delete the package for an unspecified reason. - */ - public static final int DELETE_FAILED_INTERNAL_ERROR = -1; - - /** - * Uninstall return code
      - * uninstall fail if the system failed to delete the package because it is the active DevicePolicy manager. - */ - public static final int DELETE_FAILED_DEVICE_POLICY_MANAGER = -2; - - /** - * Uninstall return code
      - * uninstall fail if pcakge name is invalid - */ - public static final int DELETE_FAILED_INVALID_PACKAGE = -3; - - /** - * Uninstall return code
      - * uninstall fail if permission denied - */ - public static final int DELETE_FAILED_PERMISSION_DENIED = -4; -} diff --git a/app/src/main/java/com/common/util/PreferencesUtils.java b/app/src/main/java/com/common/util/PreferencesUtils.java deleted file mode 100644 index 71373a9..0000000 --- a/app/src/main/java/com/common/util/PreferencesUtils.java +++ /dev/null @@ -1,248 +0,0 @@ -package com.common.util; - -import android.content.Context; -import android.content.SharedPreferences; - -/** - * PreferencesUtils, easy to get or put data - *
        - * Preference Name - *
      • you can change preference name by {@link #PREFERENCE_NAME}
      • - *
      - *
        - * Put Value - *
      • put string {@link #putString(Context, String, String)}
      • - *
      • put int {@link #putInt(Context, String, int)}
      • - *
      • put long {@link #putLong(Context, String, long)}
      • - *
      • put float {@link #putFloat(Context, String, float)}
      • - *
      • put boolean {@link #putBoolean(Context, String, boolean)}
      • - *
      - *
        - * Get Value - *
      • get string {@link #getString(Context, String)}, {@link #getString(Context, String, String)}
      • - *
      • get int {@link #getInt(Context, String)}, {@link #getInt(Context, String, int)}
      • - *
      • get long {@link #getLong(Context, String)}, {@link #getLong(Context, String, long)}
      • - *
      • get float {@link #getFloat(Context, String)}, {@link #getFloat(Context, String, float)}
      • - *
      • get boolean {@link #getBoolean(Context, String)}, {@link #getBoolean(Context, String, boolean)}
      • - *
      - * - * @author Trinea 2013-3-6 - */ -public class PreferencesUtils { - - public static String PREFERENCE_NAME = "TrineaAndroidCommon"; - - private PreferencesUtils() { - throw new AssertionError(); - } - - /** - * put string preferences - * - * @param context - * @param key The name of the preference to modify - * @param value The new value for the preference - * @return True if the new values were successfully written to persistent storage. - */ - public static boolean putString(Context context, String key, String value) { - SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = settings.edit(); - editor.putString(key, value); - return editor.commit(); - } - - /** - * get string preferences - * - * @param context - * @param key The name of the preference to retrieve - * @return The preference value if it exists, or null. Throws ClassCastException if there is a preference with this - * name that is not a string - * @see #getString(Context, String, String) - */ - public static String getString(Context context, String key) { - return getString(context, key, null); - } - - /** - * get string preferences - * - * @param context - * @param key The name of the preference to retrieve - * @param defaultValue Value to return if this preference does not exist - * @return The preference value if it exists, or defValue. Throws ClassCastException if there is a preference with - * this name that is not a string - */ - public static String getString(Context context, String key, String defaultValue) { - SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); - return settings.getString(key, defaultValue); - } - - /** - * put int preferences - * - * @param context - * @param key The name of the preference to modify - * @param value The new value for the preference - * @return True if the new values were successfully written to persistent storage. - */ - public static boolean putInt(Context context, String key, int value) { - SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = settings.edit(); - editor.putInt(key, value); - return editor.commit(); - } - - /** - * get int preferences - * - * @param context - * @param key The name of the preference to retrieve - * @return The preference value if it exists, or -1. Throws ClassCastException if there is a preference with this - * name that is not a int - * @see #getInt(Context, String, int) - */ - public static int getInt(Context context, String key) { - return getInt(context, key, -1); - } - - /** - * get int preferences - * - * @param context - * @param key The name of the preference to retrieve - * @param defaultValue Value to return if this preference does not exist - * @return The preference value if it exists, or defValue. Throws ClassCastException if there is a preference with - * this name that is not a int - */ - public static int getInt(Context context, String key, int defaultValue) { - SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); - return settings.getInt(key, defaultValue); - } - - /** - * put long preferences - * - * @param context - * @param key The name of the preference to modify - * @param value The new value for the preference - * @return True if the new values were successfully written to persistent storage. - */ - public static boolean putLong(Context context, String key, long value) { - SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = settings.edit(); - editor.putLong(key, value); - return editor.commit(); - } - - /** - * get long preferences - * - * @param context - * @param key The name of the preference to retrieve - * @return The preference value if it exists, or -1. Throws ClassCastException if there is a preference with this - * name that is not a long - * @see #getLong(Context, String, long) - */ - public static long getLong(Context context, String key) { - return getLong(context, key, -1); - } - - /** - * get long preferences - * - * @param context - * @param key The name of the preference to retrieve - * @param defaultValue Value to return if this preference does not exist - * @return The preference value if it exists, or defValue. Throws ClassCastException if there is a preference with - * this name that is not a long - */ - public static long getLong(Context context, String key, long defaultValue) { - SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); - return settings.getLong(key, defaultValue); - } - - /** - * put float preferences - * - * @param context - * @param key The name of the preference to modify - * @param value The new value for the preference - * @return True if the new values were successfully written to persistent storage. - */ - public static boolean putFloat(Context context, String key, float value) { - SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = settings.edit(); - editor.putFloat(key, value); - return editor.commit(); - } - - /** - * get float preferences - * - * @param context - * @param key The name of the preference to retrieve - * @return The preference value if it exists, or -1. Throws ClassCastException if there is a preference with this - * name that is not a float - * @see #getFloat(Context, String, float) - */ - public static float getFloat(Context context, String key) { - return getFloat(context, key, -1); - } - - /** - * get float preferences - * - * @param context - * @param key The name of the preference to retrieve - * @param defaultValue Value to return if this preference does not exist - * @return The preference value if it exists, or defValue. Throws ClassCastException if there is a preference with - * this name that is not a float - */ - public static float getFloat(Context context, String key, float defaultValue) { - SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); - return settings.getFloat(key, defaultValue); - } - - /** - * put boolean preferences - * - * @param context - * @param key The name of the preference to modify - * @param value The new value for the preference - * @return True if the new values were successfully written to persistent storage. - */ - public static boolean putBoolean(Context context, String key, boolean value) { - SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = settings.edit(); - editor.putBoolean(key, value); - return editor.commit(); - } - - /** - * get boolean preferences, default is false - * - * @param context - * @param key The name of the preference to retrieve - * @return The preference value if it exists, or false. Throws ClassCastException if there is a preference with this - * name that is not a boolean - * @see #getBoolean(Context, String, boolean) - */ - public static boolean getBoolean(Context context, String key) { - return getBoolean(context, key, false); - } - - /** - * get boolean preferences - * - * @param context - * @param key The name of the preference to retrieve - * @param defaultValue Value to return if this preference does not exist - * @return The preference value if it exists, or defValue. Throws ClassCastException if there is a preference with - * this name that is not a boolean - */ - public static boolean getBoolean(Context context, String key, boolean defaultValue) { - SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE); - return settings.getBoolean(key, defaultValue); - } -} diff --git a/app/src/main/java/com/common/util/RandomUtils.java b/app/src/main/java/com/common/util/RandomUtils.java deleted file mode 100644 index 421e464..0000000 --- a/app/src/main/java/com/common/util/RandomUtils.java +++ /dev/null @@ -1,247 +0,0 @@ -package com.common.util; - -import java.util.Random; - -/** - * Random Utils - *
        - * Shuffling algorithm - *
      • {@link #shuffle(Object[])} Shuffling algorithm, Randomly permutes the specified array using a default source of - * randomness
      • - *
      • {@link #shuffle(Object[], int)} Shuffling algorithm, Randomly permutes the specified array
      • - *
      • {@link #shuffle(int[])} Shuffling algorithm, Randomly permutes the specified int array using a default source of - * randomness
      • - *
      • {@link #shuffle(int[], int)} Shuffling algorithm, Randomly permutes the specified int array
      • - *
      - *
        - * get random int - *
      • {@link #getRandom(int)} get random int between 0 and max
      • - *
      • {@link #getRandom(int, int)} get random int between min and max
      • - *
      - *
        - * get random numbers or letters - *
      • {@link #getRandomCapitalLetters(int)} get a fixed-length random string, its a mixture of uppercase letters
      • - *
      • {@link #getRandomLetters(int)} get a fixed-length random string, its a mixture of uppercase and lowercase letters - *
      • - *
      • {@link #getRandomLowerCaseLetters(int)} get a fixed-length random string, its a mixture of lowercase letters
      • - *
      • {@link #getRandomNumbers(int)} get a fixed-length random string, its a mixture of numbers
      • - *
      • {@link #getRandomNumbersAndLetters(int)} get a fixed-length random string, its a mixture of uppercase, lowercase - * letters and numbers
      • - *
      • {@link #getRandom(String, int)} get a fixed-length random string, its a mixture of chars in source
      • - *
      • {@link #getRandom(char[], int)} get a fixed-length random string, its a mixture of chars in sourceChar
      • - *
      - * - * @author Trinea 2012-5-12 - */ -public class RandomUtils { - - public static final String NUMBERS_AND_LETTERS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - public static final String NUMBERS = "0123456789"; - public static final String LETTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - public static final String CAPITAL_LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - public static final String LOWER_CASE_LETTERS = "abcdefghijklmnopqrstuvwxyz"; - - private RandomUtils() { - throw new AssertionError(); - } - - /** - * get a fixed-length random string, its a mixture of uppercase, lowercase letters and numbers - * - * @param length - * @return - * @see RandomUtils#getRandom(String source, int length) - */ - public static String getRandomNumbersAndLetters(int length) { - return getRandom(NUMBERS_AND_LETTERS, length); - } - - /** - * get a fixed-length random string, its a mixture of numbers - * - * @param length - * @return - * @see RandomUtils#getRandom(String source, int length) - */ - public static String getRandomNumbers(int length) { - return getRandom(NUMBERS, length); - } - - /** - * get a fixed-length random string, its a mixture of uppercase and lowercase letters - * - * @param length - * @return - * @see RandomUtils#getRandom(String source, int length) - */ - public static String getRandomLetters(int length) { - return getRandom(LETTERS, length); - } - - /** - * get a fixed-length random string, its a mixture of uppercase letters - * - * @param length - * @return - * @see RandomUtils#getRandom(String source, int length) - */ - public static String getRandomCapitalLetters(int length) { - return getRandom(CAPITAL_LETTERS, length); - } - - /** - * get a fixed-length random string, its a mixture of lowercase letters - * - * @param length - * @return - * @see RandomUtils#getRandom(String source, int length) - */ - public static String getRandomLowerCaseLetters(int length) { - return getRandom(LOWER_CASE_LETTERS, length); - } - - /** - * get a fixed-length random string, its a mixture of chars in source - * - * @param source - * @param length - * @return
        - *
      • if source is null or empty, return null
      • - *
      • else see {@link RandomUtils#getRandom(char[] sourceChar, int length)}
      • - *
      - */ - public static String getRandom(String source, int length) { - return StringUtils.isEmpty(source) ? null : getRandom(source.toCharArray(), length); - } - - /** - * get a fixed-length random string, its a mixture of chars in sourceChar - * - * @param sourceChar - * @param length - * @return
        - *
      • if sourceChar is null or empty, return null
      • - *
      • if length less than 0, return null
      • - *
      - */ - public static String getRandom(char[] sourceChar, int length) { - if (sourceChar == null || sourceChar.length == 0 || length < 0) { - return null; - } - - StringBuilder str = new StringBuilder(length); - Random random = new Random(); - for (int i = 0; i < length; i++) { - str.append(sourceChar[random.nextInt(sourceChar.length)]); - } - return str.toString(); - } - - /** - * get random int between 0 and max - * - * @param max - * @return
        - *
      • if max <= 0, return 0
      • - *
      • else return random int between 0 and max
      • - *
      - */ - public static int getRandom(int max) { - return getRandom(0, max); - } - - /** - * get random int between min and max - * - * @param min - * @param max - * @return
        - *
      • if min > max, return 0
      • - *
      • if min == max, return min
      • - *
      • else return random int between min and max
      • - *
      - */ - public static int getRandom(int min, int max) { - if (min > max) { - return 0; - } - if (min == max) { - return min; - } - return min + new Random().nextInt(max - min); - } - - /** - * Shuffling algorithm, Randomly permutes the specified array using a default source of randomness - * - * @param objArray - * @return - */ - public static boolean shuffle(Object[] objArray) { - if (objArray == null) { - return false; - } - - return shuffle(objArray, getRandom(objArray.length)); - } - - /** - * Shuffling algorithm, Randomly permutes the specified array - * - * @param objArray - * @param shuffleCount - * @return - */ - public static boolean shuffle(Object[] objArray, int shuffleCount) { - int length; - if (objArray == null || shuffleCount < 0 || (length = objArray.length) < shuffleCount) { - return false; - } - - for (int i = 1; i <= shuffleCount; i++) { - int random = getRandom(length - i); - Object temp = objArray[length - i]; - objArray[length - i] = objArray[random]; - objArray[random] = temp; - } - return true; - } - - /** - * Shuffling algorithm, Randomly permutes the specified int array using a default source of randomness - * - * @param intArray - * @return - */ - public static int[] shuffle(int[] intArray) { - if (intArray == null) { - return null; - } - - return shuffle(intArray, getRandom(intArray.length)); - } - - /** - * Shuffling algorithm, Randomly permutes the specified int array - * - * @param intArray - * @param shuffleCount - * @return - */ - public static int[] shuffle(int[] intArray, int shuffleCount) { - int length; - if (intArray == null || shuffleCount < 0 || (length = intArray.length) < shuffleCount) { - return null; - } - - int[] out = new int[shuffleCount]; - for (int i = 1; i <= shuffleCount; i++) { - int random = getRandom(length - i); - out[i - 1] = intArray[random]; - int temp = intArray[length - i]; - intArray[length - i] = intArray[random]; - intArray[random] = temp; - } - return out; - } -} diff --git a/app/src/main/java/com/common/util/ResourceUtils.java b/app/src/main/java/com/common/util/ResourceUtils.java deleted file mode 100644 index 0cd348f..0000000 --- a/app/src/main/java/com/common/util/ResourceUtils.java +++ /dev/null @@ -1,135 +0,0 @@ -package com.common.util; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.List; - -import android.content.Context; - -/** - * ResourceUtils - * - * @author Trinea 2012-5-26 - */ -public class ResourceUtils { - - private ResourceUtils() { - throw new AssertionError(); - } - - /** - * get an asset using ACCESS_STREAMING mode. This provides access to files that have been bundled with an - * application as assets -- that is, files placed in to the "assets" directory. - * - * @param context - * @param fileName The name of the asset to open. This name can be hierarchical. - * @return - */ - public static String geFileFromAssets(Context context, String fileName) { - if (context == null || StringUtils.isEmpty(fileName)) { - return null; - } - - StringBuilder s = new StringBuilder(""); - try { - InputStreamReader in = new InputStreamReader(context.getResources().getAssets().open(fileName)); - BufferedReader br = new BufferedReader(in); - String line; - while ((line = br.readLine()) != null) { - s.append(line); - } - return s.toString(); - } catch (IOException e) { - e.printStackTrace(); - return null; - } - } - - /** - * get content from a raw resource. This can only be used with resources whose value is the name of an asset files - * -- that is, it can be used to open drawable, sound, and raw resources; it will fail on string and color - * resources. - * - * @param context - * @param resId The resource identifier to open, as generated by the appt tool. - * @return - */ - public static String geFileFromRaw(Context context, int resId) { - if (context == null) { - return null; - } - - StringBuilder s = new StringBuilder(); - try { - InputStreamReader in = new InputStreamReader(context.getResources().openRawResource(resId)); - BufferedReader br = new BufferedReader(in); - String line; - while ((line = br.readLine()) != null) { - s.append(line); - } - return s.toString(); - } catch (IOException e) { - e.printStackTrace(); - return null; - } - } - - /** - * same to {@link ResourceUtils#geFileFromAssets(Context, String)}, but return type is List - * - * @param context - * @param fileName - * @return - */ - public static List geFileToListFromAssets(Context context, String fileName) { - if (context == null || StringUtils.isEmpty(fileName)) { - return null; - } - - List fileContent = new ArrayList(); - try { - InputStreamReader in = new InputStreamReader(context.getResources().getAssets().open(fileName)); - BufferedReader br = new BufferedReader(in); - String line; - while ((line = br.readLine()) != null) { - fileContent.add(line); - } - br.close(); - return fileContent; - } catch (IOException e) { - e.printStackTrace(); - return null; - } - } - - /** - * same to {@link ResourceUtils#geFileFromRaw(Context, int)}, but return type is List - * - * @param context - * @param resId - * @return - */ - public static List geFileToListFromRaw(Context context, int resId) { - if (context == null) { - return null; - } - - List fileContent = new ArrayList(); - BufferedReader reader = null; - try { - InputStreamReader in = new InputStreamReader(context.getResources().openRawResource(resId)); - reader = new BufferedReader(in); - String line = null; - while ((line = reader.readLine()) != null) { - fileContent.add(line); - } - reader.close(); - return fileContent; - } catch (IOException e) { - e.printStackTrace(); - return null; - } - } -} diff --git a/app/src/main/java/com/common/util/ShellUtils.java b/app/src/main/java/com/common/util/ShellUtils.java deleted file mode 100644 index ec5fd9c..0000000 --- a/app/src/main/java/com/common/util/ShellUtils.java +++ /dev/null @@ -1,222 +0,0 @@ -package com.common.util; - -import java.io.BufferedReader; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.List; - -/** - * ShellUtils - *
        - * Check root - *
      • {@link ShellUtils#checkRootPermission()}
      • - *
      - *
        - * Execte command - *
      • {@link ShellUtils#execCommand(String, boolean)}
      • - *
      • {@link ShellUtils#execCommand(String, boolean, boolean)}
      • - *
      • {@link ShellUtils#execCommand(List, boolean)}
      • - *
      • {@link ShellUtils#execCommand(List, boolean, boolean)}
      • - *
      • {@link ShellUtils#execCommand(String[], boolean)}
      • - *
      • {@link ShellUtils#execCommand(String[], boolean, boolean)}
      • - *
      - * - * @author Trinea 2013-5-16 - */ -public class ShellUtils { - - public static final String COMMAND_SU = "su"; - public static final String COMMAND_SH = "sh"; - public static final String COMMAND_EXIT = "exit\n"; - public static final String COMMAND_LINE_END = "\n"; - - private ShellUtils() { - throw new AssertionError(); - } - - /** - * check whether has root permission - * - * @return - */ - public static boolean checkRootPermission() { - return execCommand("echo root", true, false).result == 0; - } - - /** - * execute shell command, default return result msg - * - * @param command command - * @param isRoot whether need to run with root - * @return - * @see ShellUtils#execCommand(String[], boolean, boolean) - */ - public static CommandResult execCommand(String command, boolean isRoot) { - return execCommand(new String[] {command}, isRoot, true); - } - - /** - * execute shell commands, default return result msg - * - * @param commands command list - * @param isRoot whether need to run with root - * @return - * @see ShellUtils#execCommand(String[], boolean, boolean) - */ - public static CommandResult execCommand(List commands, boolean isRoot) { - return execCommand(commands == null ? null : commands.toArray(new String[] {}), isRoot, true); - } - - /** - * execute shell commands, default return result msg - * - * @param commands command array - * @param isRoot whether need to run with root - * @return - * @see ShellUtils#execCommand(String[], boolean, boolean) - */ - public static CommandResult execCommand(String[] commands, boolean isRoot) { - return execCommand(commands, isRoot, true); - } - - /** - * execute shell command - * - * @param command command - * @param isRoot whether need to run with root - * @param isNeedResultMsg whether need result msg - * @return - * @see ShellUtils#execCommand(String[], boolean, boolean) - */ - public static CommandResult execCommand(String command, boolean isRoot, boolean isNeedResultMsg) { - return execCommand(new String[] {command}, isRoot, isNeedResultMsg); - } - - /** - * execute shell commands - * - * @param commands command list - * @param isRoot whether need to run with root - * @param isNeedResultMsg whether need result msg - * @return - * @see ShellUtils#execCommand(String[], boolean, boolean) - */ - public static CommandResult execCommand(List commands, boolean isRoot, boolean isNeedResultMsg) { - return execCommand(commands == null ? null : commands.toArray(new String[] {}), isRoot, isNeedResultMsg); - } - - /** - * execute shell commands - * - * @param commands command array - * @param isRoot whether need to run with root - * @param isNeedResultMsg whether need result msg - * @return
        - *
      • if isNeedResultMsg is false, {@link CommandResult#successMsg} is null and - * {@link CommandResult#errorMsg} is null.
      • - *
      • if {@link CommandResult#result} is -1, there maybe some excepiton.
      • - *
      - */ - public static CommandResult execCommand(String[] commands, boolean isRoot, boolean isNeedResultMsg) { - int result = -1; - if (commands == null || commands.length == 0) { - return new CommandResult(result, null, null); - } - - Process process = null; - BufferedReader successResult = null; - BufferedReader errorResult = null; - StringBuilder successMsg = null; - StringBuilder errorMsg = null; - - DataOutputStream os = null; - try { - process = Runtime.getRuntime().exec(isRoot ? COMMAND_SU : COMMAND_SH); - os = new DataOutputStream(process.getOutputStream()); - for (String command : commands) { - if (command == null) { - continue; - } - - // donnot use os.writeBytes(commmand), avoid chinese charset error - os.write(command.getBytes()); - os.writeBytes(COMMAND_LINE_END); - os.flush(); - } - os.writeBytes(COMMAND_EXIT); - os.flush(); - - result = process.waitFor(); - // get command result - if (isNeedResultMsg) { - successMsg = new StringBuilder(); - errorMsg = new StringBuilder(); - successResult = new BufferedReader(new InputStreamReader(process.getInputStream())); - errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream())); - String s; - while ((s = successResult.readLine()) != null) { - successMsg.append(s); - } - while ((s = errorResult.readLine()) != null) { - errorMsg.append(s); - } - } - } catch (IOException e) { - e.printStackTrace(); - } catch (Exception e) { - e.printStackTrace(); - } finally { - try { - if (os != null) { - os.close(); - } - if (successResult != null) { - successResult.close(); - } - if (errorResult != null) { - errorResult.close(); - } - } catch (IOException e) { - e.printStackTrace(); - } - - if (process != null) { - process.destroy(); - } - } - return new CommandResult(result, successMsg == null ? null : successMsg.toString(), errorMsg == null ? null - : errorMsg.toString()); - } - - /** - * result of command - *
        - *
      • {@link CommandResult#result} means result of command, 0 means normal, else means error, same to excute in - * linux shell
      • - *
      • {@link CommandResult#successMsg} means success message of command result
      • - *
      • {@link CommandResult#errorMsg} means error message of command result
      • - *
      - * - * @author Trinea 2013-5-16 - */ - public static class CommandResult { - - /** result of command **/ - public int result; - /** success message of command result **/ - public String successMsg; - /** error message of command result **/ - public String errorMsg; - - public CommandResult(int result) { - this.result = result; - } - - public CommandResult(int result, String successMsg, String errorMsg) { - this.result = result; - this.successMsg = successMsg; - this.errorMsg = errorMsg; - } - } -} diff --git a/app/src/main/java/com/common/util/SystemUtils.java b/app/src/main/java/com/common/util/SystemUtils.java deleted file mode 100644 index 8c0eb4b..0000000 --- a/app/src/main/java/com/common/util/SystemUtils.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.common.util; - -/** - * SystemUtils - * - * @author Trinea 2013-5-15 - */ -public class SystemUtils { - - /** recommend default thread pool size according to system available processors, {@link #getDefaultThreadPoolSize()} **/ - public static final int DEFAULT_THREAD_POOL_SIZE = getDefaultThreadPoolSize(); - - private SystemUtils() { - throw new AssertionError(); - } - - /** - * get recommend default thread pool size - * - * @return if 2 * availableProcessors + 1 less than 8, return it, else return 8; - * @see {@link #getDefaultThreadPoolSize(int)} max is 8 - */ - public static int getDefaultThreadPoolSize() { - return getDefaultThreadPoolSize(8); - } - - /** - * get recommend default thread pool size - * - * @param max - * @return if 2 * availableProcessors + 1 less than max, return it, else return max; - */ - public static int getDefaultThreadPoolSize(int max) { - int availableProcessors = 2 * Runtime.getRuntime().availableProcessors() + 1; - return availableProcessors > max ? max : availableProcessors; - } -} diff --git a/app/src/main/java/com/stickercamera/app/camera/CameraBaseFragmentActivity.java b/app/src/main/java/com/stickercamera/app/camera/CameraBaseFragmentActivity.java deleted file mode 100644 index 8ae38de..0000000 --- a/app/src/main/java/com/stickercamera/app/camera/CameraBaseFragmentActivity.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.stickercamera.app.camera; - -import android.os.Bundle; - -import com.stickercamera.base.BaseFragmentActivity; - - -public class CameraBaseFragmentActivity extends BaseFragmentActivity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - CameraManager.getInst().addActivity(this); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - CameraManager.getInst().removeActivity(this); - } -} diff --git a/app/src/main/java/com/stickercamera/app/camera/adapter/FilterAdapter.java b/app/src/main/java/com/stickercamera/app/camera/adapter/FilterAdapter.java index 7deddde..a371f5f 100755 --- a/app/src/main/java/com/stickercamera/app/camera/adapter/FilterAdapter.java +++ b/app/src/main/java/com/stickercamera/app/camera/adapter/FilterAdapter.java @@ -16,8 +16,8 @@ import java.util.List; -import jp.co.cyberagent.android.gpuimage.GPUImageFilter; import jp.co.cyberagent.android.gpuimage.GPUImageView; +import jp.co.cyberagent.android.gpuimage.filter.GPUImageFilter; /** * @author tongqian.ni diff --git a/app/src/main/java/com/stickercamera/app/camera/ui/PhotoProcessActivity.java b/app/src/main/java/com/stickercamera/app/camera/ui/PhotoProcessActivity.java index 664b317..469be5f 100644 --- a/app/src/main/java/com/stickercamera/app/camera/ui/PhotoProcessActivity.java +++ b/app/src/main/java/com/stickercamera/app/camera/ui/PhotoProcessActivity.java @@ -55,7 +55,7 @@ import butterknife.ButterKnife; import butterknife.BindView; import org.greenrobot.eventbus.EventBus; -import jp.co.cyberagent.android.gpuimage.GPUImageFilter; +import jp.co.cyberagent.android.gpuimage.filter.GPUImageFilter; import jp.co.cyberagent.android.gpuimage.GPUImageView; /** @@ -378,11 +378,6 @@ private void initFilterToolBar(){ GPUImageFilter filter = GPUImageFilterTools.createFilterForType( PhotoProcessActivity.this, filters.get(position).getType()); mGPUImageView.setFilter(filter); - GPUImageFilterTools.FilterAdjuster mFilterAdjuster = new GPUImageFilterTools.FilterAdjuster(filter); - //可调节颜色的滤镜 - if (mFilterAdjuster.canAdjust()) { - //mFilterAdjuster.adjust(100); 给可调节的滤镜选一个合适的值 - } } }); bottomToolBar.setAdapter(adapter); diff --git a/app/src/main/java/com/stickercamera/app/camera/util/GPUImageFilterTools.java b/app/src/main/java/com/stickercamera/app/camera/util/GPUImageFilterTools.java index 2a0d238..3b7dd56 100755 --- a/app/src/main/java/com/stickercamera/app/camera/util/GPUImageFilterTools.java +++ b/app/src/main/java/com/stickercamera/app/camera/util/GPUImageFilterTools.java @@ -17,652 +17,65 @@ package com.stickercamera.app.camera.util; import android.content.Context; -import android.graphics.BitmapFactory; -import android.graphics.PointF; import com.github.skykai.stickercamera.R; -import jp.co.cyberagent.android.gpuimage.GPUImage3x3ConvolutionFilter; -import jp.co.cyberagent.android.gpuimage.GPUImage3x3TextureSamplingFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageAddBlendFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageAlphaBlendFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageBoxBlurFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageBrightnessFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageBulgeDistortionFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageCGAColorspaceFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageChromaKeyBlendFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageColorBalanceFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageColorBlendFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageColorBurnBlendFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageColorDodgeBlendFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageColorInvertFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageContrastFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageCrosshatchFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageDarkenBlendFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageDifferenceBlendFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageDilationFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageDirectionalSobelEdgeDetectionFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageDissolveBlendFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageDivideBlendFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageEmbossFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageExclusionBlendFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageExposureFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageFalseColorFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageFilterGroup; -import jp.co.cyberagent.android.gpuimage.GPUImageGammaFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageGaussianBlurFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageGlassSphereFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageGrayscaleFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageHardLightBlendFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageHazeFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageHighlightShadowFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageHueBlendFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageHueFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageKuwaharaFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageLaplacianFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageLightenBlendFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageLinearBurnBlendFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageLookupFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageLuminosityBlendFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageMonochromeFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageMultiplyBlendFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageNonMaximumSuppressionFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageNormalBlendFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageOpacityFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageOverlayBlendFilter; -import jp.co.cyberagent.android.gpuimage.GPUImagePixelationFilter; -import jp.co.cyberagent.android.gpuimage.GPUImagePosterizeFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageRGBDilationFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageRGBFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageSaturationBlendFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageSaturationFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageScreenBlendFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageSepiaFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageSharpenFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageSketchFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageSmoothToonFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageSobelEdgeDetection; -import jp.co.cyberagent.android.gpuimage.GPUImageSoftLightBlendFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageSourceOverBlendFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageSphereRefractionFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageSubtractBlendFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageSwirlFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageToneCurveFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageToonFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageTwoInputFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageVignetteFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageWeakPixelInclusionFilter; -import jp.co.cyberagent.android.gpuimage.GPUImageWhiteBalanceFilter; - -import java.util.LinkedList; -import java.util.List; +import jp.co.cyberagent.android.gpuimage.filter.GPUImageFilter; +import jp.co.cyberagent.android.gpuimage.filter.GPUImageToneCurveFilter; +/** + * 滤镜工厂。本 app 仅使用「原始」滤镜与 res/raw 下的 .acv 色调曲线滤镜 + * (见 {@link com.stickercamera.app.camera.EffectService}),因此这里只保留 + * NORMAL + ACV_* 两类。 + */ public class GPUImageFilterTools { public static GPUImageFilter createFilterForType(final Context context, final FilterType type) { - GPUImageToneCurveFilter curveFilter = new GPUImageToneCurveFilter(); switch (type) { case NORMAL: return new GPUImageFilter(); case ACV_AIMEI: - curveFilter.setFromCurveFileInputStream(context.getResources().openRawResource( - R.raw.aimei)); - return curveFilter; + return createCurveFilter(context, R.raw.aimei); case ACV_DANLAN: - curveFilter.setFromCurveFileInputStream(context.getResources().openRawResource( - R.raw.danlan)); - return curveFilter; + return createCurveFilter(context, R.raw.danlan); case ACV_DANHUANG: - curveFilter.setFromCurveFileInputStream(context.getResources().openRawResource( - R.raw.danhuang)); - return curveFilter; - case ACV_FUGU: - curveFilter.setFromCurveFileInputStream(context.getResources().openRawResource( - R.raw.fugu)); - return curveFilter; + return createCurveFilter(context, R.raw.danhuang); + case ACV_FUGU: + return createCurveFilter(context, R.raw.fugu); case ACV_GAOLENG: - curveFilter.setFromCurveFileInputStream(context.getResources().openRawResource( - R.raw.gaoleng)); - return curveFilter; + return createCurveFilter(context, R.raw.gaoleng); case ACV_HUAIJIU: - curveFilter.setFromCurveFileInputStream(context.getResources().openRawResource( - R.raw.huaijiu)); - return curveFilter; + return createCurveFilter(context, R.raw.huaijiu); case ACV_JIAOPIAN: - curveFilter.setFromCurveFileInputStream(context.getResources().openRawResource( - R.raw.jiaopian)); - return curveFilter; + return createCurveFilter(context, R.raw.jiaopian); case ACV_KEAI: - curveFilter.setFromCurveFileInputStream(context.getResources().openRawResource( - R.raw.keai)); - return curveFilter; + return createCurveFilter(context, R.raw.keai); case ACV_LOMO: - curveFilter.setFromCurveFileInputStream(context.getResources().openRawResource( - R.raw.lomo)); - return curveFilter; + return createCurveFilter(context, R.raw.lomo); case ACV_MORENJIAQIANG: - curveFilter.setFromCurveFileInputStream(context.getResources().openRawResource( - R.raw.morenjiaqiang)); - return curveFilter; + return createCurveFilter(context, R.raw.morenjiaqiang); case ACV_NUANXIN: - curveFilter.setFromCurveFileInputStream(context.getResources().openRawResource( - R.raw.nuanxin)); - return curveFilter; + return createCurveFilter(context, R.raw.nuanxin); case ACV_QINGXIN: - curveFilter.setFromCurveFileInputStream(context.getResources().openRawResource( - R.raw.qingxin)); - return curveFilter; + return createCurveFilter(context, R.raw.qingxin); case ACV_RIXI: - curveFilter.setFromCurveFileInputStream(context.getResources().openRawResource( - R.raw.rixi)); - return curveFilter; + return createCurveFilter(context, R.raw.rixi); case ACV_WENNUAN: - curveFilter.setFromCurveFileInputStream(context.getResources().openRawResource( - R.raw.wennuan)); - return curveFilter; - case CONTRAST: - return new GPUImageContrastFilter(2.0f); - case GAMMA: - return new GPUImageGammaFilter(2.0f); - case INVERT: - return new GPUImageColorInvertFilter(); - case PIXELATION: - return new GPUImagePixelationFilter(); - case HUE: - return new GPUImageHueFilter(90.0f); - case BRIGHTNESS: - return new GPUImageBrightnessFilter(1.5f); - case GRAYSCALE: - return new GPUImageGrayscaleFilter(); - case SEPIA: - return new GPUImageSepiaFilter(); - case SHARPEN: - GPUImageSharpenFilter sharpness = new GPUImageSharpenFilter(); - sharpness.setSharpness(2.0f); - return sharpness; - case SOBEL_EDGE_DETECTION: - return new GPUImageSobelEdgeDetection(); - case THREE_X_THREE_CONVOLUTION: - GPUImage3x3ConvolutionFilter convolution = new GPUImage3x3ConvolutionFilter(); - convolution.setConvolutionKernel(new float[] { -1.0f, 0.0f, 1.0f, -2.0f, 0.0f, - 2.0f, -1.0f, 0.0f, 1.0f }); - return convolution; - case EMBOSS: - return new GPUImageEmbossFilter(); - case POSTERIZE: - return new GPUImagePosterizeFilter(); - case FILTER_GROUP: - List filters = new LinkedList(); - filters.add(new GPUImageContrastFilter()); - filters.add(new GPUImageDirectionalSobelEdgeDetectionFilter()); - filters.add(new GPUImageGrayscaleFilter()); - return new GPUImageFilterGroup(filters); - case SATURATION: - return new GPUImageSaturationFilter(1.0f); - case EXPOSURE: - return new GPUImageExposureFilter(0.0f); - case HIGHLIGHT_SHADOW: - return new GPUImageHighlightShadowFilter(0.0f, 1.0f); - case MONOCHROME: - return new GPUImageMonochromeFilter(1.0f, new float[] { 0.6f, 0.45f, 0.3f, 1.0f }); - case OPACITY: - return new GPUImageOpacityFilter(1.0f); - case RGB: - return new GPUImageRGBFilter(1.0f, 1.0f, 1.0f); - case WHITE_BALANCE: - return new GPUImageWhiteBalanceFilter(5000.0f, 0.0f); - case VIGNETTE: - PointF centerPoint = new PointF(); - centerPoint.x = 0.5f; - centerPoint.y = 0.5f; - return new GPUImageVignetteFilter(centerPoint, new float[] { 0.0f, 0.0f, 0.0f }, - 0.3f, 0.75f); - case TONE_CURVE: - GPUImageToneCurveFilter toneCurveFilter = new GPUImageToneCurveFilter(); - toneCurveFilter.setFromCurveFileInputStream(context.getResources().openRawResource( - R.raw.tone_cuver_sample)); - return toneCurveFilter; - case BLEND_DIFFERENCE: - return createBlendFilter(context, GPUImageDifferenceBlendFilter.class); - case BLEND_SOURCE_OVER: - return createBlendFilter(context, GPUImageSourceOverBlendFilter.class); - case BLEND_COLOR_BURN: - return createBlendFilter(context, GPUImageColorBurnBlendFilter.class); - case BLEND_COLOR_DODGE: - return createBlendFilter(context, GPUImageColorDodgeBlendFilter.class); - case BLEND_DARKEN: - return createBlendFilter(context, GPUImageDarkenBlendFilter.class); - case BLEND_DISSOLVE: - return createBlendFilter(context, GPUImageDissolveBlendFilter.class); - case BLEND_EXCLUSION: - return createBlendFilter(context, GPUImageExclusionBlendFilter.class); - - case BLEND_HARD_LIGHT: - return createBlendFilter(context, GPUImageHardLightBlendFilter.class); - case BLEND_LIGHTEN: - return createBlendFilter(context, GPUImageLightenBlendFilter.class); - case BLEND_ADD: - return createBlendFilter(context, GPUImageAddBlendFilter.class); - case BLEND_DIVIDE: - return createBlendFilter(context, GPUImageDivideBlendFilter.class); - case BLEND_MULTIPLY: - return createBlendFilter(context, GPUImageMultiplyBlendFilter.class); - case BLEND_OVERLAY: - return createBlendFilter(context, GPUImageOverlayBlendFilter.class); - case BLEND_SCREEN: - return createBlendFilter(context, GPUImageScreenBlendFilter.class); - case BLEND_ALPHA: - return createBlendFilter(context, GPUImageAlphaBlendFilter.class); - case BLEND_COLOR: - return createBlendFilter(context, GPUImageColorBlendFilter.class); - case BLEND_HUE: - return createBlendFilter(context, GPUImageHueBlendFilter.class); - case BLEND_SATURATION: - return createBlendFilter(context, GPUImageSaturationBlendFilter.class); - case BLEND_LUMINOSITY: - return createBlendFilter(context, GPUImageLuminosityBlendFilter.class); - case BLEND_LINEAR_BURN: - return createBlendFilter(context, GPUImageLinearBurnBlendFilter.class); - case BLEND_SOFT_LIGHT: - return createBlendFilter(context, GPUImageSoftLightBlendFilter.class); - case BLEND_SUBTRACT: - return createBlendFilter(context, GPUImageSubtractBlendFilter.class); - case BLEND_CHROMA_KEY: - return createBlendFilter(context, GPUImageChromaKeyBlendFilter.class); - case BLEND_NORMAL: - return createBlendFilter(context, GPUImageNormalBlendFilter.class); - - case LOOKUP_AMATORKA: - GPUImageLookupFilter amatorka = new GPUImageLookupFilter(); - amatorka.setBitmap(BitmapFactory.decodeResource(context.getResources(), - R.drawable.lookup_amatorka)); - return amatorka; - case GAUSSIAN_BLUR: - return new GPUImageGaussianBlurFilter(); - case CROSSHATCH: - return new GPUImageCrosshatchFilter(); - - case BOX_BLUR: - return new GPUImageBoxBlurFilter(); - case CGA_COLORSPACE: - return new GPUImageCGAColorspaceFilter(); - case DILATION: - return new GPUImageDilationFilter(); - case KUWAHARA: - return new GPUImageKuwaharaFilter(); - case RGB_DILATION: - return new GPUImageRGBDilationFilter(); - case SKETCH: - return new GPUImageSketchFilter(); - case TOON: - return new GPUImageToonFilter(); - case SMOOTH_TOON: - return new GPUImageSmoothToonFilter(); - - case BULGE_DISTORTION: - return new GPUImageBulgeDistortionFilter(); - case GLASS_SPHERE: - return new GPUImageGlassSphereFilter(); - case HAZE: - return new GPUImageHazeFilter(); - case LAPLACIAN: - return new GPUImageLaplacianFilter(); - case NON_MAXIMUM_SUPPRESSION: - return new GPUImageNonMaximumSuppressionFilter(); - case SPHERE_REFRACTION: - return new GPUImageSphereRefractionFilter(); - case SWIRL: - return new GPUImageSwirlFilter(); - case WEAK_PIXEL_INCLUSION: - return new GPUImageWeakPixelInclusionFilter(); - case FALSE_COLOR: - return new GPUImageFalseColorFilter(); - case COLOR_BALANCE: - return new GPUImageColorBalanceFilter(); - + return createCurveFilter(context, R.raw.wennuan); default: throw new IllegalStateException("No filter of that type!"); } - - } - - private static GPUImageFilter createBlendFilter(Context context, - Class filterClass) { - try { - GPUImageTwoInputFilter filter = filterClass.newInstance(); - filter.setBitmap(BitmapFactory.decodeResource(context.getResources(), - R.drawable.ic_launcher)); - return filter; - } catch (Exception e) { - e.printStackTrace(); - return null; - } } - public interface OnGpuImageFilterChosenListener { - void onGpuImageFilterChosenListener(GPUImageFilter filter); + private static GPUImageToneCurveFilter createCurveFilter(final Context context, final int rawResId) { + GPUImageToneCurveFilter curveFilter = new GPUImageToneCurveFilter(); + curveFilter.setFromCurveFileInputStream(context.getResources().openRawResource(rawResId)); + return curveFilter; } public enum FilterType { - NORMAL, ACV_AIMEI, ACV_DANLAN, ACV_DANHUANG, ACV_FUGU, ACV_GAOLENG, ACV_HUAIJIU, ACV_JIAOPIAN, ACV_KEAI, ACV_LOMO, ACV_MORENJIAQIANG, ACV_NUANXIN, ACV_QINGXIN, ACV_RIXI, ACV_WENNUAN, CONTRAST, GRAYSCALE, SHARPEN, SEPIA, SOBEL_EDGE_DETECTION, THREE_X_THREE_CONVOLUTION, FILTER_GROUP, EMBOSS, POSTERIZE, GAMMA, BRIGHTNESS, INVERT, HUE, PIXELATION, SATURATION, EXPOSURE, HIGHLIGHT_SHADOW, MONOCHROME, OPACITY, RGB, WHITE_BALANCE, VIGNETTE, TONE_CURVE, BLEND_COLOR_BURN, BLEND_COLOR_DODGE, BLEND_DARKEN, BLEND_DIFFERENCE, BLEND_DISSOLVE, BLEND_EXCLUSION, BLEND_SOURCE_OVER, BLEND_HARD_LIGHT, BLEND_LIGHTEN, BLEND_ADD, BLEND_DIVIDE, BLEND_MULTIPLY, BLEND_OVERLAY, BLEND_SCREEN, BLEND_ALPHA, BLEND_COLOR, BLEND_HUE, BLEND_SATURATION, BLEND_LUMINOSITY, BLEND_LINEAR_BURN, BLEND_SOFT_LIGHT, BLEND_SUBTRACT, BLEND_CHROMA_KEY, BLEND_NORMAL, LOOKUP_AMATORKA, GAUSSIAN_BLUR, CROSSHATCH, BOX_BLUR, CGA_COLORSPACE, DILATION, KUWAHARA, RGB_DILATION, SKETCH, TOON, SMOOTH_TOON, BULGE_DISTORTION, GLASS_SPHERE, HAZE, LAPLACIAN, NON_MAXIMUM_SUPPRESSION, SPHERE_REFRACTION, SWIRL, WEAK_PIXEL_INCLUSION, FALSE_COLOR, COLOR_BALANCE - } - - private static class FilterList { - public List names = new LinkedList(); - public List filters = new LinkedList(); - - public void addFilter(final String name, final FilterType filter) { - names.add(name); - filters.add(filter); - } - } - - public static class FilterAdjuster { - private final Adjuster adjuster; - - public FilterAdjuster(final GPUImageFilter filter) { - if (filter instanceof GPUImageSharpenFilter) { - adjuster = new SharpnessAdjuster().filter(filter); - } else if (filter instanceof GPUImageSepiaFilter) { - adjuster = new SepiaAdjuster().filter(filter); - } else if (filter instanceof GPUImageContrastFilter) { - adjuster = new ContrastAdjuster().filter(filter); - } else if (filter instanceof GPUImageGammaFilter) { - adjuster = new GammaAdjuster().filter(filter); - } else if (filter instanceof GPUImageBrightnessFilter) { - adjuster = new BrightnessAdjuster().filter(filter); - } else if (filter instanceof GPUImageSobelEdgeDetection) { - adjuster = new SobelAdjuster().filter(filter); - } else if (filter instanceof GPUImageEmbossFilter) { - adjuster = new EmbossAdjuster().filter(filter); - } else if (filter instanceof GPUImage3x3TextureSamplingFilter) { - adjuster = new GPU3x3TextureAdjuster().filter(filter); - } else if (filter instanceof GPUImageHueFilter) { - adjuster = new HueAdjuster().filter(filter); - } else if (filter instanceof GPUImagePosterizeFilter) { - adjuster = new PosterizeAdjuster().filter(filter); - } else if (filter instanceof GPUImagePixelationFilter) { - adjuster = new PixelationAdjuster().filter(filter); - } else if (filter instanceof GPUImageSaturationFilter) { - adjuster = new SaturationAdjuster().filter(filter); - } else if (filter instanceof GPUImageExposureFilter) { - adjuster = new ExposureAdjuster().filter(filter); - } else if (filter instanceof GPUImageHighlightShadowFilter) { - adjuster = new HighlightShadowAdjuster().filter(filter); - } else if (filter instanceof GPUImageMonochromeFilter) { - adjuster = new MonochromeAdjuster().filter(filter); - } else if (filter instanceof GPUImageOpacityFilter) { - adjuster = new OpacityAdjuster().filter(filter); - } else if (filter instanceof GPUImageRGBFilter) { - adjuster = new RGBAdjuster().filter(filter); - } else if (filter instanceof GPUImageWhiteBalanceFilter) { - adjuster = new WhiteBalanceAdjuster().filter(filter); - } else if (filter instanceof GPUImageVignetteFilter) { - adjuster = new VignetteAdjuster().filter(filter); - } else if (filter instanceof GPUImageDissolveBlendFilter) { - adjuster = new DissolveBlendAdjuster().filter(filter); - } else if (filter instanceof GPUImageGaussianBlurFilter) { - adjuster = new GaussianBlurAdjuster().filter(filter); - } else if (filter instanceof GPUImageCrosshatchFilter) { - adjuster = new CrosshatchBlurAdjuster().filter(filter); - } else if (filter instanceof GPUImageBulgeDistortionFilter) { - adjuster = new BulgeDistortionAdjuster().filter(filter); - } else if (filter instanceof GPUImageGlassSphereFilter) { - adjuster = new GlassSphereAdjuster().filter(filter); - } else if (filter instanceof GPUImageHazeFilter) { - adjuster = new HazeAdjuster().filter(filter); - } else if (filter instanceof GPUImageSphereRefractionFilter) { - adjuster = new SphereRefractionAdjuster().filter(filter); - } else if (filter instanceof GPUImageSwirlFilter) { - adjuster = new SwirlAdjuster().filter(filter); - } else if (filter instanceof GPUImageColorBalanceFilter) { - adjuster = new ColorBalanceAdjuster().filter(filter); - } else { - adjuster = null; - } - } - - public boolean canAdjust() { - return adjuster != null; - } - - public void adjust(final int percentage) { - if (adjuster != null) { - adjuster.adjust(percentage); - } - } - - private abstract class Adjuster { - private T filter; - - @SuppressWarnings("unchecked") - public Adjuster filter(final GPUImageFilter filter) { - this.filter = (T) filter; - return this; - } - - public T getFilter() { - return filter; - } - - public abstract void adjust(int percentage); - - protected float range(final int percentage, final float start, final float end) { - return (end - start) * percentage / 100.0f + start; - } - - protected int range(final int percentage, final int start, final int end) { - return (end - start) * percentage / 100 + start; - } - } - - private class SharpnessAdjuster extends Adjuster { - @Override - public void adjust(final int percentage) { - getFilter().setSharpness(range(percentage, -4.0f, 4.0f)); - } - } - - private class PixelationAdjuster extends Adjuster { - @Override - public void adjust(final int percentage) { - getFilter().setPixel(range(percentage, 1.0f, 100.0f)); - } - } - - private class HueAdjuster extends Adjuster { - @Override - public void adjust(final int percentage) { - getFilter().setHue(range(percentage, 0.0f, 360.0f)); - } - } - - private class ContrastAdjuster extends Adjuster { - @Override - public void adjust(final int percentage) { - getFilter().setContrast(range(percentage, 0.0f, 2.0f)); - } - } - - private class GammaAdjuster extends Adjuster { - @Override - public void adjust(final int percentage) { - getFilter().setGamma(range(percentage, 0.0f, 3.0f)); - } - } - - private class BrightnessAdjuster extends Adjuster { - @Override - public void adjust(final int percentage) { - getFilter().setBrightness(range(percentage, -1.0f, 1.0f)); - } - } - - private class SepiaAdjuster extends Adjuster { - @Override - public void adjust(final int percentage) { - getFilter().setIntensity(range(percentage, 0.0f, 2.0f)); - } - } - - private class SobelAdjuster extends Adjuster { - @Override - public void adjust(final int percentage) { - getFilter().setLineSize(range(percentage, 0.0f, 5.0f)); - } - } - - private class EmbossAdjuster extends Adjuster { - @Override - public void adjust(final int percentage) { - getFilter().setIntensity(range(percentage, 0.0f, 4.0f)); - } - } - - private class PosterizeAdjuster extends Adjuster { - @Override - public void adjust(final int percentage) { - // In theorie to 256, but only first 50 are interesting - getFilter().setColorLevels(range(percentage, 1, 50)); - } - } - - private class GPU3x3TextureAdjuster extends Adjuster { - @Override - public void adjust(final int percentage) { - getFilter().setLineSize(range(percentage, 0.0f, 5.0f)); - } - } - - private class SaturationAdjuster extends Adjuster { - @Override - public void adjust(final int percentage) { - getFilter().setSaturation(range(percentage, 0.0f, 2.0f)); - } - } - - private class ExposureAdjuster extends Adjuster { - @Override - public void adjust(final int percentage) { - getFilter().setExposure(range(percentage, -10.0f, 10.0f)); - } - } - - private class HighlightShadowAdjuster extends Adjuster { - @Override - public void adjust(final int percentage) { - getFilter().setShadows(range(percentage, 0.0f, 1.0f)); - getFilter().setHighlights(range(percentage, 0.0f, 1.0f)); - } - } - - private class MonochromeAdjuster extends Adjuster { - @Override - public void adjust(final int percentage) { - getFilter().setIntensity(range(percentage, 0.0f, 1.0f)); - //getFilter().setColor(new float[]{0.6f, 0.45f, 0.3f, 1.0f}); - } - } - - private class OpacityAdjuster extends Adjuster { - @Override - public void adjust(final int percentage) { - getFilter().setOpacity(range(percentage, 0.0f, 1.0f)); - } - } - - private class RGBAdjuster extends Adjuster { - @Override - public void adjust(final int percentage) { - getFilter().setRed(range(percentage, 0.0f, 1.0f)); - //getFilter().setGreen(range(percentage, 0.0f, 1.0f)); - //getFilter().setBlue(range(percentage, 0.0f, 1.0f)); - } - } - - private class WhiteBalanceAdjuster extends Adjuster { - @Override - public void adjust(final int percentage) { - getFilter().setTemperature(range(percentage, 2000.0f, 8000.0f)); - //getFilter().setTint(range(percentage, -100.0f, 100.0f)); - } - } - - private class VignetteAdjuster extends Adjuster { - @Override - public void adjust(final int percentage) { - getFilter().setVignetteStart(range(percentage, 0.0f, 1.0f)); - } - } - - private class DissolveBlendAdjuster extends Adjuster { - @Override - public void adjust(final int percentage) { - getFilter().setMix(range(percentage, 0.0f, 1.0f)); - } - } - - private class GaussianBlurAdjuster extends Adjuster { - @Override - public void adjust(final int percentage) { - getFilter().setBlurSize(range(percentage, 0.0f, 1.0f)); - } - } - - private class CrosshatchBlurAdjuster extends Adjuster { - @Override - public void adjust(final int percentage) { - getFilter().setCrossHatchSpacing(range(percentage, 0.0f, 0.06f)); - getFilter().setLineWidth(range(percentage, 0.0f, 0.006f)); - } - } - - private class BulgeDistortionAdjuster extends Adjuster { - @Override - public void adjust(final int percentage) { - getFilter().setRadius(range(percentage, 0.0f, 1.0f)); - getFilter().setScale(range(percentage, -1.0f, 1.0f)); - } - } - - private class GlassSphereAdjuster extends Adjuster { - @Override - public void adjust(final int percentage) { - getFilter().setRadius(range(percentage, 0.0f, 1.0f)); - } - } - - private class HazeAdjuster extends Adjuster { - @Override - public void adjust(final int percentage) { - getFilter().setDistance(range(percentage, -0.3f, 0.3f)); - getFilter().setSlope(range(percentage, -0.3f, 0.3f)); - } - } - - private class SphereRefractionAdjuster extends Adjuster { - @Override - public void adjust(final int percentage) { - getFilter().setRadius(range(percentage, 0.0f, 1.0f)); - } - } - - private class SwirlAdjuster extends Adjuster { - @Override - public void adjust(final int percentage) { - getFilter().setAngle(range(percentage, 0.0f, 2.0f)); - } - } - - private class ColorBalanceAdjuster extends Adjuster { - - @Override - public void adjust(int percentage) { - getFilter().setMidtones( - new float[] { range(percentage, 0.0f, 1.0f), range(percentage / 2, 0.0f, 1.0f), - range(percentage / 3, 0.0f, 1.0f) }); - } - } + NORMAL, ACV_AIMEI, ACV_DANLAN, ACV_DANHUANG, ACV_FUGU, ACV_GAOLENG, ACV_HUAIJIU, + ACV_JIAOPIAN, ACV_KEAI, ACV_LOMO, ACV_MORENJIAQIANG, ACV_NUANXIN, ACV_QINGXIN, + ACV_RIXI, ACV_WENNUAN } } diff --git a/app/src/main/java/com/stickercamera/base/BaseFragmentActivity.java b/app/src/main/java/com/stickercamera/base/BaseFragmentActivity.java deleted file mode 100644 index 1e00598..0000000 --- a/app/src/main/java/com/stickercamera/base/BaseFragmentActivity.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.stickercamera.base; - -import androidx.fragment.app.FragmentActivity; -import android.view.View; - -import com.customview.CommonTitleBar; -import com.github.skykai.stickercamera.R; - -/** - * Created by sky on 15/7/6. - */ -public class BaseFragmentActivity extends FragmentActivity { - - protected CommonTitleBar titleBar; - - @Override - public void setContentView(int layoutResID) { - super.setContentView(layoutResID); - //titleBar = (CommonTitleBar) findViewById(R.id.title_layout); - if (titleBar != null) - titleBar.setLeftBtnOnclickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - finish(); - } - }); - } -} diff --git a/app/src/main/res/drawable-hdpi/lookup_amatorka.png b/app/src/main/res/drawable-hdpi/lookup_amatorka.png deleted file mode 100755 index 4a2cc8ac2f0c4ebd95c26b17ca59a47ca4c36a3c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36390 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 V#`AB@xp)BF%uFndpBp*f`xj2m*0KNq diff --git a/app/src/main/res/raw/tone_cuver_sample.acv b/app/src/main/res/raw/tone_cuver_sample.acv deleted file mode 100755 index 5b6c95551f4e94f3015bfda37ee967a9cc9a7ad4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 62 fcmZQzVPIuoVE}=A1}laK3@aG^10fSwgdht5M-L1= diff --git a/settings.gradle b/settings.gradle index 28f9a1b..062b0af 100644 --- a/settings.gradle +++ b/settings.gradle @@ -12,4 +12,4 @@ dependencyResolutionManagement { } } rootProject.name = "StickerCamera" -include ':app', ':Gpu-Image', ':ImageViewTouch' +include ':app', ':ImageViewTouch' From a907c10507e9a6610103f3a9fe8614cae31f0116 Mon Sep 17 00:00:00 2001 From: SkyKai <1132234509@qq.com> Date: Thu, 18 Jun 2026 19:55:16 +0800 Subject: [PATCH 16/16] =?UTF-8?q?fix(app):=20=E4=BF=AE=E5=A4=8D=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E7=BC=96=E8=BE=91=E4=BF=9D=E5=AD=98=E5=8D=A1=E5=9C=A8?= =?UTF-8?q?"=E5=9B=BE=E7=89=87=E5=A4=84=E7=90=86=E4=B8=AD"=E4=B8=94?= =?UTF-8?q?=E6=97=A0=E6=B3=95=E4=BF=9D=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit targetSdk 36 分区存储下根因修复: - 保存目录由公共外部存储 Environment.getExternalStorageDirectory() 改为应用专属目录 getExternalFilesDir(),免权限、全 API 级别可写 - FileUtils.mkdir() 改用 mkdirs(),修复 mkdir 失败时 while 循环空转、导致后台保存线程死循环卡死的根因 Co-Authored-By: Claude Opus 4.8 (1M context) --- .../main/java/com/common/util/FileUtils.java | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/common/util/FileUtils.java b/app/src/main/java/com/common/util/FileUtils.java index fde84bd..8171a4b 100644 --- a/app/src/main/java/com/common/util/FileUtils.java +++ b/app/src/main/java/com/common/util/FileUtils.java @@ -149,14 +149,14 @@ public String getSystemPhotoPath() { private FileUtils() { - String sdcardState = Environment.getExternalStorageState(); - //如果没SD卡则放缓存 - if (Environment.MEDIA_MOUNTED.equals(sdcardState)) { - BASE_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() - + "/stickercamera/"; - } else { - BASE_PATH = App.getApp().getCacheDirPath(); + // 分区存储(Android 10+ / targetSdk 36)下应用无法直接写公共外部目录, + // 改用应用专属外部目录:无需运行时权限,各 API 级别均可写。 + File baseDir = App.getApp().getExternalFilesDir(null); + if (baseDir == null) { + // 外部存储不可用时退回内部缓存目录 + baseDir = App.getApp().getCacheDir(); } + BASE_PATH = baseDir.getAbsolutePath() + "/stickercamera/"; STICKER_BASE_PATH = BASE_PATH + "/stickers/"; } @@ -174,10 +174,9 @@ public boolean createFile(File file) { } public boolean mkdir(File file) { - while (!file.getParentFile().exists()) { - mkdir(file.getParentFile()); - } - return file.mkdir(); + // 用 mkdirs() 一次性创建整条目录链。旧实现用 while 循环等待父目录出现, + // 一旦 mkdir 因权限失败(分区存储)便永远卡在循环里——这是保存线程卡死的根因。 + return file.exists() || file.mkdirs(); } public boolean writeSimpleString(File file, String string) {