[
  {
    "path": ".github/ISSUE_TEMPLATE.md",
    "content": "# Future Task\n\n## What is the motivation?\n\n## What kind of solution can be considered?\n\n## What do you want to discuss?\n\n*Please add relevant labels*\n\n-----\n\n# Bug Reporting\n\n## Steps to Reproduce\n\n## Actual Results (include screenshots)\n\n## Expected Results (include screenshots)\n\n## URL\n\n## OS details\n\n- Device:\n- OS:\n\n*Please add relevant labels*\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "## What does this change?\n\n## What is the value of this and can you measure success?\n\n## Screenshots\n\n"
  },
  {
    "path": ".gitignore",
    "content": "# Mac OS\n.DS_store\n\n# Built application files\n*.apk\n*.ap_\n\n# Files for the ART/Dalvik VM\n*.dex\n\n# Java class files\n*.class\n\n# Generated files\nbin/\ngen/\nout/\n\n# Gradle files\n.gradle/\nbuild/ \n# Local configuration file (sdk path, etc)\nlocal.properties\n\n# Proguard folder generated by Eclipse\nproguard/\n\n# Log Files\n*.log\n\n# Android Studio Navigation editor temp files\n.navigation/\n\n# Android Studio captures folder\ncaptures/\n\n# IntelliJ\n*.iml\n.idea/\nprojectFilesBackup/\n\n# Keystore files\n# Uncomment the following line if you do not want to check your keystore files in.\n#*.jks\n\n# External native build folder generated in Android Studio 2.2 and later\n.externalNativeBuild\n\n# Google Services (e.g. APIs or Firebase)\ngoogle-services.json\n\n# Freeline\nfastlane/README.md\nfastlane/report.xml\n\n# fastlane\nfastlane/report.xml\nfastlane/Preview.html\nfastlane/screenshots\nfastlane/test_output\nfastlane/readme.md\n\n# NDK\n.externalNativeBuild\n.cxx\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "Change Log\n==========\n\nVersion 2.1.0 *(2020-09-21)*\n----------------------------\n\n* Update\n  * Kotlin to 1.3.72\n  * The targetSdkVersion from 28 to 30\n  * The compileSdkVersion from 28 to 30\n\nVersion 2.0.4 *(2019-08-13)*\n----------------------------\n\n* Update\n  * Kotlin to 1.3.41\n  * Android Gradle tools to 3.6.0-alpha05\n  * Gradle wrapper to 5.5\n\n* Add\n  64bit build settings for clearly\n  Can get size of rescaled image [#443](https://github.com/cats-oss/android-gpuimage/pull/443)\n        \n* Bug fix\n  GPUImageZoomBlurFilter incorrect args [#454](https://github.com/cats-oss/android-gpuimage/pull/454)\n\nVersion 2.0.3 *(2018-11-09)*\n----------------------------\n\n* Add GPUImageVibranceFilter (by @itome)\n\nVersion 2.0.2 *(2018-11-01)*\n----------------------------\n\n* Add GPUImageSolarizeFilter (by @kettsun0123)\n\n* Change attr/names\n  `show_loading` to `gpuimage_show_loading`\n  `surface_type` to `gpuimage_surface_type`\n\n* Fix a bug about filter init [#420](https://github.com/cats-oss/android-gpuimage/pull/420)\n\nVersion 2.0.1 *(2018-10-24)*\n----------------------------\n\n* Add GPUImageLuminanceFilter (by @takasfz)\n* Add GPUImageLuminanceThresholdFilter (by @takasfz)\n\nVersion 2.0.0 *(2018-10-23)*\n----------------------------\n\n* Change the minSdkVersion 9 to 14\n* Change the targetSdkVersion 23 to 28\n* Update project settings\n* Support TextureView via GLTexureView\n* Support Camera2 API\n* Fix some bugs\n\n\nVersion 1.4.1 *(2016-03-15)*\n----------------------------\n Using Bintray's JCenter.\n\nVersion 1.4.0 *(2016-02-28)*\n----------------------------\n\n* added GPUImageHalftoneFilter (by @ryohey)\n* added GPUImageTransformFilter (by @jonan)\n* fixed GPUImageChromaKeyBlendFilter (by @badjano)\n* fixed GPUImageLookupFilter (by @jonan)\n\nVersion 1.3.0 *(2015-09-04)*\n----------------------------\n\n* added GPUImageBilateralFilter (by @wysaid)\n* added flip options to `GPUImage#setRotation`\n\nVersion 1.2.3-SNAPSHOT *(2014-12-15)*\n----------------------------\n\n* added GPUImageLevelsFilter (by @vashisthg)\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# How to Contribute\n\nWe'd love to accept your patches and contributions to this project. There are\njust a few small guidelines you need to follow.\n\n## Contributor License Agreement\n\nContributions to this project must be accompanied by a Contributor License\nAgreement. You (or your employer) retain the copyright to your contribution,\nthis simply gives us permission to use and redistribute your contributions as\npart of the project. Head over to <https://cla-assistant.io/cats-oss/android-gpuimage> to see\nyour current agreements on file or to sign a new one.\n\nYou generally only need to submit a CLA once, so if you've already submitted one\n(even if it was for a different project), you probably don't need to do it\nagain.\n\n## Code reviews\n\nAll submissions, including submissions by project members, require review. We\nuse GitHub pull requests for this purpose. Consult\n[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more\ninformation on using pull requests.\n\n## Community Guidelines\n\nThis project follows [Google's Open Source Community Guidelines](https://opensource.google.com/conduct/)."
  },
  {
    "path": "README.md",
    "content": "# GPUImage for Android\n[![License](https://img.shields.io/badge/license-Apache%202-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)\n[![Download](https://api.bintray.com/packages/cats-oss/maven/gpuimage/images/download.svg) ](https://bintray.com/cats-oss/maven/gpuimage/_latestVersion)\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/jp.co.cyberagent.android/gpuimage/badge.svg)](https://search.maven.org/artifact/jp.co.cyberagent.android/gpuimage)\n[![Build Status](https://app.bitrise.io/app/d8d8090a71066e7c/status.svg?token=sJNbvX8CkecWcUA5Z898lQ&branch=master)](https://app.bitrise.io/app/d8d8090a71066e7c)\n\nIdea from: [iOS GPUImage framework](https://github.com/BradLarson/GPUImage2)\n\nGoal is to have something as similar to GPUImage as possible. Vertex and fragment shaders are exactly the same. That way it makes it easier to port filters from GPUImage iOS to Android.\n\n## Requirements\n* Android 2.2 or higher (OpenGL ES 2.0)\n\n## Usage\n\n### Gradle dependency\n\n```groovy\nrepositories {\n    mavenCentral()\n}\n\ndependencies {\n    implementation 'jp.co.cyberagent.android:gpuimage:2.x.x'\n}\n```\n\n### Sample Code\n#### With preview:\n\nJava:\n```java\n@Override\npublic void onCreate(final Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(R.layout.activity);\n\n    Uri imageUri = ...;\n    gpuImage = new GPUImage(this);\n    gpuImage.setGLSurfaceView((GLSurfaceView) findViewById(R.id.surfaceView));\n    gpuImage.setImage(imageUri); // this loads image on the current thread, should be run in a thread\n    gpuImage.setFilter(new GPUImageSepiaFilter());\n\n    // Later when image should be saved saved:\n    gpuImage.saveToPictures(\"GPUImage\", \"ImageWithFilter.jpg\", null);\n}\n```\n\nKotlin:\n```kotlin\npublic override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    setContentView(R.layout.activity_gallery)\n\n    val imageUri: Uri = ...\n    gpuImage = GPUImage(this)\n    gpuImage.setGLSurfaceView(findViewById<GLSurfaceView>(R.id.surfaceView))\n    gpuImage.setImage(imageUri) // this loads image on the current thread, should be run in a thread\n    gpuImage.setFilter(GPUImageSepiaFilter())\n\n    // Later when image should be saved saved:\n    gpuImage.saveToPictures(\"GPUImage\", \"ImageWithFilter.jpg\", null)\n}\n```\n\n#### Using GPUImageView\n```xml\n<jp.co.cyberagent.android.gpuimage.GPUImageView\n    android:id=\"@+id/gpuimageview\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    app:gpuimage_show_loading=\"false\"\n    app:gpuimage_surface_type=\"texture_view\" /> <!-- surface_view or texture_view -->\n```\n\nJava:\n```java\n@Override\npublic void onCreate(final Bundle savedInstanceState) {\n    super.onCreate(savedInstanceState);\n    setContentView(R.layout.activity);\n\n    Uri imageUri = ...;\n    gpuImageView = findViewById(R.id.gpuimageview);\n    gpuImageView.setImage(imageUri); // this loads image on the current thread, should be run in a thread\n    gpuImageView.setFilter(new GPUImageSepiaFilter());\n\n    // Later when image should be saved saved:\n    gpuImageView.saveToPictures(\"GPUImage\", \"ImageWithFilter.jpg\", null);\n}\n```\n\nKotlin:\n```kotlin\npublic override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    setContentView(R.layout.activity_gallery)\n\n    val imageUri: Uri = ...\n    gpuImageView = findViewById<GPUImageView>(R.id.gpuimageview)\n    gpuImageView.setImage(imageUri) // this loads image on the current thread, should be run in a thread\n    gpuImageView.setFilter(GPUImageSepiaFilter())\n\n    // Later when image should be saved saved:\n    gpuImageView.saveToPictures(\"GPUImage\", \"ImageWithFilter.jpg\", null)\n}\n```\n\n#### Without preview:\n\nJava:\n```java\npublic void onCreate(final Bundle savedInstanceState) {\n    public void onCreate(final Bundle savedInstanceState) {\n    Uri imageUri = ...;\n    gpuImage = new GPUImage(context);\n    gpuImage.setFilter(new GPUImageSobelEdgeDetection());\n    gpuImage.setImage(imageUri);\n    gpuImage.saveToPictures(\"GPUImage\", \"ImageWithFilter.jpg\", null);\n}\n```\n\nKotlin:\n```kotlin\npublic override fun onCreate(savedInstanceState: Bundle?) {\n    super.onCreate(savedInstanceState)\n    setContentView(R.layout.activity_gallery)\n    val imageUri: Uri = ...\n    gpuImage = GPUImage(this)\n    gpuImage.setFilter(GPUImageSepiaFilter())\n    gpuImage.setImage(imageUri)\n    gpuImage.saveToPictures(\"GPUImage\", \"ImageWithFilter.jpg\", null)\n}\n```\n\n### Support status of [GPUImage for iOS](https://github.com/BradLarson/GPUImage2) shaders\n- [x] Saturation\n- [x] Contrast\n- [x] Brightness\n- [x] Levels\n- [x] Exposure\n- [x] RGB\n- [x] RGB Diation\n- [x] Hue\n- [x] White Balance\n- [x] Monochrome\n- [x] False Color\n- [x] Sharpen\n- [ ] Unsharp Mask\n- [x] Transform Operation\n- [ ] Crop\n- [x] Gamma\n- [x] Highlights and Shadows\n- [x] Haze\n- [x] Sepia Tone\n- [ ] Amatorka\n- [ ] Miss Etikate\n- [ ] Soft Elegance\n- [x] Color Inversion\n- [x] Solarize\n- [x] Vibrance\n- [ ] Highlight and Shadow Tint\n- [x] Luminance\n- [x] Luminance Threshold\n- [ ] Average Color\n- [ ] Average Luminance\n- [ ] Average Luminance Threshold\n- [ ] Adaptive Threshold\n- [ ] Polar Pixellate\n- [x] Pixellate\n- [ ] Polka Dot\n- [x] Halftone\n- [x] Crosshatch\n- [x] Sobel Edge Detection\n- [ ] Prewitt Edge Detection\n- [ ] Canny Edge Detection\n- [x] Threshold Sobel EdgeDetection\n- [ ] Harris Corner Detector\n- [ ] Noble Corner Detector\n- [ ] Shi Tomasi Feature Detector\n- [ ] Colour FAST Feature Detector\n- [ ] Low Pass Filter\n- [ ] High Pass Filter\n- [x] Sketch Filter\n- [ ] Threshold Sketch Filter\n- [x] Toon Filter\n- [x] SmoothToon Filter\n- [ ] Tilt Shift\n- [x] CGA Colorspace Filter\n- [x] Posterize\n- [x] Convolution 3x3\n- [x] Emboss Filter\n- [x] Laplacian\n- [x] Chroma Keying\n- [x] Kuwahara Filter\n- [ ] Kuwahara Radius3 Filter\n- [x] Vignette\n- [x] Gaussian Blur\n- [x] Box Blur\n- [x] Bilateral Blur\n- [ ] Motion Blur\n- [x] Zoom Blur\n- [ ] iOS Blur\n- [ ] Median Filter\n- [x] Swirl Distortion\n- [x] Bulge Distortion\n- [ ] Pinch Distortion\n- [x] Sphere Refraction\n- [x] Glass Sphere Refraction\n- [ ] Stretch Distortion\n- [x] Dilation\n- [ ] Erosion\n- [ ] Opening Filter\n- [ ] Closing Filter\n- [ ] Local Binary Pattern\n- [ ] Color Local Binary Pattern\n- [x] Dissolve Blend\n- [x] Chroma Key Blend\n- [x] Add Blend\n- [x] Divide Blend\n- [x] Multiply Blend\n- [x] Overlay Blend\n- [x] Lighten Blend\n- [x] Darken Blend\n- [x] Color Burn Blend\n- [x] Color Dodge Blend\n- [x] Linear Burn Blend\n- [x] Screen Blend\n- [x] Difference Blend\n- [x] Subtract Blend\n- [x] Exclusion Blend\n- [x] HardLight Blend\n- [x] SoftLight Blend\n- [x] Color Blend\n- [x] Hue Blend\n- [x] Saturation Blend\n- [x] Luminosity Blend\n- [x] Normal Blend\n- [x] Source Over Blend\n- [x] Alpha Blend\n- [x] Non Maximum Suppression\n- [ ] Thresholded Non Maximum Suppression\n- [ ] Directional Non Maximum Suppression\n- [x] Opacity\n- [x] Weak Pixel Inclusion Filter\n- [x] Color Matrix\n- [x] Directional Sobel Edge Detection\n- [x] Lookup\n- [x] Tone Curve (*.acv files) \n\n## Others\n- [x] Texture 3x3\n- [x] Gray Scale\n\n### Gradle\nMake sure that you run the clean target when using maven.\n\n```groovy\ngradle clean assemble\n```\n\n## License\n    Copyright 2018 CyberAgent, Inc.\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n"
  },
  {
    "path": "build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    ext.kotlin_version = '1.3.72'\n    repositories {\n        google()\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:4.2.0-beta04'\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n\n// TODO: Close JCenter on May 1st https://jfrog.com/blog/into-the-sunset-bintray-jcenter-gocenter-and-chartcenter/\n//        classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.5'\n//        classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'\n    }\n}\n\nallprojects {\n    repositories {\n        google()\n        mavenCentral()\n        jcenter()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https://services.gradle.org/distributions/gradle-6.7.1-bin.zip\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists"
  },
  {
    "path": "gradle.properties",
    "content": "# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=1024m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\norg.gradle.parallel=true\norg.gradle.daemon=true\norg.gradle.configureondemand=true\norg.gradle.caching=true\nandroid.enableBuildCache=true\n\nVERSION_NAME=2.1.0\nVERSION_CODE=14\n\nCOMPILE_SDK_VERSION=30\nTARGET_SDK_VERSION=30\nMIN_SDK_VERSION=14\n\nandroid.useAndroidX=true\nandroid.enableJetifier=true\n"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env sh\n\n#\n# Copyright 2015 the original author or authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn () {\n    echo \"$*\"\n}\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\n  NONSTOP* )\n    nonstop=true\n    ;;\nesac\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" -a \"$nonstop\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin or MSYS, switch paths to Windows format before running java\nif [ \"$cygwin\" = \"true\" -o \"$msys\" = \"true\" ] ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=`expr $i + 1`\n    done\n    case $i in\n        0) set -- ;;\n        1) set -- \"$args0\" ;;\n        2) set -- \"$args0\" \"$args1\" ;;\n        3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Escape application args\nsave () {\n    for i do printf %s\\\\n \"$i\" | sed \"s/'/'\\\\\\\\''/g;1s/^/'/;\\$s/\\$/' \\\\\\\\/\" ; done\n    echo \" \"\n}\nAPP_ARGS=`save \"$@\"`\n\n# Collect all arguments for the java command, following the shell quoting and substitution rules\neval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS \"\\\"-Dorg.gradle.appname=$APP_BASE_NAME\\\"\" -classpath \"\\\"$CLASSPATH\\\"\" org.gradle.wrapper.GradleWrapperMain \"$APP_ARGS\"\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@rem\r\n@rem Copyright 2015 the original author or authors.\r\n@rem\r\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\r\n@rem you may not use this file except in compliance with the License.\r\n@rem You may obtain a copy of the License at\r\n@rem\r\n@rem      https://www.apache.org/licenses/LICENSE-2.0\r\n@rem\r\n@rem Unless required by applicable law or agreed to in writing, software\r\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\r\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n@rem See the License for the specific language governing permissions and\r\n@rem limitations under the License.\r\n@rem\r\n\r\n@if \"%DEBUG%\" == \"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Resolve any \".\" and \"..\" in APP_HOME to make it shorter.\r\nfor %%i in (\"%APP_HOME%\") do set APP_HOME=%%~fi\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif \"%ERRORLEVEL%\" == \"0\" goto execute\r\n\r\necho.\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto execute\r\n\r\necho.\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\r\necho.\r\necho Please set the JAVA_HOME variable in your environment to match the\r\necho location of your Java installation.\r\n\r\ngoto fail\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\r\n\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %*\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\r\nexit /b 1\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "library/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion COMPILE_SDK_VERSION as int\n\n    defaultConfig {\n        minSdkVersion MIN_SDK_VERSION as int\n        targetSdkVersion TARGET_SDK_VERSION as int\n\n        versionCode = VERSION_CODE as int\n        versionName = VERSION_NAME\n        ndk.abiFilters 'armeabi-v7a','arm64-v8a','x86','x86_64'\n        externalNativeBuild {\n            cmake { cppFlags \"\" }\n        }\n    }\n    externalNativeBuild {\n        cmake { path \"src/main/cpp/CMakeLists.txt\" }\n    }\n\n    buildTypes {\n        debug {\n            debuggable true\n        }\n        release {\n            debuggable false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\next {\n    bintrayRepo = 'maven'\n    bintrayName = 'gpuimage'\n    bintrayUserOrg = 'cats-oss'\n    publishedGroupId = 'jp.co.cyberagent.android'\n    libraryName = 'gpuimage'\n    artifact = 'gpuimage'\n    libraryDescription = 'Image filters for Android with OpenGL (based on GPUImage for iOS)'\n    siteUrl = 'https://github.com/cats-oss/android-gpuimage'\n    gitUrl = 'https://github.com/cats-oss/android-gpuimage.git'\n    issueUrl = 'https://github.com/cats-oss/android-gpuimage/issues'\n    libraryVersion = VERSION_NAME\n    developerId = 'cats'\n    developerName = 'CATS'\n    developerEmail = 'dadadada.chop@gmail.com'\n    licenseName = 'The Apache Software License, Version 2.0'\n    licenseUrl = 'http://www.apache.org/licenses/LICENSE-2.0.txt'\n    allLicenses = [\"Apache-2.0\"]\n}\n\n// TODO: Close JCenter on May 1st https://jfrog.com/blog/into-the-sunset-bintray-jcenter-gocenter-and-chartcenter/\n// apply from: 'https://gist.githubusercontent.com/wasabeef/cf14805bee509baf7461974582f17d26/raw/bintray-v1.gradle'\n// apply from: 'https://gist.githubusercontent.com/wasabeef/cf14805bee509baf7461974582f17d26/raw/install-v1.gradle'\n\napply from: 'https://gist.githubusercontent.com/wasabeef/2f2ae8d97b429e7d967128125dc47854/raw/maven-central-v1.gradle'"
  },
  {
    "path": "library/gradle.properties",
    "content": "POM_NAME=GPUImage for Android Library\nPOM_ARTIFACT_ID=gpuimage-library\nPOM_PACKAGING=aar"
  },
  {
    "path": "library/proguard-rules.txt",
    "content": "-dontwarn jp.co.cyberagent.android.gpuimage.**"
  },
  {
    "path": "library/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest package=\"jp.co.cyberagent.android.gpuimage\" />"
  },
  {
    "path": "library/src/main/cpp/CMakeLists.txt",
    "content": "# For more information about using CMake with Android Studio, read the\n# documentation: https://d.android.com/studio/projects/add-native-code.html\n\n# Sets the minimum version of CMake required to build the native library.\n\ncmake_minimum_required(VERSION 3.4.1)\n\n# Creates and names a library, sets it as either STATIC\n# or SHARED, and provides the relative paths to its source code.\n# You can define multiple libraries, and CMake builds them for you.\n# Gradle automatically packages shared libraries with your APK.\n\nadd_library( # Sets the name of the library.\n        yuv-decoder\n\n        # Sets the library as a shared library.\n        SHARED\n\n        # Provides a relative path to your source file(s).\n        yuv-decoder.c)\n\n# Searches for a specified prebuilt library and stores the path as a\n# variable. Because CMake includes system libraries in the search path by\n# default, you only need to specify the name of the public NDK library\n# you want to add. CMake verifies that the library exists before\n# completing its build.\n\nfind_library( # Sets the name of the path variable.\n        log-lib\n\n        # Specifies the name of the NDK library that\n        # you want CMake to locate.\n        log)\n\n# Specifies libraries CMake should link to your target library. You\n# can link multiple libraries, such as libraries you define in this\n# build script, prebuilt third-party libraries, or system libraries.\n\ntarget_link_libraries( # Specifies the target library.\n        yuv-decoder\n\n        # Links the target library to the log library\n        # included in the NDK.\n        ${log-lib}\n        GLESv2\n        jnigraphics)"
  },
  {
    "path": "library/src/main/cpp/yuv-decoder.c",
    "content": "#include <jni.h>\n\n#include <android/bitmap.h>\n#include <GLES2/gl2.h>\n\n\nJNIEXPORT void JNICALL\nJava_jp_co_cyberagent_android_gpuimage_GPUImageNativeLibrary_YUVtoRBGA(JNIEnv *env, jobject obj,\n                                                                       jbyteArray yuv420sp,\n                                                                       jint width, jint height,\n                                                                       jintArray rgbOut) {\n    int sz;\n    int i;\n    int j;\n    int Y;\n    int Cr = 0;\n    int Cb = 0;\n    int pixPtr = 0;\n    int jDiv2 = 0;\n    int R = 0;\n    int G = 0;\n    int B = 0;\n    int cOff;\n    int w = width;\n    int h = height;\n    sz = w * h;\n\n    jint *rgbData = (jint *) ((*env)->GetPrimitiveArrayCritical(env, rgbOut, 0));\n    jbyte *yuv = (jbyte *) (*env)->GetPrimitiveArrayCritical(env, yuv420sp, 0);\n\n    for (j = 0; j < h; j++) {\n        pixPtr = j * w;\n        jDiv2 = j >> 1;\n        for (i = 0; i < w; i++) {\n            Y = yuv[pixPtr];\n            if (Y < 0) Y += 255;\n            if ((i & 0x1) != 1) {\n                cOff = sz + jDiv2 * w + (i >> 1) * 2;\n                Cb = yuv[cOff];\n                if (Cb < 0) Cb += 127; else Cb -= 128;\n                Cr = yuv[cOff + 1];\n                if (Cr < 0) Cr += 127; else Cr -= 128;\n            }\n\n            //ITU-R BT.601 conversion\n            //\n            //R = 1.164*(Y-16) + 2.018*(Cr-128);\n            //G = 1.164*(Y-16) - 0.813*(Cb-128) - 0.391*(Cr-128);\n            //B = 1.164*(Y-16) + 1.596*(Cb-128);\n            //\n            Y = Y + (Y >> 3) + (Y >> 5) + (Y >> 7);\n            R = Y + (Cr << 1) + (Cr >> 6);\n            if (R < 0) R = 0; else if (R > 255) R = 255;\n            G = Y - Cb + (Cb >> 3) + (Cb >> 4) - (Cr >> 1) + (Cr >> 3);\n            if (G < 0) G = 0; else if (G > 255) G = 255;\n            B = Y + Cb + (Cb >> 1) + (Cb >> 4) + (Cb >> 5);\n            if (B < 0) B = 0; else if (B > 255) B = 255;\n            rgbData[pixPtr++] = 0xff000000 + (R << 16) + (G << 8) + B;\n        }\n    }\n\n    (*env)->ReleasePrimitiveArrayCritical(env, rgbOut, rgbData, 0);\n    (*env)->ReleasePrimitiveArrayCritical(env, yuv420sp, yuv, 0);\n}\n\nJNIEXPORT void JNICALL\nJava_jp_co_cyberagent_android_gpuimage_GPUImageNativeLibrary_YUVtoARBG(JNIEnv *env, jobject obj,\n                                                                       jbyteArray yuv420sp,\n                                                                       jint width, jint height,\n                                                                       jintArray rgbOut) {\n    int sz;\n    int i;\n    int j;\n    int Y;\n    int Cr = 0;\n    int Cb = 0;\n    int pixPtr = 0;\n    int jDiv2 = 0;\n    int R = 0;\n    int G = 0;\n    int B = 0;\n    int cOff;\n    int w = width;\n    int h = height;\n    sz = w * h;\n\n    jint *rgbData = (jint *) ((*env)->GetPrimitiveArrayCritical(env, rgbOut, 0));\n    jbyte *yuv = (jbyte *) (*env)->GetPrimitiveArrayCritical(env, yuv420sp, 0);\n\n    for (j = 0; j < h; j++) {\n        pixPtr = j * w;\n        jDiv2 = j >> 1;\n        for (i = 0; i < w; i++) {\n            Y = yuv[pixPtr];\n            if (Y < 0) Y += 255;\n            if ((i & 0x1) != 1) {\n                cOff = sz + jDiv2 * w + (i >> 1) * 2;\n                Cb = yuv[cOff];\n                if (Cb < 0) Cb += 127; else Cb -= 128;\n                Cr = yuv[cOff + 1];\n                if (Cr < 0) Cr += 127; else Cr -= 128;\n            }\n\n            //ITU-R BT.601 conversion\n            //\n            //R = 1.164*(Y-16) + 2.018*(Cr-128);\n            //G = 1.164*(Y-16) - 0.813*(Cb-128) - 0.391*(Cr-128);\n            //B = 1.164*(Y-16) + 1.596*(Cb-128);\n            //\n            Y = Y + (Y >> 3) + (Y >> 5) + (Y >> 7);\n            R = Y + (Cr << 1) + (Cr >> 6);\n            if (R < 0) R = 0; else if (R > 255) R = 255;\n            G = Y - Cb + (Cb >> 3) + (Cb >> 4) - (Cr >> 1) + (Cr >> 3);\n            if (G < 0) G = 0; else if (G > 255) G = 255;\n            B = Y + Cb + (Cb >> 1) + (Cb >> 4) + (Cb >> 5);\n            if (B < 0) B = 0; else if (B > 255) B = 255;\n            rgbData[pixPtr++] = 0xff000000 + (B << 16) + (G << 8) + R;\n        }\n    }\n\n    (*env)->ReleasePrimitiveArrayCritical(env, rgbOut, rgbData, 0);\n    (*env)->ReleasePrimitiveArrayCritical(env, yuv420sp, yuv, 0);\n}\n\n\nJNIEXPORT void JNICALL\nJava_jp_co_cyberagent_android_gpuimage_GPUImageNativeLibrary_adjustBitmap(JNIEnv *jenv, jclass thiz,\n                                                                       jobject src) {\n    unsigned char *srcByteBuffer;\n    int result = 0;\n    int i, j;\n    AndroidBitmapInfo srcInfo;\n\n    result = AndroidBitmap_getInfo(jenv, src, &srcInfo);\n    if (result != ANDROID_BITMAP_RESULT_SUCCESS) {\n        return;\n    }\n\n    result = AndroidBitmap_lockPixels(jenv, src, (void **) &srcByteBuffer);\n    if (result != ANDROID_BITMAP_RESULT_SUCCESS) {\n        return;\n    }\n\n    int width = srcInfo.width;\n    int height = srcInfo.height;\n    glReadPixels(0, 0, srcInfo.width, srcInfo.height, GL_RGBA, GL_UNSIGNED_BYTE, srcByteBuffer);\n\n    int *pIntBuffer = (int *) srcByteBuffer;\n\n    for (i = 0; i < height / 2; i++) {\n        for (j = 0; j < width; j++) {\n            int temp = pIntBuffer[(height - i - 1) * width + j];\n            pIntBuffer[(height - i - 1) * width + j] = pIntBuffer[i * width + j];\n            pIntBuffer[i * width + j] = temp;\n        }\n    }\n    AndroidBitmap_unlockPixels(jenv, src);\n}"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/GLTextureView.java",
    "content": "package jp.co.cyberagent.android.gpuimage;\n\nimport android.content.Context;\nimport android.graphics.SurfaceTexture;\nimport android.opengl.GLDebugHelper;\nimport android.util.AttributeSet;\nimport android.util.Log;\nimport android.view.TextureView;\nimport android.view.View;\n\nimport java.io.Writer;\nimport java.lang.ref.WeakReference;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport javax.microedition.khronos.egl.EGL10;\nimport javax.microedition.khronos.egl.EGL11;\nimport javax.microedition.khronos.egl.EGLConfig;\nimport javax.microedition.khronos.egl.EGLContext;\nimport javax.microedition.khronos.egl.EGLDisplay;\nimport javax.microedition.khronos.egl.EGLSurface;\nimport javax.microedition.khronos.opengles.GL;\nimport javax.microedition.khronos.opengles.GL10;\n\n/*\n * Copyright (C) 2018 Wasabeef\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\npublic class GLTextureView extends TextureView\n        implements TextureView.SurfaceTextureListener, View.OnLayoutChangeListener {\n\n    private final static String TAG = GLTextureView.class.getSimpleName();\n\n    private final static boolean LOG_ATTACH_DETACH = false;\n    private final static boolean LOG_THREADS = false;\n    private final static boolean LOG_PAUSE_RESUME = false;\n    private final static boolean LOG_SURFACE = false;\n    private final static boolean LOG_RENDERER = false;\n    private final static boolean LOG_RENDERER_DRAW_FRAME = false;\n    private final static boolean LOG_EGL = false;\n\n    /**\n     * The renderer only renders\n     * when the surface is created, or when {@link #requestRender} is called.\n     *\n     * @see #getRenderMode()\n     * @see #setRenderMode(int)\n     * @see #requestRender()\n     */\n    public final static int RENDERMODE_WHEN_DIRTY = 0;\n    /**\n     * The renderer is called\n     * continuously to re-render the scene.\n     *\n     * @see #getRenderMode()\n     * @see #setRenderMode(int)\n     */\n    public final static int RENDERMODE_CONTINUOUSLY = 1;\n\n    /**\n     * Check glError() after every GL call and throw an exception if glError indicates\n     * that an error has occurred. This can be used to help track down which OpenGL ES call\n     * is causing an error.\n     *\n     * @see #getDebugFlags\n     * @see #setDebugFlags\n     */\n    public final static int DEBUG_CHECK_GL_ERROR = 1;\n\n    /**\n     * Log GL calls to the system log at \"verbose\" level with tag \"GLTextureView\".\n     *\n     * @see #getDebugFlags\n     * @see #setDebugFlags\n     */\n    public final static int DEBUG_LOG_GL_CALLS = 2;\n\n    /**\n     * Standard View constructor. In order to render something, you\n     * must call {@link #setRenderer} to register a renderer.\n     */\n    public GLTextureView(Context context) {\n        super(context);\n        init();\n    }\n\n    /**\n     * Standard View constructor. In order to render something, you\n     * must call {@link #setRenderer} to register a renderer.\n     */\n    public GLTextureView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        init();\n    }\n\n    @Override\n    protected void finalize() throws Throwable {\n        try {\n            if (glThread != null) {\n                // GLThread may still be running if this view was never\n                // attached to a window.\n                glThread.requestExitAndWait();\n            }\n        } finally {\n            super.finalize();\n        }\n    }\n\n    private void init() {\n        setSurfaceTextureListener(this);\n    }\n\n    /**\n     * Set the glWrapper. If the glWrapper is not null, its\n     * {@link GLWrapper#wrap(javax.microedition.khronos.opengles.GL)} method is called\n     * whenever a surface is created. A GLWrapper can be used to wrap\n     * the GL object that's passed to the renderer. Wrapping a GL\n     * object enables examining and modifying the behavior of the\n     * GL calls made by the renderer.\n     * <p>\n     * Wrapping is typically used for debugging purposes.\n     * <p>\n     * The default value is null.\n     *\n     * @param glWrapper the new GLWrapper\n     */\n    public void setGLWrapper(GLWrapper glWrapper) {\n        this.glWrapper = glWrapper;\n    }\n\n    /**\n     * Set the debug flags to a new value. The value is\n     * constructed by OR-together zero or more\n     * of the DEBUG_CHECK_* constants. The debug flags take effect\n     * whenever a surface is created. The default value is zero.\n     *\n     * @param debugFlags the new debug flags\n     * @see #DEBUG_CHECK_GL_ERROR\n     * @see #DEBUG_LOG_GL_CALLS\n     */\n    public void setDebugFlags(int debugFlags) {\n        this.debugFlags = debugFlags;\n    }\n\n    /**\n     * Get the current value of the debug flags.\n     *\n     * @return the current value of the debug flags.\n     */\n    public int getDebugFlags() {\n        return debugFlags;\n    }\n\n    /**\n     * Control whether the EGL context is preserved when the GLTextureView is paused and\n     * resumed.\n     * <p>\n     * If set to true, then the EGL context may be preserved when the GLTextureView is paused.\n     * Whether the EGL context is actually preserved or not depends upon whether the\n     * Android device that the program is running on can support an arbitrary number of EGL\n     * contexts or not. Devices that can only support a limited number of EGL contexts must\n     * release the  EGL context in order to allow multiple applications to share the GPU.\n     * <p>\n     * If set to false, the EGL context will be released when the GLTextureView is paused,\n     * and recreated when the GLTextureView is resumed.\n     * <p>\n     * <p>\n     * The default is false.\n     *\n     * @param preserveOnPause preserve the EGL context when paused\n     */\n    public void setPreserveEGLContextOnPause(boolean preserveOnPause) {\n        preserveEGLContextOnPause = preserveOnPause;\n    }\n\n    /**\n     * @return true if the EGL context will be preserved when paused\n     */\n    public boolean getPreserveEGLContextOnPause() {\n        return preserveEGLContextOnPause;\n    }\n\n    /**\n     * Set the renderer associated with this view. Also starts the thread that\n     * will call the renderer, which in turn causes the rendering to start.\n     * <p>This method should be called once and only once in the life-cycle of\n     * a GLTextureView.\n     * <p>The following GLTextureView methods can only be called <em>before</em>\n     * setRenderer is called:\n     * <ul>\n     * <li>{@link #setEGLConfigChooser(boolean)}\n     * <li>{@link #setEGLConfigChooser(EGLConfigChooser)}\n     * <li>{@link #setEGLConfigChooser(int, int, int, int, int, int)}\n     * </ul>\n     * <p>\n     * The following GLTextureView methods can only be called <em>after</em>\n     * setRenderer is called:\n     * <ul>\n     * <li>{@link #getRenderMode()}\n     * <li>{@link #onPause()}\n     * <li>{@link #onResume()}\n     * <li>{@link #queueEvent(Runnable)}\n     * <li>{@link #requestRender()}\n     * <li>{@link #setRenderMode(int)}\n     * </ul>\n     *\n     * @param renderer the renderer to use to perform OpenGL drawing.\n     */\n    public void setRenderer(Renderer renderer) {\n        checkRenderThreadState();\n        if (eglConfigChooser == null) {\n            eglConfigChooser = new SimpleEGLConfigChooser(true);\n        }\n        if (eglContextFactory == null) {\n            eglContextFactory = new DefaultContextFactory();\n        }\n        if (eglWindowSurfaceFactory == null) {\n            eglWindowSurfaceFactory = new DefaultWindowSurfaceFactory();\n        }\n        this.renderer = renderer;\n        glThread = new GLThread(mThisWeakRef);\n        glThread.start();\n    }\n\n    /**\n     * Install a custom EGLContextFactory.\n     * <p>If this method is\n     * called, it must be called before {@link #setRenderer(Renderer)}\n     * is called.\n     * <p>\n     * If this method is not called, then by default\n     * a context will be created with no shared context and\n     * with a null attribute list.\n     */\n    public void setEGLContextFactory(EGLContextFactory factory) {\n        checkRenderThreadState();\n        eglContextFactory = factory;\n    }\n\n    /**\n     * Install a custom EGLWindowSurfaceFactory.\n     * <p>If this method is\n     * called, it must be called before {@link #setRenderer(Renderer)}\n     * is called.\n     * <p>\n     * If this method is not called, then by default\n     * a window surface will be created with a null attribute list.\n     */\n    public void setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory factory) {\n        checkRenderThreadState();\n        eglWindowSurfaceFactory = factory;\n    }\n\n    /**\n     * Install a custom EGLConfigChooser.\n     * <p>If this method is\n     * called, it must be called before {@link #setRenderer(Renderer)}\n     * is called.\n     * <p>\n     * If no setEGLConfigChooser method is called, then by default the\n     * view will choose an EGLConfig that is compatible with the current\n     * android.view.Surface, with a depth buffer depth of\n     * at least 16 bits.\n     */\n    public void setEGLConfigChooser(EGLConfigChooser configChooser) {\n        checkRenderThreadState();\n        eglConfigChooser = configChooser;\n    }\n\n    /**\n     * Install a config chooser which will choose a config\n     * as close to 16-bit RGB as possible, with or without an optional depth\n     * buffer as close to 16-bits as possible.\n     * <p>If this method is\n     * called, it must be called before {@link #setRenderer(Renderer)}\n     * is called.\n     * <p>\n     * If no setEGLConfigChooser method is called, then by default the\n     * view will choose an RGB_888 surface with a depth buffer depth of\n     * at least 16 bits.\n     */\n    public void setEGLConfigChooser(boolean needDepth) {\n        setEGLConfigChooser(new SimpleEGLConfigChooser(needDepth));\n    }\n\n    /**\n     * Install a config chooser which will choose a config\n     * with at least the specified depthSize and stencilSize,\n     * and exactly the specified redSize, greenSize, blueSize and alphaSize.\n     * <p>If this method is\n     * called, it must be called before {@link #setRenderer(Renderer)}\n     * is called.\n     * <p>\n     * If no setEGLConfigChooser method is called, then by default the\n     * view will choose an RGB_888 surface with a depth buffer depth of\n     * at least 16 bits.\n     */\n    public void setEGLConfigChooser(int redSize, int greenSize, int blueSize, int alphaSize,\n                                    int depthSize, int stencilSize) {\n        setEGLConfigChooser(\n                new ComponentSizeChooser(redSize, greenSize, blueSize, alphaSize, depthSize, stencilSize));\n    }\n\n    /**\n     * Inform the default EGLContextFactory and default EGLConfigChooser\n     * which EGLContext client version to pick.\n     * <p>Use this method to create an OpenGL ES 2.0-compatible context.\n     * Example:\n     * <pre class=\"prettyprint\">\n     * public MyView(Context context) {\n     * super(context);\n     * setEGLContextClientVersion(2); // Pick an OpenGL ES 2.0 context.\n     * setRenderer(new MyRenderer());\n     * }\n     * </pre>\n     * <p>Note: Activities which require OpenGL ES 2.0 should indicate this by\n     * setting @lt;uses-feature android:glEsVersion=\"0x00020000\" /> in the activity's\n     * AndroidManifest.xml file.\n     * <p>If this method is called, it must be called before {@link #setRenderer(Renderer)}\n     * is called.\n     * <p>This method only affects the behavior of the default EGLContexFactory and the\n     * default EGLConfigChooser. If\n     * {@link #setEGLContextFactory(EGLContextFactory)} has been called, then the supplied\n     * EGLContextFactory is responsible for creating an OpenGL ES 2.0-compatible context.\n     * If\n     * {@link #setEGLConfigChooser(EGLConfigChooser)} has been called, then the supplied\n     * EGLConfigChooser is responsible for choosing an OpenGL ES 2.0-compatible config.\n     *\n     * @param version The EGLContext client version to choose. Use 2 for OpenGL ES 2.0\n     */\n    public void setEGLContextClientVersion(int version) {\n        checkRenderThreadState();\n        eglContextClientVersion = version;\n    }\n\n    /**\n     * Set the rendering mode. When renderMode is\n     * RENDERMODE_CONTINUOUSLY, the renderer is called\n     * repeatedly to re-render the scene. When renderMode\n     * is RENDERMODE_WHEN_DIRTY, the renderer only rendered when the surface\n     * is created, or when {@link #requestRender} is called. Defaults to RENDERMODE_CONTINUOUSLY.\n     * <p>\n     * Using RENDERMODE_WHEN_DIRTY can improve battery life and overall system performance\n     * by allowing the GPU and CPU to idle when the view does not need to be updated.\n     * <p>\n     * This method can only be called after {@link #setRenderer(Renderer)}\n     *\n     * @param renderMode one of the RENDERMODE_X constants\n     * @see #RENDERMODE_CONTINUOUSLY\n     * @see #RENDERMODE_WHEN_DIRTY\n     */\n    public void setRenderMode(int renderMode) {\n        glThread.setRenderMode(renderMode);\n    }\n\n    /**\n     * Get the current rendering mode. May be called\n     * from any thread. Must not be called before a renderer has been set.\n     *\n     * @return the current rendering mode.\n     * @see #RENDERMODE_CONTINUOUSLY\n     * @see #RENDERMODE_WHEN_DIRTY\n     */\n    public int getRenderMode() {\n        return glThread.getRenderMode();\n    }\n\n    /**\n     * Request that the renderer render a frame.\n     * This method is typically used when the render mode has been set to\n     * {@link #RENDERMODE_WHEN_DIRTY}, so that frames are only rendered on demand.\n     * May be called\n     * from any thread. Must not be called before a renderer has been set.\n     */\n    public void requestRender() {\n        glThread.requestRender();\n    }\n\n    /**\n     * This method is part of the SurfaceHolder.Callback interface, and is\n     * not normally called or subclassed by clients of GLTextureView.\n     */\n    public void surfaceCreated(SurfaceTexture texture) {\n        glThread.surfaceCreated();\n    }\n\n    /**\n     * This method is part of the SurfaceHolder.Callback interface, and is\n     * not normally called or subclassed by clients of GLTextureView.\n     */\n    public void surfaceDestroyed(SurfaceTexture texture) {\n        // Surface will be destroyed when we return\n        glThread.surfaceDestroyed();\n    }\n\n    /**\n     * This method is part of the SurfaceHolder.Callback interface, and is\n     * not normally called or subclassed by clients of GLTextureView.\n     */\n    public void surfaceChanged(SurfaceTexture texture, int format, int w, int h) {\n        glThread.onWindowResize(w, h);\n    }\n\n    /**\n     * Inform the view that the activity is paused. The owner of this view must\n     * call this method when the activity is paused. Calling this method will\n     * pause the rendering thread.\n     * Must not be called before a renderer has been set.\n     */\n    public void onPause() {\n        glThread.onPause();\n    }\n\n    /**\n     * Inform the view that the activity is resumed. The owner of this view must\n     * call this method when the activity is resumed. Calling this method will\n     * recreate the OpenGL display and resume the rendering\n     * thread.\n     * Must not be called before a renderer has been set.\n     */\n    public void onResume() {\n        glThread.onResume();\n    }\n\n    /**\n     * Queue a runnable to be run on the GL rendering thread. This can be used\n     * to communicate with the Renderer on the rendering thread.\n     * Must not be called before a renderer has been set.\n     *\n     * @param r the runnable to be run on the GL rendering thread.\n     */\n    public void queueEvent(Runnable r) {\n        glThread.queueEvent(r);\n    }\n\n    /**\n     * This method is used as part of the View class and is not normally\n     * called or subclassed by clients of GLTextureView.\n     */\n    @Override\n    protected void onAttachedToWindow() {\n        super.onAttachedToWindow();\n        if (LOG_ATTACH_DETACH) {\n            Log.d(TAG, \"onAttachedToWindow reattach =\" + detached);\n        }\n        if (detached && (renderer != null)) {\n            int renderMode = RENDERMODE_CONTINUOUSLY;\n            if (glThread != null) {\n                renderMode = glThread.getRenderMode();\n            }\n            glThread = new GLThread(mThisWeakRef);\n            if (renderMode != RENDERMODE_CONTINUOUSLY) {\n                glThread.setRenderMode(renderMode);\n            }\n            glThread.start();\n        }\n        detached = false;\n    }\n\n    /**\n     * This method is used as part of the View class and is not normally\n     * called or subclassed by clients of GLTextureView.\n     * Must not be called before a renderer has been set.\n     */\n    @Override\n    protected void onDetachedFromWindow() {\n        if (LOG_ATTACH_DETACH) {\n            Log.d(TAG, \"onDetachedFromWindow\");\n        }\n        if (glThread != null) {\n            glThread.requestExitAndWait();\n        }\n        detached = true;\n        super.onDetachedFromWindow();\n    }\n\n    public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,\n                               int oldTop, int oldRight, int oldBottom) {\n        surfaceChanged(getSurfaceTexture(), 0, right - left, bottom - top);\n    }\n\n    public void addSurfaceTextureListener(SurfaceTextureListener listener) {\n        surfaceTextureListeners.add(listener);\n    }\n\n    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {\n        surfaceCreated(surface);\n        surfaceChanged(surface, 0, width, height);\n\n        for (SurfaceTextureListener l : surfaceTextureListeners) {\n            l.onSurfaceTextureAvailable(surface, width, height);\n        }\n    }\n\n    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {\n        surfaceChanged(surface, 0, width, height);\n\n        for (SurfaceTextureListener l : surfaceTextureListeners) {\n            l.onSurfaceTextureSizeChanged(surface, width, height);\n        }\n    }\n\n    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {\n        surfaceDestroyed(surface);\n\n        for (SurfaceTextureListener l : surfaceTextureListeners) {\n            l.onSurfaceTextureDestroyed(surface);\n        }\n\n        return true;\n    }\n\n    public void onSurfaceTextureUpdated(SurfaceTexture surface) {\n        requestRender();\n\n        for (SurfaceTextureListener l : surfaceTextureListeners) {\n            l.onSurfaceTextureUpdated(surface);\n        }\n    }\n\n    // ----------------------------------------------------------------------\n\n    /**\n     * An interface used to wrap a GL interface.\n     * <p>Typically\n     * used for implementing debugging and tracing on top of the default\n     * GL interface. You would typically use this by creating your own class\n     * that implemented all the GL methods by delegating to another GL instance.\n     * Then you could add your own behavior before or after calling the\n     * delegate. All the GLWrapper would do was instantiate and return the\n     * wrapper GL instance:\n     * <pre class=\"prettyprint\">\n     * class MyGLWrapper implements GLWrapper {\n     * GL wrap(GL gl) {\n     * return new MyGLImplementation(gl);\n     * }\n     * static class MyGLImplementation implements GL,GL10,GL11,... {\n     * ...\n     * }\n     * }\n     * </pre>\n     *\n     * @see #setGLWrapper(GLWrapper)\n     */\n    public interface GLWrapper {\n        /**\n         * Wraps a gl interface in another gl interface.\n         *\n         * @param gl a GL interface that is to be wrapped.\n         * @return either the input argument or another GL object that wraps the input argument.\n         */\n        GL wrap(GL gl);\n    }\n\n    /**\n     * A generic renderer interface.\n     * <p>\n     * The renderer is responsible for making OpenGL calls to render a frame.\n     * <p>\n     * GLTextureView clients typically create their own classes that implement\n     * this interface, and then call {@link GLTextureView#setRenderer} to\n     * register the renderer with the GLTextureView.\n     * <p>\n     *\n     * <div class=\"special reference\">\n     * <h3>Developer Guides</h3>\n     * <p>For more information about how to use OpenGL, read the\n     * <a href=\"{@docRoot}guide/topics/graphics/opengl.html\">OpenGL</a> developer guide.</p>\n     * </div>\n     *\n     * <h3>Threading</h3>\n     * The renderer will be called on a separate thread, so that rendering\n     * performance is decoupled from the UI thread. Clients typically need to\n     * communicate with the renderer from the UI thread, because that's where\n     * input events are received. Clients can communicate using any of the\n     * standard Java techniques for cross-thread communication, or they can\n     * use the {@link GLTextureView#queueEvent(Runnable)} convenience method.\n     * <p>\n     * <h3>EGL Context Lost</h3>\n     * There are situations where the EGL rendering context will be lost. This\n     * typically happens when device wakes up after going to sleep. When\n     * the EGL context is lost, all OpenGL resources (such as textures) that are\n     * associated with that context will be automatically deleted. In order to\n     * keep rendering correctly, a renderer must recreate any lost resources\n     * that it still needs. The {@link #onSurfaceCreated(javax.microedition.khronos.opengles.GL10,\n     * javax.microedition.khronos.egl.EGLConfig)} method\n     * is a convenient place to do this.\n     *\n     * @see #setRenderer(Renderer)\n     */\n    public interface Renderer {\n        /**\n         * Called when the surface is created or recreated.\n         * <p>\n         * Called when the rendering thread\n         * starts and whenever the EGL context is lost. The EGL context will typically\n         * be lost when the Android device awakes after going to sleep.\n         * <p>\n         * Since this method is called at the beginning of rendering, as well as\n         * every time the EGL context is lost, this method is a convenient place to put\n         * code to create resources that need to be created when the rendering\n         * starts, and that need to be recreated when the EGL context is lost.\n         * Textures are an example of a resource that you might want to create\n         * here.\n         * <p>\n         * Note that when the EGL context is lost, all OpenGL resources associated\n         * with that context will be automatically deleted. You do not need to call\n         * the corresponding \"glDelete\" methods such as glDeleteTextures to\n         * manually delete these lost resources.\n         * <p>\n         *\n         * @param gl     the GL interface. Use <code>instanceof</code> to\n         *               test if the interface supports GL11 or higher interfaces.\n         * @param config the EGLConfig of the created surface. Can be used\n         *               to create matching pbuffers.\n         */\n        void onSurfaceCreated(GL10 gl, EGLConfig config);\n\n        /**\n         * Called when the surface changed size.\n         * <p>\n         * Called after the surface is created and whenever\n         * the OpenGL ES surface size changes.\n         * <p>\n         * Typically you will set your viewport here. If your camera\n         * is fixed then you could also set your projection matrix here:\n         * <pre class=\"prettyprint\">\n         * void onSurfaceChanged(GL10 gl, int width, int height) {\n         * gl.glViewport(0, 0, width, height);\n         * // for a fixed camera, set the projection too\n         * float ratio = (float) width / height;\n         * gl.glMatrixMode(GL10.GL_PROJECTION);\n         * gl.glLoadIdentity();\n         * gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);\n         * }\n         * </pre>\n         *\n         * @param gl the GL interface. Use <code>instanceof</code> to\n         *           test if the interface supports GL11 or higher interfaces.\n         */\n        void onSurfaceChanged(GL10 gl, int width, int height);\n\n        /**\n         * Called to draw the current frame.\n         * <p>\n         * This method is responsible for drawing the current frame.\n         * <p>\n         * The implementation of this method typically looks like this:\n         * <pre class=\"prettyprint\">\n         * void onDrawFrame(GL10 gl) {\n         * gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);\n         * //... other gl calls to render the scene ...\n         * }\n         * </pre>\n         *\n         * @param gl the GL interface. Use <code>instanceof</code> to\n         *           test if the interface supports GL11 or higher interfaces.\n         */\n        void onDrawFrame(GL10 gl);\n    }\n\n    /**\n     * An interface for customizing the eglCreateContext and eglDestroyContext calls.\n     * <p>\n     * This interface must be implemented by clients wishing to call\n     * {@link GLTextureView#setEGLContextFactory(EGLContextFactory)}\n     */\n    public interface EGLContextFactory {\n        EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig);\n\n        void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context);\n    }\n\n    private class DefaultContextFactory implements EGLContextFactory {\n        private int EGL_CONTEXT_CLIENT_VERSION = 0x3098;\n\n        public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig config) {\n            int[] attrib_list = {\n                    EGL_CONTEXT_CLIENT_VERSION, eglContextClientVersion, EGL10.EGL_NONE\n            };\n\n            return egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT,\n                    eglContextClientVersion != 0 ? attrib_list : null);\n        }\n\n        public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) {\n            if (!egl.eglDestroyContext(display, context)) {\n                Log.e(\"DefaultContextFactory\", \"display:\" + display + \" context: \" + context);\n                if (LOG_THREADS) {\n                    Log.i(\"DefaultContextFactory\", \"tid=\" + Thread.currentThread().getId());\n                }\n                EglHelper.throwEglException(\"eglDestroyContex\", egl.eglGetError());\n            }\n        }\n    }\n\n    /**\n     * An interface for customizing the eglCreateWindowSurface and eglDestroySurface calls.\n     * <p>\n     * This interface must be implemented by clients wishing to call\n     * {@link GLTextureView#setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory)}\n     */\n    public interface EGLWindowSurfaceFactory {\n        /**\n         * @return null if the surface cannot be constructed.\n         */\n        EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display, EGLConfig config,\n                                       Object nativeWindow);\n\n        void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface);\n    }\n\n    private static class DefaultWindowSurfaceFactory implements EGLWindowSurfaceFactory {\n\n        public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display, EGLConfig config,\n                                              Object nativeWindow) {\n            EGLSurface result = null;\n            try {\n                result = egl.eglCreateWindowSurface(display, config, nativeWindow, null);\n            } catch (IllegalArgumentException e) {\n                // This exception indicates that the surface flinger surface\n                // is not valid. This can happen if the surface flinger surface has\n                // been torn down, but the application has not yet been\n                // notified via SurfaceHolder.Callback.surfaceDestroyed.\n                // In theory the application should be notified first,\n                // but in practice sometimes it is not. See b/4588890\n                Log.e(TAG, \"eglCreateWindowSurface\", e);\n            }\n            return result;\n        }\n\n        public void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface) {\n            egl.eglDestroySurface(display, surface);\n        }\n    }\n\n    /**\n     * An interface for choosing an EGLConfig configuration from a list of\n     * potential configurations.\n     * <p>\n     * This interface must be implemented by clients wishing to call\n     * {@link GLTextureView#setEGLConfigChooser(EGLConfigChooser)}\n     */\n    public interface EGLConfigChooser {\n        /**\n         * Choose a configuration from the list. Implementors typically\n         * implement this method by calling\n         * {@link EGL10#eglChooseConfig} and iterating through the results. Please consult the\n         * EGL specification available from The Khronos Group to learn how to call eglChooseConfig.\n         *\n         * @param egl     the EGL10 for the current display.\n         * @param display the current display.\n         * @return the chosen configuration.\n         */\n        EGLConfig chooseConfig(EGL10 egl, EGLDisplay display);\n    }\n\n    private abstract class BaseConfigChooser implements EGLConfigChooser {\n        public BaseConfigChooser(int[] configSpec) {\n            mConfigSpec = filterConfigSpec(configSpec);\n        }\n\n        public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {\n            int[] num_config = new int[1];\n            if (!egl.eglChooseConfig(display, mConfigSpec, null, 0, num_config)) {\n                throw new IllegalArgumentException(\"eglChooseConfig failed\");\n            }\n\n            int numConfigs = num_config[0];\n\n            if (numConfigs <= 0) {\n                throw new IllegalArgumentException(\"No configs match configSpec\");\n            }\n\n            EGLConfig[] configs = new EGLConfig[numConfigs];\n            if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs, num_config)) {\n                throw new IllegalArgumentException(\"eglChooseConfig#2 failed\");\n            }\n            EGLConfig config = chooseConfig(egl, display, configs);\n            if (config == null) {\n                throw new IllegalArgumentException(\"No config chosen\");\n            }\n            return config;\n        }\n\n        abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs);\n\n        protected int[] mConfigSpec;\n\n        private int[] filterConfigSpec(int[] configSpec) {\n            if (eglContextClientVersion != 2) {\n                return configSpec;\n            }\n            /* We know none of the subclasses define EGL_RENDERABLE_TYPE.\n             * And we know the configSpec is well formed.\n             */\n            int len = configSpec.length;\n            int[] newConfigSpec = new int[len + 2];\n            System.arraycopy(configSpec, 0, newConfigSpec, 0, len - 1);\n            newConfigSpec[len - 1] = EGL10.EGL_RENDERABLE_TYPE;\n            newConfigSpec[len] = 0x0004; /* EGL_OPENGL_ES2_BIT */\n            newConfigSpec[len + 1] = EGL10.EGL_NONE;\n            return newConfigSpec;\n        }\n    }\n\n    /**\n     * Choose a configuration with exactly the specified r,g,b,a sizes,\n     * and at least the specified depth and stencil sizes.\n     */\n    private class ComponentSizeChooser extends BaseConfigChooser {\n        public ComponentSizeChooser(int redSize, int greenSize, int blueSize, int alphaSize,\n                                    int depthSize, int stencilSize) {\n            super(new int[]{\n                    EGL10.EGL_RED_SIZE, redSize, EGL10.EGL_GREEN_SIZE, greenSize, EGL10.EGL_BLUE_SIZE,\n                    blueSize, EGL10.EGL_ALPHA_SIZE, alphaSize, EGL10.EGL_DEPTH_SIZE, depthSize,\n                    EGL10.EGL_STENCIL_SIZE, stencilSize, EGL10.EGL_NONE\n            });\n            value = new int[1];\n            this.redSize = redSize;\n            this.greenSize = greenSize;\n            this.blueSize = blueSize;\n            this.alphaSize = alphaSize;\n            this.depthSize = depthSize;\n            this.stencilSize = stencilSize;\n        }\n\n        @Override\n        public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs) {\n            for (EGLConfig config : configs) {\n                int d = findConfigAttrib(egl, display, config, EGL10.EGL_DEPTH_SIZE, 0);\n                int s = findConfigAttrib(egl, display, config, EGL10.EGL_STENCIL_SIZE, 0);\n                if ((d >= depthSize) && (s >= stencilSize)) {\n                    int r = findConfigAttrib(egl, display, config, EGL10.EGL_RED_SIZE, 0);\n                    int g = findConfigAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE, 0);\n                    int b = findConfigAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE, 0);\n                    int a = findConfigAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE, 0);\n                    if ((r == redSize) && (g == greenSize) && (b == blueSize) && (a == alphaSize)) {\n                        return config;\n                    }\n                }\n            }\n            return null;\n        }\n\n        private int findConfigAttrib(EGL10 egl, EGLDisplay display, EGLConfig config, int attribute,\n                                     int defaultValue) {\n\n            if (egl.eglGetConfigAttrib(display, config, attribute, value)) {\n                return value[0];\n            }\n            return defaultValue;\n        }\n\n        private int[] value;\n        // Subclasses can adjust these values:\n        protected int redSize;\n        protected int greenSize;\n        protected int blueSize;\n        protected int alphaSize;\n        protected int depthSize;\n        protected int stencilSize;\n    }\n\n    /**\n     * This class will choose a RGB_888 surface with\n     * or without a depth buffer.\n     */\n    private class SimpleEGLConfigChooser extends ComponentSizeChooser {\n        public SimpleEGLConfigChooser(boolean withDepthBuffer) {\n            super(8, 8, 8, 0, withDepthBuffer ? 16 : 0, 0);\n        }\n    }\n\n    /**\n     * An EGL helper class.\n     */\n\n    private static class EglHelper {\n        public EglHelper(WeakReference<GLTextureView> glTextureViewWeakReference) {\n            this.glTextureViewWeakRef = glTextureViewWeakReference;\n        }\n\n        /**\n         * Initialize EGL for a given configuration spec.\n         */\n        public void start() {\n            if (LOG_EGL) {\n                Log.w(\"EglHelper\", \"start() tid=\" + Thread.currentThread().getId());\n            }\n            /*\n             * Get an EGL instance\n             */\n            egl = (EGL10) EGLContext.getEGL();\n\n            /*\n             * Get to the default display.\n             */\n            eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);\n\n            if (eglDisplay == EGL10.EGL_NO_DISPLAY) {\n                throw new RuntimeException(\"eglGetDisplay failed\");\n            }\n\n            /*\n             * We can now initialize EGL for that display\n             */\n            int[] version = new int[2];\n            if (!egl.eglInitialize(eglDisplay, version)) {\n                throw new RuntimeException(\"eglInitialize failed\");\n            }\n            GLTextureView view = glTextureViewWeakRef.get();\n            if (view == null) {\n                eglConfig = null;\n                eglContext = null;\n            } else {\n                eglConfig = view.eglConfigChooser.chooseConfig(egl, eglDisplay);\n\n                /*\n                 * Create an EGL context. We want to do this as rarely as we can, because an\n                 * EGL context is a somewhat heavy object.\n                 */\n                eglContext = view.eglContextFactory.createContext(egl, eglDisplay, eglConfig);\n            }\n            if (eglContext == null || eglContext == EGL10.EGL_NO_CONTEXT) {\n                eglContext = null;\n                throwEglException(\"createContext\");\n            }\n            if (LOG_EGL) {\n                Log.w(\"EglHelper\",\n                        \"createContext \" + eglContext + \" tid=\" + Thread.currentThread().getId());\n            }\n\n            eglSurface = null;\n        }\n\n        /**\n         * Create an egl surface for the current SurfaceHolder surface. If a surface\n         * already exists, destroy it before creating the new surface.\n         *\n         * @return true if the surface was created successfully.\n         */\n        public boolean createSurface() {\n            if (LOG_EGL) {\n                Log.w(\"EglHelper\", \"createSurface()  tid=\" + Thread.currentThread().getId());\n            }\n            /*\n             * Check preconditions.\n             */\n            if (egl == null) {\n                throw new RuntimeException(\"egl not initialized\");\n            }\n            if (eglDisplay == null) {\n                throw new RuntimeException(\"eglDisplay not initialized\");\n            }\n            if (eglConfig == null) {\n                throw new RuntimeException(\"eglConfig not initialized\");\n            }\n\n            /*\n             *  The window size has changed, so we need to create a new\n             *  surface.\n             */\n            destroySurfaceImp();\n\n            /*\n             * Create an EGL surface we can render into.\n             */\n            GLTextureView view = glTextureViewWeakRef.get();\n            if (view != null) {\n                eglSurface = view.eglWindowSurfaceFactory.createWindowSurface(egl, eglDisplay, eglConfig,\n                        view.getSurfaceTexture());\n            } else {\n                eglSurface = null;\n            }\n\n            if (eglSurface == null || eglSurface == EGL10.EGL_NO_SURFACE) {\n                int error = egl.eglGetError();\n                if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {\n                    Log.e(\"EglHelper\", \"createWindowSurface returned EGL_BAD_NATIVE_WINDOW.\");\n                }\n                return false;\n            }\n\n            /*\n             * Before we can issue GL commands, we need to make sure\n             * the context is current and bound to a surface.\n             */\n            if (!egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) {\n                /*\n                 * Could not make the context current, probably because the underlying\n                 * TextureView surface has been destroyed.\n                 */\n                logEglErrorAsWarning(\"EGLHelper\", \"eglMakeCurrent\", egl.eglGetError());\n                return false;\n            }\n\n            return true;\n        }\n\n        /**\n         * Create a GL object for the current EGL context.\n         */\n        GL createGL() {\n\n            GL gl = eglContext.getGL();\n            GLTextureView view = glTextureViewWeakRef.get();\n            if (view != null) {\n                if (view.glWrapper != null) {\n                    gl = view.glWrapper.wrap(gl);\n                }\n\n                if ((view.debugFlags & (DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS)) != 0) {\n                    int configFlags = 0;\n                    Writer log = null;\n                    if ((view.debugFlags & DEBUG_CHECK_GL_ERROR) != 0) {\n                        configFlags |= GLDebugHelper.CONFIG_CHECK_GL_ERROR;\n                    }\n                    if ((view.debugFlags & DEBUG_LOG_GL_CALLS) != 0) {\n                        log = new LogWriter();\n                    }\n                    gl = GLDebugHelper.wrap(gl, configFlags, log);\n                }\n            }\n            return gl;\n        }\n\n        /**\n         * Display the current render surface.\n         *\n         * @return the EGL error code from eglSwapBuffers.\n         */\n        public int swap() {\n            if (!egl.eglSwapBuffers(eglDisplay, eglSurface)) {\n                return egl.eglGetError();\n            }\n            return EGL10.EGL_SUCCESS;\n        }\n\n        public void destroySurface() {\n            if (LOG_EGL) {\n                Log.w(\"EglHelper\", \"destroySurface()  tid=\" + Thread.currentThread().getId());\n            }\n            destroySurfaceImp();\n        }\n\n        private void destroySurfaceImp() {\n            if (eglSurface != null && eglSurface != EGL10.EGL_NO_SURFACE) {\n                egl.eglMakeCurrent(eglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE,\n                        EGL10.EGL_NO_CONTEXT);\n                GLTextureView view = glTextureViewWeakRef.get();\n                if (view != null) {\n                    view.eglWindowSurfaceFactory.destroySurface(egl, eglDisplay, eglSurface);\n                }\n                eglSurface = null;\n            }\n        }\n\n        public void finish() {\n            if (LOG_EGL) {\n                Log.w(\"EglHelper\", \"finish() tid=\" + Thread.currentThread().getId());\n            }\n            if (eglContext != null) {\n                GLTextureView view = glTextureViewWeakRef.get();\n                if (view != null) {\n                    view.eglContextFactory.destroyContext(egl, eglDisplay, eglContext);\n                }\n                eglContext = null;\n            }\n            if (eglDisplay != null) {\n                egl.eglTerminate(eglDisplay);\n                eglDisplay = null;\n            }\n        }\n\n        private void throwEglException(String function) {\n            throwEglException(function, egl.eglGetError());\n        }\n\n        public static void throwEglException(String function, int error) {\n            String message = formatEglError(function, error);\n            if (LOG_THREADS) {\n                Log.e(\"EglHelper\",\n                        \"throwEglException tid=\" + Thread.currentThread().getId() + \" \" + message);\n            }\n            throw new RuntimeException(message);\n        }\n\n        public static void logEglErrorAsWarning(String tag, String function, int error) {\n            Log.w(tag, formatEglError(function, error));\n        }\n\n        public static String formatEglError(String function, int error) {\n            return function + \" failed: \" + error;\n        }\n\n        private WeakReference<GLTextureView> glTextureViewWeakRef;\n        EGL10 egl;\n        EGLDisplay eglDisplay;\n        EGLSurface eglSurface;\n        EGLConfig eglConfig;\n        EGLContext eglContext;\n    }\n\n    /**\n     * A generic GL Thread. Takes care of initializing EGL and GL. Delegates\n     * to a Renderer instance to do the actual drawing. Can be configured to\n     * render continuously or on request.\n     * <p>\n     * All potentially blocking synchronization is done through the\n     * glThreadManager object. This avoids multiple-lock ordering issues.\n     */\n    static class GLThread extends Thread {\n        GLThread(WeakReference<GLTextureView> glTextureViewWeakRef) {\n            super();\n            width = 0;\n            height = 0;\n            requestRender = true;\n            renderMode = RENDERMODE_CONTINUOUSLY;\n            this.glTextureViewWeakRef = glTextureViewWeakRef;\n        }\n\n        @Override\n        public void run() {\n            setName(\"GLThread \" + getId());\n            if (LOG_THREADS) {\n                Log.i(\"GLThread\", \"starting tid=\" + getId());\n            }\n\n            try {\n                guardedRun();\n            } catch (InterruptedException e) {\n                // fall thru and exit normally\n            } finally {\n                glThreadManager.threadExiting(this);\n            }\n        }\n\n        /*\n         * This private method should only be called inside a\n         * synchronized(glThreadManager) block.\n         */\n        private void stopEglSurfaceLocked() {\n            if (haveEglSurface) {\n                haveEglSurface = false;\n                eglHelper.destroySurface();\n            }\n        }\n\n        /*\n         * This private method should only be called inside a\n         * synchronized(glThreadManager) block.\n         */\n        private void stopEglContextLocked() {\n            if (haveEglContext) {\n                eglHelper.finish();\n                haveEglContext = false;\n                glThreadManager.releaseEglContextLocked(this);\n            }\n        }\n\n        private void guardedRun() throws InterruptedException {\n            eglHelper = new EglHelper(glTextureViewWeakRef);\n            haveEglContext = false;\n            haveEglSurface = false;\n            try {\n                GL10 gl = null;\n                boolean createEglContext = false;\n                boolean createEglSurface = false;\n                boolean createGlInterface = false;\n                boolean lostEglContext = false;\n                boolean sizeChanged = false;\n                boolean wantRenderNotification = false;\n                boolean doRenderNotification = false;\n                boolean askedToReleaseEglContext = false;\n                int w = 0;\n                int h = 0;\n                Runnable event = null;\n\n                while (true) {\n                    synchronized (glThreadManager) {\n                        while (true) {\n                            if (shouldExit) {\n                                return;\n                            }\n\n                            if (!eventQueue.isEmpty()) {\n                                event = eventQueue.remove(0);\n                                break;\n                            }\n\n                            // Update the pause state.\n                            boolean pausing = false;\n                            if (paused != requestPaused) {\n                                pausing = requestPaused;\n                                paused = requestPaused;\n                                glThreadManager.notifyAll();\n                                if (LOG_PAUSE_RESUME) {\n                                    Log.i(\"GLThread\", \"paused is now \" + paused + \" tid=\" + getId());\n                                }\n                            }\n\n                            // Do we need to give up the EGL context?\n                            if (shouldReleaseEglContext) {\n                                if (LOG_SURFACE) {\n                                    Log.i(\"GLThread\", \"releasing EGL context because asked to tid=\" + getId());\n                                }\n                                stopEglSurfaceLocked();\n                                stopEglContextLocked();\n                                shouldReleaseEglContext = false;\n                                askedToReleaseEglContext = true;\n                            }\n\n                            // Have we lost the EGL context?\n                            if (lostEglContext) {\n                                stopEglSurfaceLocked();\n                                stopEglContextLocked();\n                                lostEglContext = false;\n                            }\n\n                            // When pausing, release the EGL surface:\n                            if (pausing && haveEglSurface) {\n                                if (LOG_SURFACE) {\n                                    Log.i(\"GLThread\", \"releasing EGL surface because paused tid=\" + getId());\n                                }\n                                stopEglSurfaceLocked();\n                            }\n\n                            // When pausing, optionally release the EGL Context:\n                            if (pausing && haveEglContext) {\n                                GLTextureView view = glTextureViewWeakRef.get();\n                                boolean preserveEglContextOnPause =\n                                        view == null ? false : view.preserveEGLContextOnPause;\n                                if (!preserveEglContextOnPause\n                                        || glThreadManager.shouldReleaseEGLContextWhenPausing()) {\n                                    stopEglContextLocked();\n                                    if (LOG_SURFACE) {\n                                        Log.i(\"GLThread\", \"releasing EGL context because paused tid=\" + getId());\n                                    }\n                                }\n                            }\n\n                            // When pausing, optionally terminate EGL:\n                            if (pausing) {\n                                if (glThreadManager.shouldTerminateEGLWhenPausing()) {\n                                    eglHelper.finish();\n                                    if (LOG_SURFACE) {\n                                        Log.i(\"GLThread\", \"terminating EGL because paused tid=\" + getId());\n                                    }\n                                }\n                            }\n\n                            // Have we lost the TextureView surface?\n                            if ((!hasSurface) && (!waitingForSurface)) {\n                                if (LOG_SURFACE) {\n                                    Log.i(\"GLThread\", \"noticed textureView surface lost tid=\" + getId());\n                                }\n                                if (haveEglSurface) {\n                                    stopEglSurfaceLocked();\n                                }\n                                waitingForSurface = true;\n                                surfaceIsBad = false;\n                                glThreadManager.notifyAll();\n                            }\n\n                            // Have we acquired the surface view surface?\n                            if (hasSurface && waitingForSurface) {\n                                if (LOG_SURFACE) {\n                                    Log.i(\"GLThread\", \"noticed textureView surface acquired tid=\" + getId());\n                                }\n                                waitingForSurface = false;\n                                glThreadManager.notifyAll();\n                            }\n\n                            if (doRenderNotification) {\n                                if (LOG_SURFACE) {\n                                    Log.i(\"GLThread\", \"sending render notification tid=\" + getId());\n                                }\n                                wantRenderNotification = false;\n                                doRenderNotification = false;\n                                renderComplete = true;\n                                glThreadManager.notifyAll();\n                            }\n\n                            // Ready to draw?\n                            if (readyToDraw()) {\n\n                                // If we don't have an EGL context, try to acquire one.\n                                if (!haveEglContext) {\n                                    if (askedToReleaseEglContext) {\n                                        askedToReleaseEglContext = false;\n                                    } else if (glThreadManager.tryAcquireEglContextLocked(this)) {\n                                        try {\n                                            eglHelper.start();\n                                        } catch (RuntimeException t) {\n                                            glThreadManager.releaseEglContextLocked(this);\n                                            throw t;\n                                        }\n                                        haveEglContext = true;\n                                        createEglContext = true;\n\n                                        glThreadManager.notifyAll();\n                                    }\n                                }\n\n                                if (haveEglContext && !haveEglSurface) {\n                                    haveEglSurface = true;\n                                    createEglSurface = true;\n                                    createGlInterface = true;\n                                    sizeChanged = true;\n                                }\n\n                                if (haveEglSurface) {\n                                    if (this.sizeChanged) {\n                                        sizeChanged = true;\n                                        w = width;\n                                        h = height;\n                                        wantRenderNotification = true;\n                                        if (LOG_SURFACE) {\n                                            Log.i(\"GLThread\", \"noticing that we want render notification tid=\" + getId());\n                                        }\n\n                                        // Destroy and recreate the EGL surface.\n                                        createEglSurface = true;\n\n                                        this.sizeChanged = false;\n                                    }\n                                    requestRender = false;\n                                    glThreadManager.notifyAll();\n                                    break;\n                                }\n                            }\n\n                            // By design, this is the only place in a GLThread thread where we wait().\n                            if (LOG_THREADS) {\n                                Log.i(\"GLThread\", \"waiting tid=\" + getId() + \" haveEglContext: \" + haveEglContext\n                                        + \" haveEglSurface: \" + haveEglSurface + \" paused: \" + paused + \" hasSurface: \"\n                                        + hasSurface + \" surfaceIsBad: \" + surfaceIsBad + \" waitingForSurface: \"\n                                        + waitingForSurface + \" width: \" + width + \" height: \" + height\n                                        + \" requestRender: \" + requestRender + \" renderMode: \" + renderMode);\n                            }\n                            glThreadManager.wait();\n                        }\n                    } // end of synchronized(glThreadManager)\n\n                    if (event != null) {\n                        event.run();\n                        event = null;\n                        continue;\n                    }\n\n                    if (createEglSurface) {\n                        if (LOG_SURFACE) {\n                            Log.w(\"GLThread\", \"egl createSurface\");\n                        }\n                        if (!eglHelper.createSurface()) {\n                            synchronized (glThreadManager) {\n                                surfaceIsBad = true;\n                                glThreadManager.notifyAll();\n                            }\n                            continue;\n                        }\n                        createEglSurface = false;\n                    }\n\n                    if (createGlInterface) {\n                        gl = (GL10) eglHelper.createGL();\n\n                        glThreadManager.checkGLDriver(gl);\n                        createGlInterface = false;\n                    }\n\n                    if (createEglContext) {\n                        if (LOG_RENDERER) {\n                            Log.w(\"GLThread\", \"onSurfaceCreated\");\n                        }\n                        GLTextureView view = glTextureViewWeakRef.get();\n                        if (view != null) {\n                            view.renderer.onSurfaceCreated(gl, eglHelper.eglConfig);\n                        }\n                        createEglContext = false;\n                    }\n\n                    if (sizeChanged) {\n                        if (LOG_RENDERER) {\n                            Log.w(\"GLThread\", \"onSurfaceChanged(\" + w + \", \" + h + \")\");\n                        }\n                        GLTextureView view = glTextureViewWeakRef.get();\n                        if (view != null) {\n                            view.renderer.onSurfaceChanged(gl, w, h);\n                        }\n                        sizeChanged = false;\n                    }\n\n                    if (LOG_RENDERER_DRAW_FRAME) {\n                        Log.w(\"GLThread\", \"onDrawFrame tid=\" + getId());\n                    }\n                    {\n                        GLTextureView view = glTextureViewWeakRef.get();\n                        if (view != null) {\n                            view.renderer.onDrawFrame(gl);\n                        }\n                    }\n                    int swapError = eglHelper.swap();\n                    switch (swapError) {\n                        case EGL10.EGL_SUCCESS:\n                            break;\n                        case EGL11.EGL_CONTEXT_LOST:\n                            if (LOG_SURFACE) {\n                                Log.i(\"GLThread\", \"egl context lost tid=\" + getId());\n                            }\n                            lostEglContext = true;\n                            break;\n                        default:\n                            // Other errors typically mean that the current surface is bad,\n                            // probably because the TextureView surface has been destroyed,\n                            // but we haven't been notified yet.\n                            // Log the error to help developers understand why rendering stopped.\n                            EglHelper.logEglErrorAsWarning(\"GLThread\", \"eglSwapBuffers\", swapError);\n\n                            synchronized (glThreadManager) {\n                                surfaceIsBad = true;\n                                glThreadManager.notifyAll();\n                            }\n                            break;\n                    }\n\n                    if (wantRenderNotification) {\n                        doRenderNotification = true;\n                    }\n                }\n            } finally {\n                /*\n                 * clean-up everything...\n                 */\n                synchronized (glThreadManager) {\n                    stopEglSurfaceLocked();\n                    stopEglContextLocked();\n                }\n            }\n        }\n\n        public boolean ableToDraw() {\n            return haveEglContext && haveEglSurface && readyToDraw();\n        }\n\n        private boolean readyToDraw() {\n            return (!paused) && hasSurface && (!surfaceIsBad) && (width > 0) && (height > 0) && (\n                    requestRender || (renderMode == RENDERMODE_CONTINUOUSLY));\n        }\n\n        public void setRenderMode(int renderMode) {\n            if (!((RENDERMODE_WHEN_DIRTY <= renderMode) && (renderMode <= RENDERMODE_CONTINUOUSLY))) {\n                throw new IllegalArgumentException(\"renderMode\");\n            }\n            synchronized (glThreadManager) {\n                this.renderMode = renderMode;\n                glThreadManager.notifyAll();\n            }\n        }\n\n        public int getRenderMode() {\n            synchronized (glThreadManager) {\n                return renderMode;\n            }\n        }\n\n        public void requestRender() {\n            synchronized (glThreadManager) {\n                requestRender = true;\n                glThreadManager.notifyAll();\n            }\n        }\n\n        public void surfaceCreated() {\n            synchronized (glThreadManager) {\n                if (LOG_THREADS) {\n                    Log.i(\"GLThread\", \"surfaceCreated tid=\" + getId());\n                }\n                hasSurface = true;\n                glThreadManager.notifyAll();\n                while ((waitingForSurface) && (!exited)) {\n                    try {\n                        glThreadManager.wait();\n                    } catch (InterruptedException e) {\n                        Thread.currentThread().interrupt();\n                    }\n                }\n            }\n        }\n\n        public void surfaceDestroyed() {\n            synchronized (glThreadManager) {\n                if (LOG_THREADS) {\n                    Log.i(\"GLThread\", \"surfaceDestroyed tid=\" + getId());\n                }\n                hasSurface = false;\n                glThreadManager.notifyAll();\n                while ((!waitingForSurface) && (!exited)) {\n                    try {\n                        glThreadManager.wait();\n                    } catch (InterruptedException e) {\n                        Thread.currentThread().interrupt();\n                    }\n                }\n            }\n        }\n\n        public void onPause() {\n            synchronized (glThreadManager) {\n                if (LOG_PAUSE_RESUME) {\n                    Log.i(\"GLThread\", \"onPause tid=\" + getId());\n                }\n                requestPaused = true;\n                glThreadManager.notifyAll();\n                while ((!exited) && (!paused)) {\n                    if (LOG_PAUSE_RESUME) {\n                        Log.i(\"Main thread\", \"onPause waiting for paused.\");\n                    }\n                    try {\n                        glThreadManager.wait();\n                    } catch (InterruptedException ex) {\n                        Thread.currentThread().interrupt();\n                    }\n                }\n            }\n        }\n\n        public void onResume() {\n            synchronized (glThreadManager) {\n                if (LOG_PAUSE_RESUME) {\n                    Log.i(\"GLThread\", \"onResume tid=\" + getId());\n                }\n                requestPaused = false;\n                requestRender = true;\n                renderComplete = false;\n                glThreadManager.notifyAll();\n                while ((!exited) && paused && (!renderComplete)) {\n                    if (LOG_PAUSE_RESUME) {\n                        Log.i(\"Main thread\", \"onResume waiting for !paused.\");\n                    }\n                    try {\n                        glThreadManager.wait();\n                    } catch (InterruptedException ex) {\n                        Thread.currentThread().interrupt();\n                    }\n                }\n            }\n        }\n\n        public void onWindowResize(int w, int h) {\n            synchronized (glThreadManager) {\n                width = w;\n                height = h;\n                sizeChanged = true;\n                requestRender = true;\n                renderComplete = false;\n                glThreadManager.notifyAll();\n\n                // Wait for thread to react to resize and render a frame\n                while (!exited && !paused && !renderComplete && ableToDraw()) {\n                    if (LOG_SURFACE) {\n                        Log.i(\"Main thread\", \"onWindowResize waiting for render complete from tid=\" + getId());\n                    }\n                    try {\n                        glThreadManager.wait();\n                    } catch (InterruptedException ex) {\n                        Thread.currentThread().interrupt();\n                    }\n                }\n            }\n        }\n\n        public void requestExitAndWait() {\n            // don't call this from GLThread thread or it is a guaranteed\n            // deadlock!\n            synchronized (glThreadManager) {\n                shouldExit = true;\n                glThreadManager.notifyAll();\n                while (!exited) {\n                    try {\n                        glThreadManager.wait();\n                    } catch (InterruptedException ex) {\n                        Thread.currentThread().interrupt();\n                    }\n                }\n            }\n        }\n\n        public void requestReleaseEglContextLocked() {\n            shouldReleaseEglContext = true;\n            glThreadManager.notifyAll();\n        }\n\n        /**\n         * Queue an \"event\" to be run on the GL rendering thread.\n         *\n         * @param r the runnable to be run on the GL rendering thread.\n         */\n        public void queueEvent(Runnable r) {\n            if (r == null) {\n                throw new IllegalArgumentException(\"r must not be null\");\n            }\n            synchronized (glThreadManager) {\n                eventQueue.add(r);\n                glThreadManager.notifyAll();\n            }\n        }\n\n        // Once the thread is started, all accesses to the following member\n        // variables are protected by the glThreadManager monitor\n        private boolean shouldExit;\n        private boolean exited;\n        private boolean requestPaused;\n        private boolean paused;\n        private boolean hasSurface;\n        private boolean surfaceIsBad;\n        private boolean waitingForSurface;\n        private boolean haveEglContext;\n        private boolean haveEglSurface;\n        private boolean shouldReleaseEglContext;\n        private int width;\n        private int height;\n        private int renderMode;\n        private boolean requestRender;\n        private boolean renderComplete;\n        private ArrayList<Runnable> eventQueue = new ArrayList<>();\n        private boolean sizeChanged = true;\n\n        // End of member variables protected by the glThreadManager monitor.\n\n        private EglHelper eglHelper;\n\n        /**\n         * Set once at thread construction time, nulled out when the parent view is garbage\n         * called. This weak reference allows the GLTextureView to be garbage collected while\n         * the GLThread is still alive.\n         */\n        private WeakReference<GLTextureView> glTextureViewWeakRef;\n    }\n\n    static class LogWriter extends Writer {\n\n        @Override\n        public void close() {\n            flushBuilder();\n        }\n\n        @Override\n        public void flush() {\n            flushBuilder();\n        }\n\n        @Override\n        public void write(char[] buf, int offset, int count) {\n            for (int i = 0; i < count; i++) {\n                char c = buf[offset + i];\n                if (c == '\\n') {\n                    flushBuilder();\n                } else {\n                    builder.append(c);\n                }\n            }\n        }\n\n        private void flushBuilder() {\n            if (builder.length() > 0) {\n                Log.v(\"GLTextureView\", builder.toString());\n                builder.delete(0, builder.length());\n            }\n        }\n\n        private StringBuilder builder = new StringBuilder();\n    }\n\n    private void checkRenderThreadState() {\n        if (glThread != null) {\n            throw new IllegalStateException(\"setRenderer has already been called for this instance.\");\n        }\n    }\n\n    private static class GLThreadManager {\n        private static String TAG = \"GLThreadManager\";\n\n        public synchronized void threadExiting(GLThread thread) {\n            if (LOG_THREADS) {\n                Log.i(\"GLThread\", \"exiting tid=\" + thread.getId());\n            }\n            thread.exited = true;\n            if (eglOwner == thread) {\n                eglOwner = null;\n            }\n            notifyAll();\n        }\n\n        /*\n         * Tries once to acquire the right to use an EGL\n         * context. Does not block. Requires that we are already\n         * in the glThreadManager monitor when this is called.\n         *\n         * @return true if the right to use an EGL context was acquired.\n         */\n        public boolean tryAcquireEglContextLocked(GLThread thread) {\n            if (eglOwner == thread || eglOwner == null) {\n                eglOwner = thread;\n                notifyAll();\n                return true;\n            }\n            checkGLESVersion();\n            if (multipleGLESContextsAllowed) {\n                return true;\n            }\n            // Notify the owning thread that it should release the context.\n            // TODO: implement a fairness policy. Currently\n            // if the owning thread is drawing continuously it will just\n            // reacquire the EGL context.\n            if (eglOwner != null) {\n                eglOwner.requestReleaseEglContextLocked();\n            }\n            return false;\n        }\n\n        /*\n         * Releases the EGL context. Requires that we are already in the\n         * glThreadManager monitor when this is called.\n         */\n        public void releaseEglContextLocked(GLThread thread) {\n            if (eglOwner == thread) {\n                eglOwner = null;\n            }\n            notifyAll();\n        }\n\n        public synchronized boolean shouldReleaseEGLContextWhenPausing() {\n            // Release the EGL context when pausing even if\n            // the hardware supports multiple EGL contexts.\n            // Otherwise the device could run out of EGL contexts.\n            return limitedGLESContexts;\n        }\n\n        public synchronized boolean shouldTerminateEGLWhenPausing() {\n            checkGLESVersion();\n            return !multipleGLESContextsAllowed;\n        }\n\n        public synchronized void checkGLDriver(GL10 gl) {\n            if (!glesDriverCheckComplete) {\n                checkGLESVersion();\n                String renderer = gl.glGetString(GL10.GL_RENDERER);\n                if (glesVersion < kGLES_20) {\n                    multipleGLESContextsAllowed = !renderer.startsWith(kMSM7K_RENDERER_PREFIX);\n                    notifyAll();\n                }\n                limitedGLESContexts = !multipleGLESContextsAllowed;\n                if (LOG_SURFACE) {\n                    Log.w(TAG, \"checkGLDriver renderer = \\\"\" + renderer + \"\\\" multipleContextsAllowed = \"\n                            + multipleGLESContextsAllowed + \" limitedGLESContexts = \" + limitedGLESContexts);\n                }\n                glesDriverCheckComplete = true;\n            }\n        }\n\n        private void checkGLESVersion() {\n            if (!glesVersionCheckComplete) {\n                glesVersionCheckComplete = true;\n            }\n        }\n\n        /**\n         * This check was required for some pre-Android-3.0 hardware. Android 3.0 provides\n         * support for hardware-accelerated views, therefore multiple EGL contexts are\n         * supported on all Android 3.0+ EGL drivers.\n         */\n        private boolean glesVersionCheckComplete;\n        private int glesVersion;\n        private boolean glesDriverCheckComplete;\n        private boolean multipleGLESContextsAllowed;\n        private boolean limitedGLESContexts;\n        private static final int kGLES_20 = 0x20000;\n        private static final String kMSM7K_RENDERER_PREFIX = \"Q3Dimension MSM7500 \";\n        private GLThread eglOwner;\n    }\n\n    private static final GLThreadManager glThreadManager = new GLThreadManager();\n\n    private final WeakReference<GLTextureView> mThisWeakRef = new WeakReference<>(this);\n    private GLThread glThread;\n    private Renderer renderer;\n    private boolean detached;\n    private EGLConfigChooser eglConfigChooser;\n    private EGLContextFactory eglContextFactory;\n    private EGLWindowSurfaceFactory eglWindowSurfaceFactory;\n    private GLWrapper glWrapper;\n    private int debugFlags;\n    private int eglContextClientVersion;\n    private boolean preserveEGLContextOnPause;\n    private List<SurfaceTextureListener> surfaceTextureListeners = new ArrayList<>();\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/GPUImage.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage;\n\nimport android.app.ActivityManager;\nimport android.content.Context;\nimport android.content.pm.ConfigurationInfo;\nimport android.database.Cursor;\nimport android.graphics.Bitmap;\nimport android.graphics.Bitmap.CompressFormat;\nimport android.graphics.BitmapFactory;\nimport android.graphics.Matrix;\nimport android.graphics.PixelFormat;\nimport android.hardware.Camera;\nimport android.media.ExifInterface;\nimport android.media.MediaScannerConnection;\nimport android.net.Uri;\nimport android.opengl.GLSurfaceView;\nimport android.os.AsyncTask;\nimport android.os.Environment;\nimport android.os.Handler;\nimport android.provider.MediaStore;\nimport android.view.Display;\nimport android.view.WindowManager;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.URL;\nimport java.util.List;\n\nimport jp.co.cyberagent.android.gpuimage.filter.GPUImageFilter;\nimport jp.co.cyberagent.android.gpuimage.util.Rotation;\n\n/**\n * The main accessor for GPUImage functionality. This class helps to do common\n * tasks through a simple interface.\n */\npublic class GPUImage {\n\n    public enum ScaleType {CENTER_INSIDE, CENTER_CROP}\n\n    static final int SURFACE_TYPE_SURFACE_VIEW = 0;\n    static final int SURFACE_TYPE_TEXTURE_VIEW = 1;\n\n    private final Context context;\n    private final GPUImageRenderer renderer;\n    private int surfaceType = SURFACE_TYPE_SURFACE_VIEW;\n    private GLSurfaceView glSurfaceView;\n    private GLTextureView glTextureView;\n    private GPUImageFilter filter;\n    private Bitmap currentBitmap;\n    private ScaleType scaleType = ScaleType.CENTER_CROP;\n    private int scaleWidth, scaleHeight;\n\n    /**\n     * Instantiates a new GPUImage object.\n     *\n     * @param context the context\n     */\n    public GPUImage(final Context context) {\n        if (!supportsOpenGLES2(context)) {\n            throw new IllegalStateException(\"OpenGL ES 2.0 is not supported on this phone.\");\n        }\n\n        this.context = context;\n        filter = new GPUImageFilter();\n        renderer = new GPUImageRenderer(filter);\n    }\n\n    /**\n     * Checks if OpenGL ES 2.0 is supported on the current device.\n     *\n     * @param context the context\n     * @return true, if successful\n     */\n    private boolean supportsOpenGLES2(final Context context) {\n        final ActivityManager activityManager = (ActivityManager)\n                context.getSystemService(Context.ACTIVITY_SERVICE);\n        final ConfigurationInfo configurationInfo =\n                activityManager.getDeviceConfigurationInfo();\n        return configurationInfo.reqGlEsVersion >= 0x20000;\n    }\n\n    /**\n     * Sets the GLSurfaceView which will display the preview.\n     *\n     * @param view the GLSurfaceView\n     */\n    public void setGLSurfaceView(final GLSurfaceView view) {\n        surfaceType = SURFACE_TYPE_SURFACE_VIEW;\n        glSurfaceView = view;\n        glSurfaceView.setEGLContextClientVersion(2);\n        glSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);\n        glSurfaceView.getHolder().setFormat(PixelFormat.RGBA_8888);\n        glSurfaceView.setRenderer(renderer);\n        glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);\n        glSurfaceView.requestRender();\n    }\n\n    /**\n     * Sets the GLTextureView which will display the preview.\n     *\n     * @param view the GLTextureView\n     */\n    public void setGLTextureView(final GLTextureView view) {\n        surfaceType = SURFACE_TYPE_TEXTURE_VIEW;\n        glTextureView = view;\n        glTextureView.setEGLContextClientVersion(2);\n        glTextureView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);\n        glTextureView.setOpaque(false);\n        glTextureView.setRenderer(renderer);\n        glTextureView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);\n        glTextureView.requestRender();\n    }\n\n    /**\n     * Sets the background color\n     *\n     * @param red   red color value\n     * @param green green color value\n     * @param blue  red color value\n     */\n    public void setBackgroundColor(float red, float green, float blue) {\n        renderer.setBackgroundColor(red, green, blue);\n    }\n\n    /**\n     * Request the preview to be rendered again.\n     */\n    public void requestRender() {\n        if (surfaceType == SURFACE_TYPE_SURFACE_VIEW) {\n            if (glSurfaceView != null) {\n                glSurfaceView.requestRender();\n            }\n        } else if (surfaceType == SURFACE_TYPE_TEXTURE_VIEW) {\n            if (glTextureView != null) {\n                glTextureView.requestRender();\n            }\n        }\n    }\n\n    /**\n     * Deprecated: Please call\n     * {@link GPUImage#updatePreviewFrame(byte[], int, int)} frame by frame\n     * <p>\n     * Sets the up camera to be connected to GPUImage to get a filtered preview.\n     *\n     * @param camera the camera\n     */\n    @Deprecated\n    public void setUpCamera(final Camera camera) {\n        setUpCamera(camera, 0, false, false);\n    }\n\n    /**\n     * Deprecated: Please call\n     * {@link GPUImage#updatePreviewFrame(byte[], int, int)} frame by frame\n     * <p>\n     * Sets the up camera to be connected to GPUImage to get a filtered preview.\n     *\n     * @param camera         the camera\n     * @param degrees        by how many degrees the image should be rotated\n     * @param flipHorizontal if the image should be flipped horizontally\n     * @param flipVertical   if the image should be flipped vertically\n     */\n    @Deprecated\n    public void setUpCamera(final Camera camera, final int degrees, final boolean flipHorizontal,\n                            final boolean flipVertical) {\n        if (surfaceType == SURFACE_TYPE_SURFACE_VIEW) {\n            glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);\n        } else if (surfaceType == SURFACE_TYPE_TEXTURE_VIEW) {\n            glTextureView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);\n        }\n        renderer.setUpSurfaceTexture(camera);\n        Rotation rotation = Rotation.NORMAL;\n        switch (degrees) {\n            case 90:\n                rotation = Rotation.ROTATION_90;\n                break;\n            case 180:\n                rotation = Rotation.ROTATION_180;\n                break;\n            case 270:\n                rotation = Rotation.ROTATION_270;\n                break;\n        }\n        renderer.setRotationCamera(rotation, flipHorizontal, flipVertical);\n    }\n\n    /**\n     * Sets the filter which should be applied to the image which was (or will\n     * be) set by setImage(...).\n     *\n     * @param filter the new filter\n     */\n    public void setFilter(final GPUImageFilter filter) {\n        this.filter = filter;\n        renderer.setFilter(this.filter);\n        requestRender();\n    }\n\n    /**\n     * Sets the image on which the filter should be applied.\n     *\n     * @param bitmap the new image\n     */\n    public void setImage(final Bitmap bitmap) {\n        currentBitmap = bitmap;\n        renderer.setImageBitmap(bitmap, false);\n        requestRender();\n    }\n\n    /**\n     * Update camera preview frame with YUV format data.\n     *\n     * @param data   Camera preview YUV data for frame.\n     * @param width  width of camera preview\n     * @param height height of camera preview\n     */\n    public void updatePreviewFrame(final byte[] data, final int width, final int height) {\n        renderer.onPreviewFrame(data, width, height);\n    }\n\n    /**\n     * This sets the scale type of GPUImage. This has to be run before setting the image.\n     * If image is set and scale type changed, image needs to be reset.\n     *\n     * @param scaleType The new ScaleType\n     */\n    public void setScaleType(ScaleType scaleType) {\n        this.scaleType = scaleType;\n        renderer.setScaleType(scaleType);\n        renderer.deleteImage();\n        currentBitmap = null;\n        requestRender();\n    }\n\n    /**\n     * This gets the size of the image. This makes it easier to adjust\n     * the size of your imagePreview to the the size of the scaled image.\n     *\n     * @return array with width and height of bitmap image\n     */\n    public int[] getScaleSize() {\n        return new int[] {scaleWidth, scaleHeight};\n    }\n\n    /**\n     * Sets the rotation of the displayed image.\n     *\n     * @param rotation new rotation\n     */\n    public void setRotation(Rotation rotation) {\n        renderer.setRotation(rotation);\n    }\n\n    /**\n     * Sets the rotation of the displayed image with flip options.\n     *\n     * @param rotation new rotation\n     */\n    public void setRotation(Rotation rotation, boolean flipHorizontal, boolean flipVertical) {\n        renderer.setRotation(rotation, flipHorizontal, flipVertical);\n    }\n\n    /**\n     * Deletes the current image.\n     */\n    public void deleteImage() {\n        renderer.deleteImage();\n        currentBitmap = null;\n        requestRender();\n    }\n\n    /**\n     * Sets the image on which the filter should be applied from a Uri.\n     *\n     * @param uri the uri of the new image\n     */\n    public void setImage(final Uri uri) {\n        new LoadImageUriTask(this, uri).execute();\n    }\n\n    /**\n     * Sets the image on which the filter should be applied from a File.\n     *\n     * @param file the file of the new image\n     */\n    public void setImage(final File file) {\n        new LoadImageFileTask(this, file).execute();\n    }\n\n    private String getPath(final Uri uri) {\n        String[] projection = {\n                MediaStore.Images.Media.DATA,\n        };\n        Cursor cursor = context.getContentResolver()\n                .query(uri, projection, null, null, null);\n        String path = null;\n        if (cursor == null) {\n            return null;\n        }\n        if (cursor.moveToFirst()) {\n            int pathIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);\n            path = cursor.getString(pathIndex);\n        }\n        cursor.close();\n        return path;\n    }\n\n    /**\n     * Gets the current displayed image with applied filter as a Bitmap.\n     *\n     * @return the current image with filter applied\n     */\n    public Bitmap getBitmapWithFilterApplied() {\n        return getBitmapWithFilterApplied(currentBitmap);\n    }\n\n    /**\n     * Gets the given bitmap with current filter applied as a Bitmap.\n     *\n     * @param bitmap the bitmap on which the current filter should be applied\n     * @return the bitmap with filter applied\n     */\n    public Bitmap getBitmapWithFilterApplied(final Bitmap bitmap) {\n        return getBitmapWithFilterApplied(bitmap, false);\n    }\n\n    /**\n     * Gets the given bitmap with current filter applied as a Bitmap.\n     *\n     * @param bitmap  the bitmap on which the current filter should be applied\n     * @param recycle recycle the bitmap or not.\n     * @return the bitmap with filter applied\n     */\n    public Bitmap getBitmapWithFilterApplied(final Bitmap bitmap, boolean recycle) {\n        if (glSurfaceView != null || glTextureView != null) {\n            renderer.deleteImage();\n            renderer.runOnDraw(new Runnable() {\n\n                @Override\n                public void run() {\n                    synchronized (filter) {\n                        filter.destroy();\n                        filter.notify();\n                    }\n                }\n            });\n            synchronized (filter) {\n                requestRender();\n                try {\n                    filter.wait();\n                } catch (InterruptedException e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n\n        GPUImageRenderer renderer = new GPUImageRenderer(filter);\n        renderer.setRotation(Rotation.NORMAL,\n                this.renderer.isFlippedHorizontally(), this.renderer.isFlippedVertically());\n        renderer.setScaleType(scaleType);\n        PixelBuffer buffer = new PixelBuffer(bitmap.getWidth(), bitmap.getHeight());\n        buffer.setRenderer(renderer);\n        renderer.setImageBitmap(bitmap, recycle);\n        Bitmap result = buffer.getBitmap();\n        filter.destroy();\n        renderer.deleteImage();\n        buffer.destroy();\n\n        this.renderer.setFilter(filter);\n        if (currentBitmap != null) {\n            this.renderer.setImageBitmap(currentBitmap, false);\n        }\n        requestRender();\n\n        return result;\n    }\n\n    /**\n     * Gets the images for multiple filters on a image. This can be used to\n     * quickly get thumbnail images for filters. <br>\n     * Whenever a new Bitmap is ready, the listener will be called with the\n     * bitmap. The order of the calls to the listener will be the same as the\n     * filter order.\n     *\n     * @param bitmap   the bitmap on which the filters will be applied\n     * @param filters  the filters which will be applied on the bitmap\n     * @param listener the listener on which the results will be notified\n     */\n    public static void getBitmapForMultipleFilters(final Bitmap bitmap,\n                                                   final List<GPUImageFilter> filters, final ResponseListener<Bitmap> listener) {\n        if (filters.isEmpty()) {\n            return;\n        }\n        GPUImageRenderer renderer = new GPUImageRenderer(filters.get(0));\n        renderer.setImageBitmap(bitmap, false);\n        PixelBuffer buffer = new PixelBuffer(bitmap.getWidth(), bitmap.getHeight());\n        buffer.setRenderer(renderer);\n\n        for (GPUImageFilter filter : filters) {\n            renderer.setFilter(filter);\n            listener.response(buffer.getBitmap());\n            filter.destroy();\n        }\n        renderer.deleteImage();\n        buffer.destroy();\n    }\n\n    /**\n     * Save current image with applied filter to Pictures. It will be stored on\n     * the default Picture folder on the phone below the given folderName and\n     * fileName. <br>\n     * This method is async and will notify when the image was saved through the\n     * listener.\n     *\n     * @param folderName the folder name\n     * @param fileName   the file name\n     * @param listener   the listener\n     */\n    public void saveToPictures(final String folderName, final String fileName,\n                               final OnPictureSavedListener listener) {\n        saveToPictures(currentBitmap, folderName, fileName, listener);\n    }\n\n    /**\n     * Apply and save the given bitmap with applied filter to Pictures. It will\n     * be stored on the default Picture folder on the phone below the given\n     * folerName and fileName. <br>\n     * This method is async and will notify when the image was saved through the\n     * listener.\n     *\n     * @param bitmap     the bitmap\n     * @param folderName the folder name\n     * @param fileName   the file name\n     * @param listener   the listener\n     */\n    public void saveToPictures(final Bitmap bitmap, final String folderName, final String fileName,\n                               final OnPictureSavedListener listener) {\n        new SaveTask(bitmap, folderName, fileName, listener).execute();\n    }\n\n    /**\n     * Runs the given Runnable on the OpenGL thread.\n     *\n     * @param runnable The runnable to be run on the OpenGL thread.\n     */\n    void runOnGLThread(Runnable runnable) {\n        renderer.runOnDrawEnd(runnable);\n    }\n\n    private int getOutputWidth() {\n        if (renderer != null && renderer.getFrameWidth() != 0) {\n            return renderer.getFrameWidth();\n        } else if (currentBitmap != null) {\n            return currentBitmap.getWidth();\n        } else {\n            WindowManager windowManager =\n                    (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);\n            Display display = windowManager.getDefaultDisplay();\n            return display.getWidth();\n        }\n    }\n\n    private int getOutputHeight() {\n        if (renderer != null && renderer.getFrameHeight() != 0) {\n            return renderer.getFrameHeight();\n        } else if (currentBitmap != null) {\n            return currentBitmap.getHeight();\n        } else {\n            WindowManager windowManager =\n                    (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);\n            Display display = windowManager.getDefaultDisplay();\n            return display.getHeight();\n        }\n    }\n\n    @Deprecated\n    private class SaveTask extends AsyncTask<Void, Void, Void> {\n\n        private final Bitmap bitmap;\n        private final String folderName;\n        private final String fileName;\n        private final OnPictureSavedListener listener;\n        private final Handler handler;\n\n        public SaveTask(final Bitmap bitmap, final String folderName, final String fileName,\n                        final OnPictureSavedListener listener) {\n            this.bitmap = bitmap;\n            this.folderName = folderName;\n            this.fileName = fileName;\n            this.listener = listener;\n            handler = new Handler();\n        }\n\n        @Override\n        protected Void doInBackground(final Void... params) {\n            Bitmap result = getBitmapWithFilterApplied(bitmap);\n            saveImage(folderName, fileName, result);\n            return null;\n        }\n\n        private void saveImage(final String folderName, final String fileName, final Bitmap image) {\n            File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);\n            File file = new File(path, folderName + \"/\" + fileName);\n            try {\n                file.getParentFile().mkdirs();\n                image.compress(CompressFormat.JPEG, 80, new FileOutputStream(file));\n                MediaScannerConnection.scanFile(context,\n                        new String[]{\n                                file.toString()\n                        }, null,\n                        new MediaScannerConnection.OnScanCompletedListener() {\n                            @Override\n                            public void onScanCompleted(final String path, final Uri uri) {\n                                if (listener != null) {\n                                    handler.post(new Runnable() {\n\n                                        @Override\n                                        public void run() {\n                                            listener.onPictureSaved(uri);\n                                        }\n                                    });\n                                }\n                            }\n                        });\n            } catch (FileNotFoundException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    public interface OnPictureSavedListener {\n        void onPictureSaved(Uri uri);\n    }\n\n    private class LoadImageUriTask extends LoadImageTask {\n\n        private final Uri uri;\n\n        public LoadImageUriTask(GPUImage gpuImage, Uri uri) {\n            super(gpuImage);\n            this.uri = uri;\n        }\n\n        @Override\n        protected Bitmap decode(BitmapFactory.Options options) {\n            try {\n                InputStream inputStream;\n                if (uri.getScheme().startsWith(\"http\") || uri.getScheme().startsWith(\"https\")) {\n                    inputStream = new URL(uri.toString()).openStream();\n                } else if (uri.getPath().startsWith(\"/android_asset/\")) {\n                    inputStream = context.getAssets().open(uri.getPath().substring((\"/android_asset/\").length()));\n                } else {\n                    inputStream = context.getContentResolver().openInputStream(uri);\n                }\n                return BitmapFactory.decodeStream(inputStream, null, options);\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n            return null;\n        }\n\n        @Override\n        protected int getImageOrientation() throws IOException {\n            Cursor cursor = context.getContentResolver().query(uri,\n                    new String[]{MediaStore.Images.ImageColumns.ORIENTATION}, null, null, null);\n\n            if (cursor == null || cursor.getCount() != 1) {\n                return 0;\n            }\n\n            cursor.moveToFirst();\n            int orientation = cursor.getInt(0);\n            cursor.close();\n            return orientation;\n        }\n    }\n\n    private class LoadImageFileTask extends LoadImageTask {\n\n        private final File imageFile;\n\n        public LoadImageFileTask(GPUImage gpuImage, File file) {\n            super(gpuImage);\n            imageFile = file;\n        }\n\n        @Override\n        protected Bitmap decode(BitmapFactory.Options options) {\n            return BitmapFactory.decodeFile(imageFile.getAbsolutePath(), options);\n        }\n\n        @Override\n        protected int getImageOrientation() throws IOException {\n            ExifInterface exif = new ExifInterface(imageFile.getAbsolutePath());\n            int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);\n            switch (orientation) {\n                case ExifInterface.ORIENTATION_NORMAL:\n                    return 0;\n                case ExifInterface.ORIENTATION_ROTATE_90:\n                    return 90;\n                case ExifInterface.ORIENTATION_ROTATE_180:\n                    return 180;\n                case ExifInterface.ORIENTATION_ROTATE_270:\n                    return 270;\n                default:\n                    return 0;\n            }\n        }\n    }\n\n    private abstract class LoadImageTask extends AsyncTask<Void, Void, Bitmap> {\n\n        private final GPUImage gpuImage;\n        private int outputWidth;\n        private int outputHeight;\n\n        public LoadImageTask(final GPUImage gpuImage) {\n            this.gpuImage = gpuImage;\n        }\n\n        @Override\n        protected Bitmap doInBackground(Void... params) {\n            if (renderer != null && renderer.getFrameWidth() == 0) {\n                try {\n                    synchronized (renderer.surfaceChangedWaiter) {\n                        renderer.surfaceChangedWaiter.wait(3000);\n                    }\n                } catch (InterruptedException e) {\n                    e.printStackTrace();\n                }\n            }\n            outputWidth = getOutputWidth();\n            outputHeight = getOutputHeight();\n            return loadResizedImage();\n        }\n\n        @Override\n        protected void onPostExecute(Bitmap bitmap) {\n            super.onPostExecute(bitmap);\n            gpuImage.deleteImage();\n            gpuImage.setImage(bitmap);\n        }\n\n        protected abstract Bitmap decode(BitmapFactory.Options options);\n\n        private Bitmap loadResizedImage() {\n            BitmapFactory.Options options = new BitmapFactory.Options();\n            options.inJustDecodeBounds = true;\n            decode(options);\n            int scale = 1;\n            while (checkSize(options.outWidth / scale > outputWidth, options.outHeight / scale > outputHeight)) {\n                scale++;\n            }\n\n            scale--;\n            if (scale < 1) {\n                scale = 1;\n            }\n            options = new BitmapFactory.Options();\n            options.inSampleSize = scale;\n            options.inPreferredConfig = Bitmap.Config.RGB_565;\n            options.inPurgeable = true;\n            options.inTempStorage = new byte[32 * 1024];\n            Bitmap bitmap = decode(options);\n            if (bitmap == null) {\n                return null;\n            }\n            bitmap = rotateImage(bitmap);\n            bitmap = scaleBitmap(bitmap);\n            return bitmap;\n        }\n\n        private Bitmap scaleBitmap(Bitmap bitmap) {\n            // resize to desired dimensions\n            int width = bitmap.getWidth();\n            int height = bitmap.getHeight();\n            int[] newSize = getScaleSize(width, height);\n            Bitmap workBitmap = Bitmap.createScaledBitmap(bitmap, newSize[0], newSize[1], true);\n            if (workBitmap != bitmap) {\n                bitmap.recycle();\n                bitmap = workBitmap;\n                System.gc();\n            }\n\n            if (scaleType == ScaleType.CENTER_CROP) {\n                // Crop it\n                int diffWidth = newSize[0] - outputWidth;\n                int diffHeight = newSize[1] - outputHeight;\n                workBitmap = Bitmap.createBitmap(bitmap, diffWidth / 2, diffHeight / 2,\n                        newSize[0] - diffWidth, newSize[1] - diffHeight);\n                if (workBitmap != bitmap) {\n                    bitmap.recycle();\n                    bitmap = workBitmap;\n                }\n            }\n\n            return bitmap;\n        }\n\n        /**\n         * Retrieve the scaling size for the image dependent on the ScaleType.<br>\n         * <br>\n         * If CROP: sides are same size or bigger than output's sides<br>\n         * Else   : sides are same size or smaller than output's sides\n         */\n        private int[] getScaleSize(int width, int height) {\n            float newWidth;\n            float newHeight;\n\n            float withRatio = (float) width / outputWidth;\n            float heightRatio = (float) height / outputHeight;\n\n            boolean adjustWidth = scaleType == ScaleType.CENTER_CROP\n                    ? withRatio > heightRatio : withRatio < heightRatio;\n\n            if (adjustWidth) {\n                newHeight = outputHeight;\n                newWidth = (newHeight / height) * width;\n            } else {\n                newWidth = outputWidth;\n                newHeight = (newWidth / width) * height;\n            }\n            scaleWidth = Math.round(newWidth);\n            scaleHeight = Math.round(newHeight);\n            return new int[]{Math.round(newWidth), Math.round(newHeight)};\n        }\n\n        private boolean checkSize(boolean widthBigger, boolean heightBigger) {\n            if (scaleType == ScaleType.CENTER_CROP) {\n                return widthBigger && heightBigger;\n            } else {\n                return widthBigger || heightBigger;\n            }\n        }\n\n        private Bitmap rotateImage(final Bitmap bitmap) {\n            if (bitmap == null) {\n                return null;\n            }\n            Bitmap rotatedBitmap = bitmap;\n            try {\n                int orientation = getImageOrientation();\n                if (orientation != 0) {\n                    Matrix matrix = new Matrix();\n                    matrix.postRotate(orientation);\n                    rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),\n                            bitmap.getHeight(), matrix, true);\n                    bitmap.recycle();\n                }\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n            return rotatedBitmap;\n        }\n\n        protected abstract int getImageOrientation() throws IOException;\n    }\n\n    public interface ResponseListener<T> {\n        void response(T item);\n    }\n\n    public GPUImageRenderer getRenderer() {\n        return renderer;\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/GPUImageNativeLibrary.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage;\n\nimport android.graphics.Bitmap;\n\npublic class GPUImageNativeLibrary {\n    static {\n        System.loadLibrary(\"yuv-decoder\");\n    }\n\n    public static native void YUVtoRBGA(byte[] yuv, int width, int height, int[] out);\n\n    public static native void YUVtoARBG(byte[] yuv, int width, int height, int[] out);\n\n    public static native void adjustBitmap(Bitmap srcBitmap);\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/GPUImageRenderer.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage;\n\nimport android.graphics.Bitmap;\nimport android.graphics.Canvas;\nimport android.graphics.SurfaceTexture;\nimport android.hardware.Camera;\nimport android.hardware.Camera.PreviewCallback;\nimport android.hardware.Camera.Size;\nimport android.opengl.GLES20;\nimport android.opengl.GLSurfaceView;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.FloatBuffer;\nimport java.nio.IntBuffer;\nimport java.util.LinkedList;\nimport java.util.Queue;\n\nimport javax.microedition.khronos.egl.EGLConfig;\nimport javax.microedition.khronos.opengles.GL10;\n\nimport jp.co.cyberagent.android.gpuimage.filter.GPUImageFilter;\nimport jp.co.cyberagent.android.gpuimage.util.OpenGlUtils;\nimport jp.co.cyberagent.android.gpuimage.util.Rotation;\nimport jp.co.cyberagent.android.gpuimage.util.TextureRotationUtil;\n\nimport static jp.co.cyberagent.android.gpuimage.util.TextureRotationUtil.TEXTURE_NO_ROTATION;\n\npublic class GPUImageRenderer implements GLSurfaceView.Renderer, GLTextureView.Renderer, PreviewCallback {\n    private static final int NO_IMAGE = -1;\n    public static final float CUBE[] = {\n            -1.0f, -1.0f,\n            1.0f, -1.0f,\n            -1.0f, 1.0f,\n            1.0f, 1.0f,\n    };\n\n    private GPUImageFilter filter;\n\n    public final Object surfaceChangedWaiter = new Object();\n\n    private int glTextureId = NO_IMAGE;\n    private SurfaceTexture surfaceTexture = null;\n    private final FloatBuffer glCubeBuffer;\n    private final FloatBuffer glTextureBuffer;\n    private IntBuffer glRgbBuffer;\n\n    private int outputWidth;\n    private int outputHeight;\n    private int imageWidth;\n    private int imageHeight;\n    private int addedPadding;\n\n    private final Queue<Runnable> runOnDraw;\n    private final Queue<Runnable> runOnDrawEnd;\n    private Rotation rotation;\n    private boolean flipHorizontal;\n    private boolean flipVertical;\n    private GPUImage.ScaleType scaleType = GPUImage.ScaleType.CENTER_CROP;\n\n    private float backgroundRed = 0;\n    private float backgroundGreen = 0;\n    private float backgroundBlue = 0;\n\n    public GPUImageRenderer(final GPUImageFilter filter) {\n        this.filter = filter;\n        runOnDraw = new LinkedList<>();\n        runOnDrawEnd = new LinkedList<>();\n\n        glCubeBuffer = ByteBuffer.allocateDirect(CUBE.length * 4)\n                .order(ByteOrder.nativeOrder())\n                .asFloatBuffer();\n        glCubeBuffer.put(CUBE).position(0);\n\n        glTextureBuffer = ByteBuffer.allocateDirect(TEXTURE_NO_ROTATION.length * 4)\n                .order(ByteOrder.nativeOrder())\n                .asFloatBuffer();\n        setRotation(Rotation.NORMAL, false, false);\n    }\n\n    @Override\n    public void onSurfaceCreated(final GL10 unused, final EGLConfig config) {\n        GLES20.glClearColor(backgroundRed, backgroundGreen, backgroundBlue, 1);\n        GLES20.glDisable(GLES20.GL_DEPTH_TEST);\n        filter.ifNeedInit();\n    }\n\n    @Override\n    public void onSurfaceChanged(final GL10 gl, final int width, final int height) {\n        outputWidth = width;\n        outputHeight = height;\n        GLES20.glViewport(0, 0, width, height);\n        GLES20.glUseProgram(filter.getProgram());\n        filter.onOutputSizeChanged(width, height);\n        adjustImageScaling();\n        synchronized (surfaceChangedWaiter) {\n            surfaceChangedWaiter.notifyAll();\n        }\n    }\n\n    @Override\n    public void onDrawFrame(final GL10 gl) {\n        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);\n        runAll(runOnDraw);\n        filter.onDraw(glTextureId, glCubeBuffer, glTextureBuffer);\n        runAll(runOnDrawEnd);\n        if (surfaceTexture != null) {\n            surfaceTexture.updateTexImage();\n        }\n    }\n\n    /**\n     * Sets the background color\n     *\n     * @param red   red color value\n     * @param green green color value\n     * @param blue  red color value\n     */\n    public void setBackgroundColor(float red, float green, float blue) {\n        backgroundRed = red;\n        backgroundGreen = green;\n        backgroundBlue = blue;\n    }\n\n    private void runAll(Queue<Runnable> queue) {\n        synchronized (queue) {\n            while (!queue.isEmpty()) {\n                queue.poll().run();\n            }\n        }\n    }\n\n    @Override\n    public void onPreviewFrame(final byte[] data, final Camera camera) {\n        final Size previewSize = camera.getParameters().getPreviewSize();\n        onPreviewFrame(data, previewSize.width, previewSize.height);\n    }\n\n    public void onPreviewFrame(final byte[] data, final int width, final int height) {\n        if (glRgbBuffer == null) {\n            glRgbBuffer = IntBuffer.allocate(width * height);\n        }\n        if (runOnDraw.isEmpty()) {\n            runOnDraw(new Runnable() {\n                @Override\n                public void run() {\n                    GPUImageNativeLibrary.YUVtoRBGA(data, width, height, glRgbBuffer.array());\n                    glTextureId = OpenGlUtils.loadTexture(glRgbBuffer, width, height, glTextureId);\n\n                    if (imageWidth != width) {\n                        imageWidth = width;\n                        imageHeight = height;\n                        adjustImageScaling();\n                    }\n                }\n            });\n        }\n    }\n\n    public void setUpSurfaceTexture(final Camera camera) {\n        runOnDraw(new Runnable() {\n            @Override\n            public void run() {\n                int[] textures = new int[1];\n                GLES20.glGenTextures(1, textures, 0);\n                surfaceTexture = new SurfaceTexture(textures[0]);\n                try {\n                    camera.setPreviewTexture(surfaceTexture);\n                    camera.setPreviewCallback(GPUImageRenderer.this);\n                    camera.startPreview();\n                } catch (IOException e) {\n                    e.printStackTrace();\n                }\n            }\n        });\n    }\n\n    public void setFilter(final GPUImageFilter filter) {\n        runOnDraw(new Runnable() {\n\n            @Override\n            public void run() {\n                final GPUImageFilter oldFilter = GPUImageRenderer.this.filter;\n                GPUImageRenderer.this.filter = filter;\n                if (oldFilter != null) {\n                    oldFilter.destroy();\n                }\n                GPUImageRenderer.this.filter.ifNeedInit();\n                GLES20.glUseProgram(GPUImageRenderer.this.filter.getProgram());\n                GPUImageRenderer.this.filter.onOutputSizeChanged(outputWidth, outputHeight);\n            }\n        });\n    }\n\n    public void deleteImage() {\n        runOnDraw(new Runnable() {\n\n            @Override\n            public void run() {\n                GLES20.glDeleteTextures(1, new int[]{\n                        glTextureId\n                }, 0);\n                glTextureId = NO_IMAGE;\n            }\n        });\n    }\n\n    public void setImageBitmap(final Bitmap bitmap) {\n        setImageBitmap(bitmap, true);\n    }\n\n    public void setImageBitmap(final Bitmap bitmap, final boolean recycle) {\n        if (bitmap == null) {\n            return;\n        }\n\n        runOnDraw(new Runnable() {\n\n            @Override\n            public void run() {\n                Bitmap resizedBitmap = null;\n                if (bitmap.getWidth() % 2 == 1) {\n                    resizedBitmap = Bitmap.createBitmap(bitmap.getWidth() + 1, bitmap.getHeight(),\n                            Bitmap.Config.ARGB_8888);\n                    resizedBitmap.setDensity(bitmap.getDensity());\n                    Canvas can = new Canvas(resizedBitmap);\n                    can.drawARGB(0x00, 0x00, 0x00, 0x00);\n                    can.drawBitmap(bitmap, 0, 0, null);\n                    addedPadding = 1;\n                } else {\n                    addedPadding = 0;\n                }\n\n                glTextureId = OpenGlUtils.loadTexture(\n                        resizedBitmap != null ? resizedBitmap : bitmap, glTextureId, recycle);\n                if (resizedBitmap != null) {\n                    resizedBitmap.recycle();\n                }\n                imageWidth = bitmap.getWidth();\n                imageHeight = bitmap.getHeight();\n                adjustImageScaling();\n            }\n        });\n    }\n\n    public void setScaleType(GPUImage.ScaleType scaleType) {\n        this.scaleType = scaleType;\n    }\n\n    protected int getFrameWidth() {\n        return outputWidth;\n    }\n\n    protected int getFrameHeight() {\n        return outputHeight;\n    }\n\n    private void adjustImageScaling() {\n        float outputWidth = this.outputWidth;\n        float outputHeight = this.outputHeight;\n        if (rotation == Rotation.ROTATION_270 || rotation == Rotation.ROTATION_90) {\n            outputWidth = this.outputHeight;\n            outputHeight = this.outputWidth;\n        }\n\n        float ratio1 = outputWidth / imageWidth;\n        float ratio2 = outputHeight / imageHeight;\n        float ratioMax = Math.max(ratio1, ratio2);\n        int imageWidthNew = Math.round(imageWidth * ratioMax);\n        int imageHeightNew = Math.round(imageHeight * ratioMax);\n\n        float ratioWidth = imageWidthNew / outputWidth;\n        float ratioHeight = imageHeightNew / outputHeight;\n\n        float[] cube = CUBE;\n        float[] textureCords = TextureRotationUtil.getRotation(rotation, flipHorizontal, flipVertical);\n        if (scaleType == GPUImage.ScaleType.CENTER_CROP) {\n            float distHorizontal = (1 - 1 / ratioWidth) / 2;\n            float distVertical = (1 - 1 / ratioHeight) / 2;\n            textureCords = new float[]{\n                    addDistance(textureCords[0], distHorizontal), addDistance(textureCords[1], distVertical),\n                    addDistance(textureCords[2], distHorizontal), addDistance(textureCords[3], distVertical),\n                    addDistance(textureCords[4], distHorizontal), addDistance(textureCords[5], distVertical),\n                    addDistance(textureCords[6], distHorizontal), addDistance(textureCords[7], distVertical),\n            };\n        } else {\n            cube = new float[]{\n                    CUBE[0] / ratioHeight, CUBE[1] / ratioWidth,\n                    CUBE[2] / ratioHeight, CUBE[3] / ratioWidth,\n                    CUBE[4] / ratioHeight, CUBE[5] / ratioWidth,\n                    CUBE[6] / ratioHeight, CUBE[7] / ratioWidth,\n            };\n        }\n\n        glCubeBuffer.clear();\n        glCubeBuffer.put(cube).position(0);\n        glTextureBuffer.clear();\n        glTextureBuffer.put(textureCords).position(0);\n    }\n\n    private float addDistance(float coordinate, float distance) {\n        return coordinate == 0.0f ? distance : 1 - distance;\n    }\n\n    public void setRotationCamera(final Rotation rotation, final boolean flipHorizontal,\n                                  final boolean flipVertical) {\n        setRotation(rotation, flipVertical, flipHorizontal);\n    }\n\n    public void setRotation(final Rotation rotation) {\n        this.rotation = rotation;\n        adjustImageScaling();\n    }\n\n    public void setRotation(final Rotation rotation,\n                            final boolean flipHorizontal, final boolean flipVertical) {\n        this.flipHorizontal = flipHorizontal;\n        this.flipVertical = flipVertical;\n        setRotation(rotation);\n    }\n\n    public Rotation getRotation() {\n        return rotation;\n    }\n\n    public boolean isFlippedHorizontally() {\n        return flipHorizontal;\n    }\n\n    public boolean isFlippedVertically() {\n        return flipVertical;\n    }\n\n    protected void runOnDraw(final Runnable runnable) {\n        synchronized (runOnDraw) {\n            runOnDraw.add(runnable);\n        }\n    }\n\n    protected void runOnDrawEnd(final Runnable runnable) {\n        synchronized (runOnDrawEnd) {\n            runOnDrawEnd.add(runnable);\n        }\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/GPUImageView.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.Bitmap;\nimport android.graphics.Color;\nimport android.hardware.Camera;\nimport android.media.MediaScannerConnection;\nimport android.net.Uri;\nimport android.opengl.GLSurfaceView;\nimport android.os.AsyncTask;\nimport android.os.Build;\nimport android.os.Environment;\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.util.AttributeSet;\nimport android.view.Gravity;\nimport android.view.View;\nimport android.view.ViewTreeObserver;\nimport android.widget.FrameLayout;\nimport android.widget.ProgressBar;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.util.concurrent.Semaphore;\n\nimport jp.co.cyberagent.android.gpuimage.filter.GPUImageFilter;\nimport jp.co.cyberagent.android.gpuimage.util.Rotation;\n\nimport static jp.co.cyberagent.android.gpuimage.GPUImage.SURFACE_TYPE_SURFACE_VIEW;\nimport static jp.co.cyberagent.android.gpuimage.GPUImage.SURFACE_TYPE_TEXTURE_VIEW;\n\npublic class GPUImageView extends FrameLayout {\n\n    private int surfaceType = SURFACE_TYPE_SURFACE_VIEW;\n    private View surfaceView;\n    private GPUImage gpuImage;\n    private boolean isShowLoading = true;\n    private GPUImageFilter filter;\n    public Size forceSize = null;\n    private float ratio = 0.0f;\n\n    public final static int RENDERMODE_WHEN_DIRTY = 0;\n    public final static int RENDERMODE_CONTINUOUSLY = 1;\n\n    public GPUImageView(Context context) {\n        super(context);\n        init(context, null);\n    }\n\n    public GPUImageView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        init(context, attrs);\n    }\n\n    private void init(Context context, AttributeSet attrs) {\n        if (attrs != null) {\n            TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.GPUImageView, 0, 0);\n            try {\n                surfaceType = a.getInt(R.styleable.GPUImageView_gpuimage_surface_type, surfaceType);\n                isShowLoading = a.getBoolean(R.styleable.GPUImageView_gpuimage_show_loading, isShowLoading);\n            } finally {\n                a.recycle();\n            }\n        }\n        gpuImage = new GPUImage(context);\n        if (surfaceType == SURFACE_TYPE_TEXTURE_VIEW) {\n            surfaceView = new GPUImageGLTextureView(context, attrs);\n            gpuImage.setGLTextureView((GLTextureView) surfaceView);\n        } else {\n            surfaceView = new GPUImageGLSurfaceView(context, attrs);\n            gpuImage.setGLSurfaceView((GLSurfaceView) surfaceView);\n        }\n        addView(surfaceView);\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        if (ratio != 0.0f) {\n            int width = MeasureSpec.getSize(widthMeasureSpec);\n            int height = MeasureSpec.getSize(heightMeasureSpec);\n\n            int newHeight;\n            int newWidth;\n            if (width / ratio < height) {\n                newWidth = width;\n                newHeight = Math.round(width / ratio);\n            } else {\n                newHeight = height;\n                newWidth = Math.round(height * ratio);\n            }\n\n            int newWidthSpec = MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY);\n            int newHeightSpec = MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.EXACTLY);\n            super.onMeasure(newWidthSpec, newHeightSpec);\n        } else {\n            super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n        }\n    }\n\n    /**\n     * Retrieve the GPUImage instance used by this view.\n     *\n     * @return used GPUImage instance\n     */\n    public GPUImage getGPUImage() {\n        return gpuImage;\n    }\n\n    /**\n     * Deprecated: Please call\n     * {@link GPUImageView#updatePreviewFrame(byte[], int, int)} frame by frame\n     * <p>\n     * Sets the up camera to be connected to GPUImage to get a filtered preview.\n     *\n     * @param camera the camera\n     */\n    @Deprecated\n    public void setUpCamera(final Camera camera) {\n        gpuImage.setUpCamera(camera);\n    }\n\n    /**\n     * Deprecated: Please call\n     * {@link GPUImageView#updatePreviewFrame(byte[], int, int)} frame by frame\n     * <p>\n     * Sets the up camera to be connected to GPUImage to get a filtered preview.\n     *\n     * @param camera         the camera\n     * @param degrees        by how many degrees the image should be rotated\n     * @param flipHorizontal if the image should be flipped horizontally\n     * @param flipVertical   if the image should be flipped vertically\n     */\n    @Deprecated\n    public void setUpCamera(final Camera camera, final int degrees, final boolean flipHorizontal,\n                            final boolean flipVertical) {\n        gpuImage.setUpCamera(camera, degrees, flipHorizontal, flipVertical);\n    }\n\n    /**\n     * Update camera preview frame with YUV format data.\n     *\n     * @param data   Camera preview YUV data for frame.\n     * @param width  width of camera preview\n     * @param height height of camera preview\n     */\n    public void updatePreviewFrame(byte[] data, int width, int height) {\n        gpuImage.updatePreviewFrame(data, width, height);\n    }\n\n    /**\n     * Sets the background color\n     *\n     * @param red   red color value\n     * @param green green color value\n     * @param blue  red color value\n     */\n    public void setBackgroundColor(float red, float green, float blue) {\n        gpuImage.setBackgroundColor(red, green, blue);\n    }\n\n    /**\n     * Set the rendering mode. When renderMode is\n     * RENDERMODE_CONTINUOUSLY, the renderer is called\n     * repeatedly to re-render the scene. When renderMode\n     * is RENDERMODE_WHEN_DIRTY, the renderer only rendered when the surface\n     * is created, or when {@link #requestRender} is called. Defaults to RENDERMODE_CONTINUOUSLY.\n     *\n     * @param renderMode one of the RENDERMODE_X constants\n     * @see #RENDERMODE_CONTINUOUSLY\n     * @see #RENDERMODE_WHEN_DIRTY\n     * @see GLSurfaceView#setRenderMode(int)\n     * @see GLTextureView#setRenderMode(int)\n     */\n    public void setRenderMode(int renderMode) {\n        if (surfaceView instanceof GLSurfaceView) {\n            ((GLSurfaceView) surfaceView).setRenderMode(renderMode);\n        } else if (surfaceView instanceof GLTextureView) {\n            ((GLTextureView) surfaceView).setRenderMode(renderMode);\n        }\n    }\n\n    // TODO Should be an xml attribute. But then GPUImage can not be distributed as .jar anymore.\n    public void setRatio(float ratio) {\n        this.ratio = ratio;\n        surfaceView.requestLayout();\n        gpuImage.deleteImage();\n    }\n\n    /**\n     * Set the scale type of GPUImage.\n     *\n     * @param scaleType the new ScaleType\n     */\n    public void setScaleType(GPUImage.ScaleType scaleType) {\n        gpuImage.setScaleType(scaleType);\n    }\n\n    /**\n     * Sets the rotation of the displayed image.\n     *\n     * @param rotation new rotation\n     */\n    public void setRotation(Rotation rotation) {\n        gpuImage.setRotation(rotation);\n        requestRender();\n    }\n\n    /**\n     * Set the filter to be applied on the image.\n     *\n     * @param filter Filter that should be applied on the image.\n     */\n    public void setFilter(GPUImageFilter filter) {\n        this.filter = filter;\n        gpuImage.setFilter(filter);\n        requestRender();\n    }\n\n    /**\n     * Get the current applied filter.\n     *\n     * @return the current filter\n     */\n    public GPUImageFilter getFilter() {\n        return filter;\n    }\n\n    /**\n     * Sets the image on which the filter should be applied.\n     *\n     * @param bitmap the new image\n     */\n    public void setImage(final Bitmap bitmap) {\n        gpuImage.setImage(bitmap);\n    }\n\n    /**\n     * Sets the image on which the filter should be applied from a Uri.\n     *\n     * @param uri the uri of the new image\n     */\n    public void setImage(final Uri uri) {\n        gpuImage.setImage(uri);\n    }\n\n    /**\n     * Sets the image on which the filter should be applied from a File.\n     *\n     * @param file the file of the new image\n     */\n    public void setImage(final File file) {\n        gpuImage.setImage(file);\n    }\n\n    public void requestRender() {\n        if (surfaceView instanceof GLSurfaceView) {\n            ((GLSurfaceView) surfaceView).requestRender();\n        } else if (surfaceView instanceof GLTextureView) {\n            ((GLTextureView) surfaceView).requestRender();\n        }\n    }\n\n    /**\n     * Save current image with applied filter to Pictures. It will be stored on\n     * the default Picture folder on the phone below the given folderName and\n     * fileName. <br>\n     * This method is async and will notify when the image was saved through the\n     * listener.\n     *\n     * @param folderName the folder name\n     * @param fileName   the file name\n     * @param listener   the listener\n     */\n    public void saveToPictures(final String folderName, final String fileName,\n                               final OnPictureSavedListener listener) {\n        new SaveTask(folderName, fileName, listener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);\n    }\n\n    /**\n     * Save current image with applied filter to Pictures. It will be stored on\n     * the default Picture folder on the phone below the given folderName and\n     * fileName. <br>\n     * This method is async and will notify when the image was saved through the\n     * listener.\n     *\n     * @param folderName the folder name\n     * @param fileName   the file name\n     * @param width      requested output width\n     * @param height     requested output height\n     * @param listener   the listener\n     */\n    public void saveToPictures(final String folderName, final String fileName,\n                               int width, int height,\n                               final OnPictureSavedListener listener) {\n        new SaveTask(folderName, fileName, width, height, listener).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);\n    }\n\n    /**\n     * Retrieve current image with filter applied and given size as Bitmap.\n     *\n     * @param width  requested Bitmap width\n     * @param height requested Bitmap height\n     * @return Bitmap of picture with given size\n     * @throws InterruptedException\n     */\n    public Bitmap capture(final int width, final int height) throws InterruptedException {\n        // This method needs to run on a background thread because it will take a longer time\n        if (Looper.myLooper() == Looper.getMainLooper()) {\n            throw new IllegalStateException(\"Do not call this method from the UI thread!\");\n        }\n\n        forceSize = new Size(width, height);\n\n        final Semaphore waiter = new Semaphore(0);\n\n        // Layout with new size\n        getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {\n            @Override\n            public void onGlobalLayout() {\n                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {\n                    getViewTreeObserver().removeGlobalOnLayoutListener(this);\n                } else {\n                    getViewTreeObserver().removeOnGlobalLayoutListener(this);\n                }\n                waiter.release();\n            }\n        });\n\n        post(new Runnable() {\n            @Override\n            public void run() {\n                // Optionally, show loading view:\n                if (isShowLoading) {\n                    addView(new LoadingView(getContext()));\n                }\n                // Request layout to release waiter:\n                surfaceView.requestLayout();\n            }\n        });\n\n        waiter.acquire();\n\n        // Run one render pass\n        gpuImage.runOnGLThread(new Runnable() {\n            @Override\n            public void run() {\n                waiter.release();\n            }\n        });\n        requestRender();\n        waiter.acquire();\n        Bitmap bitmap = capture();\n\n\n        forceSize = null;\n        post(new Runnable() {\n            @Override\n            public void run() {\n                surfaceView.requestLayout();\n            }\n        });\n        requestRender();\n\n        if (isShowLoading) {\n            postDelayed(new Runnable() {\n                @Override\n                public void run() {\n                    // Remove loading view\n                    removeViewAt(1);\n                }\n            }, 300);\n        }\n\n        return bitmap;\n    }\n\n    /**\n     * Capture the current image with the size as it is displayed and retrieve it as Bitmap.\n     *\n     * @return current output as Bitmap\n     * @throws InterruptedException\n     */\n    public Bitmap capture() throws InterruptedException {\n        final Semaphore waiter = new Semaphore(0);\n\n        final int width = surfaceView.getMeasuredWidth();\n        final int height = surfaceView.getMeasuredHeight();\n\n        // Take picture on OpenGL thread\n        final Bitmap resultBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);\n        gpuImage.runOnGLThread(new Runnable() {\n            @Override\n            public void run() {\n                GPUImageNativeLibrary.adjustBitmap(resultBitmap);\n                waiter.release();\n            }\n        });\n        requestRender();\n        waiter.acquire();\n\n        return resultBitmap;\n    }\n\n    /**\n     * Pauses the Surface.\n     */\n    public void onPause() {\n        if (surfaceView instanceof GLSurfaceView) {\n            ((GLSurfaceView) surfaceView).onPause();\n        } else if (surfaceView instanceof GLTextureView) {\n            ((GLTextureView) surfaceView).onPause();\n        }\n    }\n\n    /**\n     * Resumes the Surface.\n     */\n    public void onResume() {\n        if (surfaceView instanceof GLSurfaceView) {\n            ((GLSurfaceView) surfaceView).onResume();\n        } else if (surfaceView instanceof GLTextureView) {\n            ((GLTextureView) surfaceView).onResume();\n        }\n    }\n\n    public static class Size {\n        int width;\n        int height;\n\n        public Size(int width, int height) {\n            this.width = width;\n            this.height = height;\n        }\n    }\n\n    private class GPUImageGLSurfaceView extends GLSurfaceView {\n        public GPUImageGLSurfaceView(Context context) {\n            super(context);\n        }\n\n        public GPUImageGLSurfaceView(Context context, AttributeSet attrs) {\n            super(context, attrs);\n        }\n\n        @Override\n        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n            if (forceSize != null) {\n                super.onMeasure(MeasureSpec.makeMeasureSpec(forceSize.width, MeasureSpec.EXACTLY),\n                        MeasureSpec.makeMeasureSpec(forceSize.height, MeasureSpec.EXACTLY));\n            } else {\n                super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n            }\n        }\n    }\n\n    private class GPUImageGLTextureView extends GLTextureView {\n        public GPUImageGLTextureView(Context context) {\n            super(context);\n        }\n\n        public GPUImageGLTextureView(Context context, AttributeSet attrs) {\n            super(context, attrs);\n        }\n\n        @Override\n        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n            if (forceSize != null) {\n                super.onMeasure(MeasureSpec.makeMeasureSpec(forceSize.width, MeasureSpec.EXACTLY),\n                        MeasureSpec.makeMeasureSpec(forceSize.height, MeasureSpec.EXACTLY));\n            } else {\n                super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n            }\n        }\n    }\n\n    private class LoadingView extends FrameLayout {\n        public LoadingView(Context context) {\n            super(context);\n            init();\n        }\n\n        public LoadingView(Context context, AttributeSet attrs) {\n            super(context, attrs);\n            init();\n        }\n\n        public LoadingView(Context context, AttributeSet attrs, int defStyle) {\n            super(context, attrs, defStyle);\n            init();\n        }\n\n        private void init() {\n            ProgressBar view = new ProgressBar(getContext());\n            view.setLayoutParams(\n                    new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, Gravity.CENTER));\n            addView(view);\n            setBackgroundColor(Color.BLACK);\n        }\n    }\n\n    private class SaveTask extends AsyncTask<Void, Void, Void> {\n        private final String folderName;\n        private final String fileName;\n        private final int width;\n        private final int height;\n        private final OnPictureSavedListener listener;\n        private final Handler handler;\n\n        public SaveTask(final String folderName, final String fileName,\n                        final OnPictureSavedListener listener) {\n            this(folderName, fileName, 0, 0, listener);\n        }\n\n        public SaveTask(final String folderName, final String fileName, int width, int height,\n                        final OnPictureSavedListener listener) {\n            this.folderName = folderName;\n            this.fileName = fileName;\n            this.width = width;\n            this.height = height;\n            this.listener = listener;\n            handler = new Handler();\n        }\n\n        @Override\n        protected Void doInBackground(final Void... params) {\n            try {\n                Bitmap result = width != 0 ? capture(width, height) : capture();\n                saveImage(folderName, fileName, result);\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n            return null;\n        }\n\n        private void saveImage(final String folderName, final String fileName, final Bitmap image) {\n            File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);\n            File file = new File(path, folderName + \"/\" + fileName);\n            try {\n                file.getParentFile().mkdirs();\n                image.compress(Bitmap.CompressFormat.JPEG, 80, new FileOutputStream(file));\n                MediaScannerConnection.scanFile(getContext(),\n                        new String[]{\n                                file.toString()\n                        }, null,\n                        new MediaScannerConnection.OnScanCompletedListener() {\n                            @Override\n                            public void onScanCompleted(final String path, final Uri uri) {\n                                if (listener != null) {\n                                    handler.post(new Runnable() {\n\n                                        @Override\n                                        public void run() {\n                                            listener.onPictureSaved(uri);\n                                        }\n                                    });\n                                }\n                            }\n                        });\n            } catch (FileNotFoundException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    public interface OnPictureSavedListener {\n        void onPictureSaved(Uri uri);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/PixelBuffer.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n * Copyright (C) 2010 jsemler\n *\n * Original publication without License\n * http://www.anddev.org/android-2d-3d-graphics-opengl-tutorials-f2/possible-to-do-opengl-off-screen-rendering-in-android-t13232.html#p41662\n */\n\npackage jp.co.cyberagent.android.gpuimage;\n\nimport android.graphics.Bitmap;\nimport android.opengl.GLSurfaceView;\nimport android.util.Log;\n\nimport javax.microedition.khronos.egl.EGL10;\nimport javax.microedition.khronos.egl.EGLConfig;\nimport javax.microedition.khronos.egl.EGLContext;\nimport javax.microedition.khronos.egl.EGLDisplay;\nimport javax.microedition.khronos.egl.EGLSurface;\nimport javax.microedition.khronos.opengles.GL10;\n\nimport static javax.microedition.khronos.egl.EGL10.EGL_ALPHA_SIZE;\nimport static javax.microedition.khronos.egl.EGL10.EGL_BLUE_SIZE;\nimport static javax.microedition.khronos.egl.EGL10.EGL_DEFAULT_DISPLAY;\nimport static javax.microedition.khronos.egl.EGL10.EGL_DEPTH_SIZE;\nimport static javax.microedition.khronos.egl.EGL10.EGL_GREEN_SIZE;\nimport static javax.microedition.khronos.egl.EGL10.EGL_HEIGHT;\nimport static javax.microedition.khronos.egl.EGL10.EGL_NONE;\nimport static javax.microedition.khronos.egl.EGL10.EGL_NO_CONTEXT;\nimport static javax.microedition.khronos.egl.EGL10.EGL_RED_SIZE;\nimport static javax.microedition.khronos.egl.EGL10.EGL_STENCIL_SIZE;\nimport static javax.microedition.khronos.egl.EGL10.EGL_WIDTH;\n\npublic class PixelBuffer {\n    private final static String TAG = \"PixelBuffer\";\n    private final static boolean LIST_CONFIGS = false;\n\n    private GLSurfaceView.Renderer renderer; // borrow this interface\n    private int width, height;\n    private Bitmap bitmap;\n\n    private EGL10 egl10;\n    private EGLDisplay eglDisplay;\n    private EGLConfig[] eglConfigs;\n    private EGLConfig eglConfig;\n    private EGLContext eglContext;\n    private EGLSurface eglSurface;\n    private GL10 gl10;\n\n    private String mThreadOwner;\n\n    public PixelBuffer(final int width, final int height) {\n        this.width = width;\n        this.height = height;\n\n        int[] version = new int[2];\n        int[] attribList = new int[]{\n                EGL_WIDTH, this.width,\n                EGL_HEIGHT, this.height,\n                EGL_NONE\n        };\n\n        // No error checking performed, minimum required code to elucidate logic\n        egl10 = (EGL10) EGLContext.getEGL();\n        eglDisplay = egl10.eglGetDisplay(EGL_DEFAULT_DISPLAY);\n        egl10.eglInitialize(eglDisplay, version);\n        eglConfig = chooseConfig(); // Choosing a config is a little more\n        // complicated\n\n        // eglContext = egl10.eglCreateContext(eglDisplay, eglConfig,\n        // EGL_NO_CONTEXT, null);\n        int EGL_CONTEXT_CLIENT_VERSION = 0x3098;\n        int[] attrib_list = {\n                EGL_CONTEXT_CLIENT_VERSION, 2,\n                EGL10.EGL_NONE\n        };\n        eglContext = egl10.eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, attrib_list);\n\n        eglSurface = egl10.eglCreatePbufferSurface(eglDisplay, eglConfig, attribList);\n        egl10.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);\n\n        gl10 = (GL10) eglContext.getGL();\n\n        // Record thread owner of OpenGL context\n        mThreadOwner = Thread.currentThread().getName();\n    }\n\n    public void setRenderer(final GLSurfaceView.Renderer renderer) {\n        this.renderer = renderer;\n\n        // Does this thread own the OpenGL context?\n        if (!Thread.currentThread().getName().equals(mThreadOwner)) {\n            Log.e(TAG, \"setRenderer: This thread does not own the OpenGL context.\");\n            return;\n        }\n\n        // Call the renderer initialization routines\n        this.renderer.onSurfaceCreated(gl10, eglConfig);\n        this.renderer.onSurfaceChanged(gl10, width, height);\n    }\n\n    public Bitmap getBitmap() {\n        // Do we have a renderer?\n        if (renderer == null) {\n            Log.e(TAG, \"getBitmap: Renderer was not set.\");\n            return null;\n        }\n\n        // Does this thread own the OpenGL context?\n        if (!Thread.currentThread().getName().equals(mThreadOwner)) {\n            Log.e(TAG, \"getBitmap: This thread does not own the OpenGL context.\");\n            return null;\n        }\n\n        // Call the renderer draw routine (it seems that some filters do not\n        // work if this is only called once)\n        renderer.onDrawFrame(gl10);\n        renderer.onDrawFrame(gl10);\n        convertToBitmap();\n        return bitmap;\n    }\n\n    public void destroy() {\n        renderer.onDrawFrame(gl10);\n        renderer.onDrawFrame(gl10);\n        egl10.eglMakeCurrent(eglDisplay, EGL10.EGL_NO_SURFACE,\n                EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);\n\n        egl10.eglDestroySurface(eglDisplay, eglSurface);\n        egl10.eglDestroyContext(eglDisplay, eglContext);\n        egl10.eglTerminate(eglDisplay);\n    }\n\n    private EGLConfig chooseConfig() {\n        int[] attribList = new int[]{\n                EGL_DEPTH_SIZE, 0,\n                EGL_STENCIL_SIZE, 0,\n                EGL_RED_SIZE, 8,\n                EGL_GREEN_SIZE, 8,\n                EGL_BLUE_SIZE, 8,\n                EGL_ALPHA_SIZE, 8,\n                EGL10.EGL_RENDERABLE_TYPE, 4,\n                EGL_NONE\n        };\n\n        // No error checking performed, minimum required code to elucidate logic\n        // Expand on this logic to be more selective in choosing a configuration\n        int[] numConfig = new int[1];\n        egl10.eglChooseConfig(eglDisplay, attribList, null, 0, numConfig);\n        int configSize = numConfig[0];\n        eglConfigs = new EGLConfig[configSize];\n        egl10.eglChooseConfig(eglDisplay, attribList, eglConfigs, configSize, numConfig);\n\n        if (LIST_CONFIGS) {\n            listConfig();\n        }\n\n        return eglConfigs[0]; // Best match is probably the first configuration\n    }\n\n    private void listConfig() {\n        Log.i(TAG, \"Config List {\");\n\n        for (EGLConfig config : eglConfigs) {\n            int d, s, r, g, b, a;\n\n            // Expand on this logic to dump other attributes\n            d = getConfigAttrib(config, EGL_DEPTH_SIZE);\n            s = getConfigAttrib(config, EGL_STENCIL_SIZE);\n            r = getConfigAttrib(config, EGL_RED_SIZE);\n            g = getConfigAttrib(config, EGL_GREEN_SIZE);\n            b = getConfigAttrib(config, EGL_BLUE_SIZE);\n            a = getConfigAttrib(config, EGL_ALPHA_SIZE);\n            Log.i(TAG, \"    <d,s,r,g,b,a> = <\" + d + \",\" + s + \",\" +\n                    r + \",\" + g + \",\" + b + \",\" + a + \">\");\n        }\n\n        Log.i(TAG, \"}\");\n    }\n\n    private int getConfigAttrib(final EGLConfig config, final int attribute) {\n        int[] value = new int[1];\n        return egl10.eglGetConfigAttrib(eglDisplay, config,\n                attribute, value) ? value[0] : 0;\n    }\n\n    private void convertToBitmap() {\n        bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);\n        GPUImageNativeLibrary.adjustBitmap(bitmap);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImage3x3ConvolutionFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\n/**\n * Runs a 3x3 convolution kernel against the image\n */\npublic class GPUImage3x3ConvolutionFilter extends GPUImage3x3TextureSamplingFilter {\n    public static final String THREE_X_THREE_TEXTURE_SAMPLING_FRAGMENT_SHADER = \"\" +\n            \"precision highp float;\\n\" +\n            \"\\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"\\n\" +\n            \"uniform mediump mat3 convolutionMatrix;\\n\" +\n            \"\\n\" +\n            \"varying vec2 textureCoordinate;\\n\" +\n            \"varying vec2 leftTextureCoordinate;\\n\" +\n            \"varying vec2 rightTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"varying vec2 topTextureCoordinate;\\n\" +\n            \"varying vec2 topLeftTextureCoordinate;\\n\" +\n            \"varying vec2 topRightTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"varying vec2 bottomTextureCoordinate;\\n\" +\n            \"varying vec2 bottomLeftTextureCoordinate;\\n\" +\n            \"varying vec2 bottomRightTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"    mediump vec4 bottomColor = texture2D(inputImageTexture, bottomTextureCoordinate);\\n\" +\n            \"    mediump vec4 bottomLeftColor = texture2D(inputImageTexture, bottomLeftTextureCoordinate);\\n\" +\n            \"    mediump vec4 bottomRightColor = texture2D(inputImageTexture, bottomRightTextureCoordinate);\\n\" +\n            \"    mediump vec4 centerColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"    mediump vec4 leftColor = texture2D(inputImageTexture, leftTextureCoordinate);\\n\" +\n            \"    mediump vec4 rightColor = texture2D(inputImageTexture, rightTextureCoordinate);\\n\" +\n            \"    mediump vec4 topColor = texture2D(inputImageTexture, topTextureCoordinate);\\n\" +\n            \"    mediump vec4 topRightColor = texture2D(inputImageTexture, topRightTextureCoordinate);\\n\" +\n            \"    mediump vec4 topLeftColor = texture2D(inputImageTexture, topLeftTextureCoordinate);\\n\" +\n            \"\\n\" +\n            \"    mediump vec4 resultColor = topLeftColor * convolutionMatrix[0][0] + topColor * convolutionMatrix[0][1] + topRightColor * convolutionMatrix[0][2];\\n\" +\n            \"    resultColor += leftColor * convolutionMatrix[1][0] + centerColor * convolutionMatrix[1][1] + rightColor * convolutionMatrix[1][2];\\n\" +\n            \"    resultColor += bottomLeftColor * convolutionMatrix[2][0] + bottomColor * convolutionMatrix[2][1] + bottomRightColor * convolutionMatrix[2][2];\\n\" +\n            \"\\n\" +\n            \"    gl_FragColor = resultColor;\\n\" +\n            \"}\";\n\n    private float[] convolutionKernel;\n    private int uniformConvolutionMatrix;\n\n    /**\n     * Instantiates a new GPUimage3x3ConvolutionFilter with default values, that\n     * will look like the original image.\n     */\n    public GPUImage3x3ConvolutionFilter() {\n        this(new float[]{\n                0.0f, 0.0f, 0.0f,\n                0.0f, 1.0f, 0.0f,\n                0.0f, 0.0f, 0.0f\n        });\n    }\n\n    /**\n     * Instantiates a new GPUimage3x3ConvolutionFilter with given convolution kernel.\n     *\n     * @param convolutionKernel the convolution kernel\n     */\n    public GPUImage3x3ConvolutionFilter(final float[] convolutionKernel) {\n        super(THREE_X_THREE_TEXTURE_SAMPLING_FRAGMENT_SHADER);\n        this.convolutionKernel = convolutionKernel;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        uniformConvolutionMatrix = GLES20.glGetUniformLocation(getProgram(), \"convolutionMatrix\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setConvolutionKernel(convolutionKernel);\n    }\n\n    /**\n     * Sets the convolution kernel.\n     *\n     * @param convolutionKernel the new convolution kernel\n     */\n    public void setConvolutionKernel(final float[] convolutionKernel) {\n        this.convolutionKernel = convolutionKernel;\n        setUniformMatrix3f(uniformConvolutionMatrix, this.convolutionKernel);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImage3x3TextureSamplingFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\npublic class GPUImage3x3TextureSamplingFilter extends GPUImageFilter {\n    public static final String THREE_X_THREE_TEXTURE_SAMPLING_VERTEX_SHADER = \"\" +\n            \"attribute vec4 position;\\n\" +\n            \"attribute vec4 inputTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"uniform highp float texelWidth; \\n\" +\n            \"uniform highp float texelHeight; \\n\" +\n            \"\\n\" +\n            \"varying vec2 textureCoordinate;\\n\" +\n            \"varying vec2 leftTextureCoordinate;\\n\" +\n            \"varying vec2 rightTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"varying vec2 topTextureCoordinate;\\n\" +\n            \"varying vec2 topLeftTextureCoordinate;\\n\" +\n            \"varying vec2 topRightTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"varying vec2 bottomTextureCoordinate;\\n\" +\n            \"varying vec2 bottomLeftTextureCoordinate;\\n\" +\n            \"varying vec2 bottomRightTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"    gl_Position = position;\\n\" +\n            \"\\n\" +\n            \"    vec2 widthStep = vec2(texelWidth, 0.0);\\n\" +\n            \"    vec2 heightStep = vec2(0.0, texelHeight);\\n\" +\n            \"    vec2 widthHeightStep = vec2(texelWidth, texelHeight);\\n\" +\n            \"    vec2 widthNegativeHeightStep = vec2(texelWidth, -texelHeight);\\n\" +\n            \"\\n\" +\n            \"    textureCoordinate = inputTextureCoordinate.xy;\\n\" +\n            \"    leftTextureCoordinate = inputTextureCoordinate.xy - widthStep;\\n\" +\n            \"    rightTextureCoordinate = inputTextureCoordinate.xy + widthStep;\\n\" +\n            \"\\n\" +\n            \"    topTextureCoordinate = inputTextureCoordinate.xy - heightStep;\\n\" +\n            \"    topLeftTextureCoordinate = inputTextureCoordinate.xy - widthHeightStep;\\n\" +\n            \"    topRightTextureCoordinate = inputTextureCoordinate.xy + widthNegativeHeightStep;\\n\" +\n            \"\\n\" +\n            \"    bottomTextureCoordinate = inputTextureCoordinate.xy + heightStep;\\n\" +\n            \"    bottomLeftTextureCoordinate = inputTextureCoordinate.xy - widthNegativeHeightStep;\\n\" +\n            \"    bottomRightTextureCoordinate = inputTextureCoordinate.xy + widthHeightStep;\\n\" +\n            \"}\";\n\n    private int uniformTexelWidthLocation;\n    private int uniformTexelHeightLocation;\n\n    private boolean hasOverriddenImageSizeFactor = false;\n    private float texelWidth;\n    private float texelHeight;\n    private float lineSize = 1.0f;\n\n    public GPUImage3x3TextureSamplingFilter() {\n        this(NO_FILTER_VERTEX_SHADER);\n    }\n\n    public GPUImage3x3TextureSamplingFilter(final String fragmentShader) {\n        super(THREE_X_THREE_TEXTURE_SAMPLING_VERTEX_SHADER, fragmentShader);\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        uniformTexelWidthLocation = GLES20.glGetUniformLocation(getProgram(), \"texelWidth\");\n        uniformTexelHeightLocation = GLES20.glGetUniformLocation(getProgram(), \"texelHeight\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        if (texelWidth != 0) {\n            updateTexelValues();\n        }\n    }\n\n    @Override\n    public void onOutputSizeChanged(final int width, final int height) {\n        super.onOutputSizeChanged(width, height);\n        if (!hasOverriddenImageSizeFactor) {\n            setLineSize(lineSize);\n        }\n    }\n\n    public void setTexelWidth(final float texelWidth) {\n        hasOverriddenImageSizeFactor = true;\n        this.texelWidth = texelWidth;\n        setFloat(uniformTexelWidthLocation, texelWidth);\n    }\n\n    public void setTexelHeight(final float texelHeight) {\n        hasOverriddenImageSizeFactor = true;\n        this.texelHeight = texelHeight;\n        setFloat(uniformTexelHeightLocation, texelHeight);\n    }\n\n    public void setLineSize(final float size) {\n        lineSize = size;\n        texelWidth = size / getOutputWidth();\n        texelHeight = size / getOutputHeight();\n        updateTexelValues();\n    }\n\n    private void updateTexelValues() {\n        setFloat(uniformTexelWidthLocation, texelWidth);\n        setFloat(uniformTexelHeightLocation, texelHeight);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageAddBlendFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\npublic class GPUImageAddBlendFilter extends GPUImageTwoInputFilter {\n    public static final String ADD_BLEND_FRAGMENT_SHADER = \"varying highp vec2 textureCoordinate;\\n\" +\n            \" varying highp vec2 textureCoordinate2;\\n\" +\n            \"\\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform sampler2D inputImageTexture2;\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"   lowp vec4 base = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"   lowp vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);\\n\" +\n            \"\\n\" +\n            \"   mediump float r;\\n\" +\n            \"   if (overlay.r * base.a + base.r * overlay.a >= overlay.a * base.a) {\\n\" +\n            \"     r = overlay.a * base.a + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);\\n\" +\n            \"   } else {\\n\" +\n            \"     r = overlay.r + base.r;\\n\" +\n            \"   }\\n\" +\n            \"\\n\" +\n            \"   mediump float g;\\n\" +\n            \"   if (overlay.g * base.a + base.g * overlay.a >= overlay.a * base.a) {\\n\" +\n            \"     g = overlay.a * base.a + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);\\n\" +\n            \"   } else {\\n\" +\n            \"     g = overlay.g + base.g;\\n\" +\n            \"   }\\n\" +\n            \"\\n\" +\n            \"   mediump float b;\\n\" +\n            \"   if (overlay.b * base.a + base.b * overlay.a >= overlay.a * base.a) {\\n\" +\n            \"     b = overlay.a * base.a + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);\\n\" +\n            \"   } else {\\n\" +\n            \"     b = overlay.b + base.b;\\n\" +\n            \"   }\\n\" +\n            \"\\n\" +\n            \"   mediump float a = overlay.a + base.a - overlay.a * base.a;\\n\" +\n            \"   \\n\" +\n            \"   gl_FragColor = vec4(r, g, b, a);\\n\" +\n            \" }\";\n\n    public GPUImageAddBlendFilter() {\n        super(ADD_BLEND_FRAGMENT_SHADER);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageAlphaBlendFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\n/**\n * Mix ranges from 0.0 (only image 1) to 1.0 (only image 2), with 0.5 (half of either) as the normal level\n */\npublic class GPUImageAlphaBlendFilter extends GPUImageMixBlendFilter {\n    public static final String ALPHA_BLEND_FRAGMENT_SHADER = \"varying highp vec2 textureCoordinate;\\n\" +\n            \" varying highp vec2 textureCoordinate2;\\n\" +\n            \"\\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform sampler2D inputImageTexture2;\\n\" +\n            \" \\n\" +\n            \" uniform lowp float mixturePercent;\\n\" +\n            \"\\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"   lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"   lowp vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);\\n\" +\n            \"\\n\" +\n            \"   gl_FragColor = vec4(mix(textureColor.rgb, textureColor2.rgb, textureColor2.a * mixturePercent), textureColor.a);\\n\" +\n            \" }\";\n\n    public GPUImageAlphaBlendFilter() {\n        super(ALPHA_BLEND_FRAGMENT_SHADER);\n    }\n\n    public GPUImageAlphaBlendFilter(float mix) {\n        super(ALPHA_BLEND_FRAGMENT_SHADER, mix);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageBilateralBlurFilter.java",
    "content": "/**\n * @author wysaid\n * @mail admin@wysaid.org\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\n\npublic class GPUImageBilateralBlurFilter extends GPUImageFilter {\n    public static final String BILATERAL_VERTEX_SHADER = \"\" +\n            \"attribute vec4 position;\\n\" +\n            \"attribute vec4 inputTextureCoordinate;\\n\" +\n\n            \"const int GAUSSIAN_SAMPLES = 9;\\n\" +\n\n            \"uniform vec2 singleStepOffset;\\n\" +\n\n            \"varying vec2 textureCoordinate;\\n\" +\n            \"varying vec2 blurCoordinates[GAUSSIAN_SAMPLES];\\n\" +\n\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"\tgl_Position = position;\\n\" +\n            \"\ttextureCoordinate = inputTextureCoordinate.xy;\\n\" +\n\n            \"\tint multiplier = 0;\\n\" +\n            \"\tvec2 blurStep;\\n\" +\n\n            \"\tfor (int i = 0; i < GAUSSIAN_SAMPLES; i++)\\n\" +\n            \"\t{\\n\" +\n            \"\t\tmultiplier = (i - ((GAUSSIAN_SAMPLES - 1) / 2));\\n\" +\n\n            \"\t\tblurStep = float(multiplier) * singleStepOffset;\\n\" +\n            \"\t\tblurCoordinates[i] = inputTextureCoordinate.xy + blurStep;\\n\" +\n            \"\t}\\n\" +\n            \"}\";\n\n    public static final String BILATERAL_FRAGMENT_SHADER = \"\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n\n            \" const lowp int GAUSSIAN_SAMPLES = 9;\\n\" +\n\n            \" varying highp vec2 textureCoordinate;\\n\" +\n            \" varying highp vec2 blurCoordinates[GAUSSIAN_SAMPLES];\\n\" +\n\n            \" uniform mediump float distanceNormalizationFactor;\\n\" +\n\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"     lowp vec4 centralColor;\\n\" +\n            \"     lowp float gaussianWeightTotal;\\n\" +\n            \"     lowp vec4 sum;\\n\" +\n            \"     lowp vec4 sampleColor;\\n\" +\n            \"     lowp float distanceFromCentralColor;\\n\" +\n            \"     lowp float gaussianWeight;\\n\" +\n            \"     \\n\" +\n            \"     centralColor = texture2D(inputImageTexture, blurCoordinates[4]);\\n\" +\n            \"     gaussianWeightTotal = 0.18;\\n\" +\n            \"     sum = centralColor * 0.18;\\n\" +\n            \"     \\n\" +\n            \"     sampleColor = texture2D(inputImageTexture, blurCoordinates[0]);\\n\" +\n            \"     distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);\\n\" +\n            \"     gaussianWeight = 0.05 * (1.0 - distanceFromCentralColor);\\n\" +\n            \"     gaussianWeightTotal += gaussianWeight;\\n\" +\n            \"     sum += sampleColor * gaussianWeight;\\n\" +\n\n            \"     sampleColor = texture2D(inputImageTexture, blurCoordinates[1]);\\n\" +\n            \"     distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);\\n\" +\n            \"     gaussianWeight = 0.09 * (1.0 - distanceFromCentralColor);\\n\" +\n            \"     gaussianWeightTotal += gaussianWeight;\\n\" +\n            \"     sum += sampleColor * gaussianWeight;\\n\" +\n\n            \"     sampleColor = texture2D(inputImageTexture, blurCoordinates[2]);\\n\" +\n            \"     distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);\\n\" +\n            \"     gaussianWeight = 0.12 * (1.0 - distanceFromCentralColor);\\n\" +\n            \"     gaussianWeightTotal += gaussianWeight;\\n\" +\n            \"     sum += sampleColor * gaussianWeight;\\n\" +\n\n            \"     sampleColor = texture2D(inputImageTexture, blurCoordinates[3]);\\n\" +\n            \"     distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);\\n\" +\n            \"     gaussianWeight = 0.15 * (1.0 - distanceFromCentralColor);\\n\" +\n            \"     gaussianWeightTotal += gaussianWeight;\\n\" +\n            \"     sum += sampleColor * gaussianWeight;\\n\" +\n\n            \"     sampleColor = texture2D(inputImageTexture, blurCoordinates[5]);\\n\" +\n            \"     distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);\\n\" +\n            \"     gaussianWeight = 0.15 * (1.0 - distanceFromCentralColor);\\n\" +\n            \"     gaussianWeightTotal += gaussianWeight;\\n\" +\n            \"     sum += sampleColor * gaussianWeight;\\n\" +\n\n            \"     sampleColor = texture2D(inputImageTexture, blurCoordinates[6]);\\n\" +\n            \"     distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);\\n\" +\n            \"     gaussianWeight = 0.12 * (1.0 - distanceFromCentralColor);\\n\" +\n            \"     gaussianWeightTotal += gaussianWeight;\\n\" +\n            \"     sum += sampleColor * gaussianWeight;\\n\" +\n\n            \"     sampleColor = texture2D(inputImageTexture, blurCoordinates[7]);\\n\" +\n            \"     distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);\\n\" +\n            \"     gaussianWeight = 0.09 * (1.0 - distanceFromCentralColor);\\n\" +\n            \"     gaussianWeightTotal += gaussianWeight;\\n\" +\n            \"     sum += sampleColor * gaussianWeight;\\n\" +\n\n            \"     sampleColor = texture2D(inputImageTexture, blurCoordinates[8]);\\n\" +\n            \"     distanceFromCentralColor = min(distance(centralColor, sampleColor) * distanceNormalizationFactor, 1.0);\\n\" +\n            \"     gaussianWeight = 0.05 * (1.0 - distanceFromCentralColor);\\n\" +\n            \"     gaussianWeightTotal += gaussianWeight;\\n\" +\n            \"     sum += sampleColor * gaussianWeight;\\n\" +\n            \"     gl_FragColor = sum / gaussianWeightTotal;\\n\" +\n            \" }\";\n\n    private float distanceNormalizationFactor;\n    private int disFactorLocation;\n    private int singleStepOffsetLocation;\n\n    public GPUImageBilateralBlurFilter() {\n        this(8.0f);\n    }\n\n    public GPUImageBilateralBlurFilter(final float distanceNormalizationFactor) {\n        super(BILATERAL_VERTEX_SHADER, BILATERAL_FRAGMENT_SHADER);\n        this.distanceNormalizationFactor = distanceNormalizationFactor;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        disFactorLocation = GLES20.glGetUniformLocation(getProgram(), \"distanceNormalizationFactor\");\n        singleStepOffsetLocation = GLES20.glGetUniformLocation(getProgram(), \"singleStepOffset\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setDistanceNormalizationFactor(distanceNormalizationFactor);\n    }\n\n    public void setDistanceNormalizationFactor(final float newValue) {\n        distanceNormalizationFactor = newValue;\n        setFloat(disFactorLocation, newValue);\n    }\n\n    private void setTexelSize(final float w, final float h) {\n        setFloatVec2(singleStepOffsetLocation, new float[]{1.0f / w, 1.0f / h});\n    }\n\n    @Override\n    public void onOutputSizeChanged(final int width, final int height) {\n        super.onOutputSizeChanged(width, height);\n        setTexelSize(width, height);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageBoxBlurFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\n/**\n * A hardware-accelerated 9-hit box blur of an image\n * <p>\n * scaling: for the size of the applied blur, default of 1.0\n */\npublic class GPUImageBoxBlurFilter extends GPUImageTwoPassTextureSamplingFilter {\n    public static final String VERTEX_SHADER =\n            \"attribute vec4 position;\\n\" +\n                    \"attribute vec2 inputTextureCoordinate;\\n\" +\n                    \"\\n\" +\n                    \"uniform float texelWidthOffset; \\n\" +\n                    \"uniform float texelHeightOffset; \\n\" +\n                    \"\\n\" +\n                    \"varying vec2 centerTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepLeftTextureCoordinate;\\n\" +\n                    \"varying vec2 twoStepsLeftTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepRightTextureCoordinate;\\n\" +\n                    \"varying vec2 twoStepsRightTextureCoordinate;\\n\" +\n                    \"\\n\" +\n                    \"void main()\\n\" +\n                    \"{\\n\" +\n                    \"gl_Position = position;\\n\" +\n                    \"\\n\" +\n                    \"vec2 firstOffset = vec2(1.5 * texelWidthOffset, 1.5 * texelHeightOffset);\\n\" +\n                    \"vec2 secondOffset = vec2(3.5 * texelWidthOffset, 3.5 * texelHeightOffset);\\n\" +\n                    \"\\n\" +\n                    \"centerTextureCoordinate = inputTextureCoordinate;\\n\" +\n                    \"oneStepLeftTextureCoordinate = inputTextureCoordinate - firstOffset;\\n\" +\n                    \"twoStepsLeftTextureCoordinate = inputTextureCoordinate - secondOffset;\\n\" +\n                    \"oneStepRightTextureCoordinate = inputTextureCoordinate + firstOffset;\\n\" +\n                    \"twoStepsRightTextureCoordinate = inputTextureCoordinate + secondOffset;\\n\" +\n                    \"}\\n\";\n\n    public static final String FRAGMENT_SHADER =\n            \"precision highp float;\\n\" +\n                    \"\\n\" +\n                    \"uniform sampler2D inputImageTexture;\\n\" +\n                    \"\\n\" +\n                    \"varying vec2 centerTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepLeftTextureCoordinate;\\n\" +\n                    \"varying vec2 twoStepsLeftTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepRightTextureCoordinate;\\n\" +\n                    \"varying vec2 twoStepsRightTextureCoordinate;\\n\" +\n                    \"\\n\" +\n                    \"void main()\\n\" +\n                    \"{\\n\" +\n                    \"lowp vec4 fragmentColor = texture2D(inputImageTexture, centerTextureCoordinate) * 0.2;\\n\" +\n                    \"fragmentColor += texture2D(inputImageTexture, oneStepLeftTextureCoordinate) * 0.2;\\n\" +\n                    \"fragmentColor += texture2D(inputImageTexture, oneStepRightTextureCoordinate) * 0.2;\\n\" +\n                    \"fragmentColor += texture2D(inputImageTexture, twoStepsLeftTextureCoordinate) * 0.2;\\n\" +\n                    \"fragmentColor += texture2D(inputImageTexture, twoStepsRightTextureCoordinate) * 0.2;\\n\" +\n                    \"\\n\" +\n                    \"gl_FragColor = fragmentColor;\\n\" +\n                    \"}\\n\";\n\n    private float blurSize;\n\n    /**\n     * Construct new BoxBlurFilter with default blur size of 1.0.\n     */\n    public GPUImageBoxBlurFilter() {\n        this(1f);\n    }\n\n\n    public GPUImageBoxBlurFilter(float blurSize) {\n        super(VERTEX_SHADER, FRAGMENT_SHADER, VERTEX_SHADER, FRAGMENT_SHADER);\n        this.blurSize = blurSize;\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setBlurSize(blurSize);\n    }\n\n    /**\n     * A scaling for the size of the applied blur, default of 1.0\n     *\n     * @param blurSize\n     */\n    public void setBlurSize(float blurSize) {\n        this.blurSize = blurSize;\n        runOnDraw(new Runnable() {\n            @Override\n            public void run() {\n                initTexelOffsets();\n            }\n        });\n    }\n\n    @Override\n    public float getVerticalTexelOffsetRatio() {\n        return blurSize;\n    }\n\n    @Override\n    public float getHorizontalTexelOffsetRatio() {\n        return blurSize;\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageBrightnessFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\n/**\n * brightness value ranges from -1.0 to 1.0, with 0.0 as the normal level\n */\npublic class GPUImageBrightnessFilter extends GPUImageFilter {\n    public static final String BRIGHTNESS_FRAGMENT_SHADER = \"\" +\n            \"varying highp vec2 textureCoordinate;\\n\" +\n            \" \\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform lowp float brightness;\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"     lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"     \\n\" +\n            \"     gl_FragColor = vec4((textureColor.rgb + vec3(brightness)), textureColor.w);\\n\" +\n            \" }\";\n\n    private int brightnessLocation;\n    private float brightness;\n\n    public GPUImageBrightnessFilter() {\n        this(0.0f);\n    }\n\n    public GPUImageBrightnessFilter(final float brightness) {\n        super(NO_FILTER_VERTEX_SHADER, BRIGHTNESS_FRAGMENT_SHADER);\n        this.brightness = brightness;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        brightnessLocation = GLES20.glGetUniformLocation(getProgram(), \"brightness\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setBrightness(brightness);\n    }\n\n    public void setBrightness(final float brightness) {\n        this.brightness = brightness;\n        setFloat(brightnessLocation, this.brightness);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageBulgeDistortionFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.graphics.PointF;\nimport android.opengl.GLES20;\n\npublic class GPUImageBulgeDistortionFilter extends GPUImageFilter {\n    public static final String BULGE_FRAGMENT_SHADER = \"\" +\n            \"varying highp vec2 textureCoordinate;\\n\" +\n            \"\\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"\\n\" +\n            \"uniform highp float aspectRatio;\\n\" +\n            \"uniform highp vec2 center;\\n\" +\n            \"uniform highp float radius;\\n\" +\n            \"uniform highp float scale;\\n\" +\n            \"\\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"highp vec2 textureCoordinateToUse = vec2(textureCoordinate.x, (textureCoordinate.y * aspectRatio + 0.5 - 0.5 * aspectRatio));\\n\" +\n            \"highp float dist = distance(center, textureCoordinateToUse);\\n\" +\n            \"textureCoordinateToUse = textureCoordinate;\\n\" +\n            \"\\n\" +\n            \"if (dist < radius)\\n\" +\n            \"{\\n\" +\n            \"textureCoordinateToUse -= center;\\n\" +\n            \"highp float percent = 1.0 - ((radius - dist) / radius) * scale;\\n\" +\n            \"percent = percent * percent;\\n\" +\n            \"\\n\" +\n            \"textureCoordinateToUse = textureCoordinateToUse * percent;\\n\" +\n            \"textureCoordinateToUse += center;\\n\" +\n            \"}\\n\" +\n            \"\\n\" +\n            \"gl_FragColor = texture2D(inputImageTexture, textureCoordinateToUse );    \\n\" +\n            \"}\\n\";\n\n    private float scale;\n    private int scaleLocation;\n    private float radius;\n    private int radiusLocation;\n    private PointF center;\n    private int centerLocation;\n    private float aspectRatio;\n    private int aspectRatioLocation;\n\n    public GPUImageBulgeDistortionFilter() {\n        this(0.25f, 0.5f, new PointF(0.5f, 0.5f));\n    }\n\n    public GPUImageBulgeDistortionFilter(float radius, float scale, PointF center) {\n        super(NO_FILTER_VERTEX_SHADER, BULGE_FRAGMENT_SHADER);\n        this.radius = radius;\n        this.scale = scale;\n        this.center = center;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        scaleLocation = GLES20.glGetUniformLocation(getProgram(), \"scale\");\n        radiusLocation = GLES20.glGetUniformLocation(getProgram(), \"radius\");\n        centerLocation = GLES20.glGetUniformLocation(getProgram(), \"center\");\n        aspectRatioLocation = GLES20.glGetUniformLocation(getProgram(), \"aspectRatio\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setAspectRatio(aspectRatio);\n        setRadius(radius);\n        setScale(scale);\n        setCenter(center);\n    }\n\n    @Override\n    public void onOutputSizeChanged(int width, int height) {\n        aspectRatio = (float) height / width;\n        setAspectRatio(aspectRatio);\n        super.onOutputSizeChanged(width, height);\n    }\n\n    private void setAspectRatio(float aspectRatio) {\n        this.aspectRatio = aspectRatio;\n        setFloat(aspectRatioLocation, aspectRatio);\n    }\n\n    /**\n     * The radius of the distortion, ranging from 0.0 to 1.0, with a default of 0.25\n     *\n     * @param radius from 0.0 to 1.0, default 0.25\n     */\n    public void setRadius(float radius) {\n        this.radius = radius;\n        setFloat(radiusLocation, radius);\n    }\n\n    /**\n     * The amount of distortion to apply, from -1.0 to 1.0, with a default of 0.5\n     *\n     * @param scale from -1.0 to 1.0, default 0.5\n     */\n    public void setScale(float scale) {\n        this.scale = scale;\n        setFloat(scaleLocation, scale);\n    }\n\n    /**\n     * The center about which to apply the distortion, with a default of (0.5, 0.5)\n     *\n     * @param center default (0.5, 0.5)\n     */\n    public void setCenter(PointF center) {\n        this.center = center;\n        setPoint(centerLocation, center);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageCGAColorspaceFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\npublic class GPUImageCGAColorspaceFilter extends GPUImageFilter {\n    public static final String CGACOLORSPACE_FRAGMENT_SHADER = \"\" +\n            \"varying highp vec2 textureCoordinate;\\n\" +\n            \"\\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"\\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"highp vec2 sampleDivisor = vec2(1.0 / 200.0, 1.0 / 320.0);\\n\" +\n            \"//highp vec4 colorDivisor = vec4(colorDepth);\\n\" +\n            \"\\n\" +\n            \"highp vec2 samplePos = textureCoordinate - mod(textureCoordinate, sampleDivisor);\\n\" +\n            \"highp vec4 color = texture2D(inputImageTexture, samplePos );\\n\" +\n            \"\\n\" +\n            \"//gl_FragColor = texture2D(inputImageTexture, samplePos );\\n\" +\n            \"mediump vec4 colorCyan = vec4(85.0 / 255.0, 1.0, 1.0, 1.0);\\n\" +\n            \"mediump vec4 colorMagenta = vec4(1.0, 85.0 / 255.0, 1.0, 1.0);\\n\" +\n            \"mediump vec4 colorWhite = vec4(1.0, 1.0, 1.0, 1.0);\\n\" +\n            \"mediump vec4 colorBlack = vec4(0.0, 0.0, 0.0, 1.0);\\n\" +\n            \"\\n\" +\n            \"mediump vec4 endColor;\\n\" +\n            \"highp float blackDistance = distance(color, colorBlack);\\n\" +\n            \"highp float whiteDistance = distance(color, colorWhite);\\n\" +\n            \"highp float magentaDistance = distance(color, colorMagenta);\\n\" +\n            \"highp float cyanDistance = distance(color, colorCyan);\\n\" +\n            \"\\n\" +\n            \"mediump vec4 finalColor;\\n\" +\n            \"\\n\" +\n            \"highp float colorDistance = min(magentaDistance, cyanDistance);\\n\" +\n            \"colorDistance = min(colorDistance, whiteDistance);\\n\" +\n            \"colorDistance = min(colorDistance, blackDistance); \\n\" +\n            \"\\n\" +\n            \"if (colorDistance == blackDistance) {\\n\" +\n            \"finalColor = colorBlack;\\n\" +\n            \"} else if (colorDistance == whiteDistance) {\\n\" +\n            \"finalColor = colorWhite;\\n\" +\n            \"} else if (colorDistance == cyanDistance) {\\n\" +\n            \"finalColor = colorCyan;\\n\" +\n            \"} else {\\n\" +\n            \"finalColor = colorMagenta;\\n\" +\n            \"}\\n\" +\n            \"\\n\" +\n            \"gl_FragColor = finalColor;\\n\" +\n            \"}\\n\";\n\n    public GPUImageCGAColorspaceFilter() {\n        super(NO_FILTER_VERTEX_SHADER, CGACOLORSPACE_FRAGMENT_SHADER);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageChromaKeyBlendFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\n/**\n * Selectively replaces a color in the first image with the second image\n */\npublic class GPUImageChromaKeyBlendFilter extends GPUImageTwoInputFilter {\n    public static final String CHROMA_KEY_BLEND_FRAGMENT_SHADER = \" precision highp float;\\n\" +\n            \" \\n\" +\n            \" varying highp vec2 textureCoordinate;\\n\" +\n            \" varying highp vec2 textureCoordinate2;\\n\" +\n            \"\\n\" +\n            \" uniform float thresholdSensitivity;\\n\" +\n            \" uniform float smoothing;\\n\" +\n            \" uniform vec3 colorToReplace;\\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform sampler2D inputImageTexture2;\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"     vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"     vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);\\n\" +\n            \"     \\n\" +\n            \"     float maskY = 0.2989 * colorToReplace.r + 0.5866 * colorToReplace.g + 0.1145 * colorToReplace.b;\\n\" +\n            \"     float maskCr = 0.7132 * (colorToReplace.r - maskY);\\n\" +\n            \"     float maskCb = 0.5647 * (colorToReplace.b - maskY);\\n\" +\n            \"     \\n\" +\n            \"     float Y = 0.2989 * textureColor.r + 0.5866 * textureColor.g + 0.1145 * textureColor.b;\\n\" +\n            \"     float Cr = 0.7132 * (textureColor.r - Y);\\n\" +\n            \"     float Cb = 0.5647 * (textureColor.b - Y);\\n\" +\n            \"     \\n\" +\n            \"     float blendValue = 1.0 - smoothstep(thresholdSensitivity, thresholdSensitivity + smoothing, distance(vec2(Cr, Cb), vec2(maskCr, maskCb)));\\n\" +\n            \"     gl_FragColor = mix(textureColor, textureColor2, blendValue);\\n\" +\n            \" }\";\n\n    private int thresholdSensitivityLocation;\n    private int smoothingLocation;\n    private int colorToReplaceLocation;\n    private float thresholdSensitivity = 0.4f;\n    private float smoothing = 0.1f;\n    private float[] colorToReplace = new float[]{0.0f, 1.0f, 0.0f};\n\n    public GPUImageChromaKeyBlendFilter() {\n        super(CHROMA_KEY_BLEND_FRAGMENT_SHADER);\n\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        thresholdSensitivityLocation = GLES20.glGetUniformLocation(getProgram(), \"thresholdSensitivity\");\n        smoothingLocation = GLES20.glGetUniformLocation(getProgram(), \"smoothing\");\n        colorToReplaceLocation = GLES20.glGetUniformLocation(getProgram(), \"colorToReplace\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setSmoothing(smoothing);\n        setThresholdSensitivity(thresholdSensitivity);\n        setColorToReplace(colorToReplace[0], colorToReplace[1], colorToReplace[2]);\n    }\n\n    /**\n     * The degree of smoothing controls how gradually similar colors are replaced in the image\n     * The default value is 0.1\n     */\n    public void setSmoothing(final float smoothing) {\n        this.smoothing = smoothing;\n        setFloat(smoothingLocation, this.smoothing);\n    }\n\n    /**\n     * The threshold sensitivity controls how similar pixels need to be colored to be replaced\n     * The default value is 0.3\n     */\n    public void setThresholdSensitivity(final float thresholdSensitivity) {\n        this.thresholdSensitivity = thresholdSensitivity;\n        setFloat(thresholdSensitivityLocation, this.thresholdSensitivity);\n    }\n\n    /**\n     * The color to be replaced is specified using individual red, green, and blue components (normalized to 1.0).\n     * The default is green: (0.0, 1.0, 0.0).\n     *\n     * @param redComponent   Red component of color to be replaced\n     * @param greenComponent Green component of color to be replaced\n     * @param blueComponent  Blue component of color to be replaced\n     */\n    public void setColorToReplace(float redComponent, float greenComponent, float blueComponent) {\n        colorToReplace = new float[]{redComponent, greenComponent, blueComponent};\n        setFloatVec3(colorToReplaceLocation, colorToReplace);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageColorBalanceFilter.java",
    "content": "package jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\n/**\n * Created by edward_chiang on 13/10/16.\n */\npublic class GPUImageColorBalanceFilter extends GPUImageFilter {\n\n    public static final String GPU_IMAGE_COLOR_BALANCE_FRAGMENT_SHADER = \"\" +\n            \"varying highp vec2 textureCoordinate;\\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"uniform lowp vec3 shadowsShift;\\n\" +\n            \"uniform lowp vec3 midtonesShift;\\n\" +\n            \"uniform lowp vec3 highlightsShift;\\n\" +\n            \"uniform int preserveLuminosity;\\n\" +\n            \"lowp vec3 RGBToHSL(lowp vec3 color)\\n\" +\n\n            \"{\\n\" +\n            \"lowp vec3 hsl; // init to 0 to avoid warnings ? (and reverse if + remove first part)\\n\" +\n\n            \"lowp float fmin = min(min(color.r, color.g), color.b);    //Min. value of RGB\\n\" +\n            \"lowp float fmax = max(max(color.r, color.g), color.b);    //Max. value of RGB\\n\" +\n            \"lowp float delta = fmax - fmin;             //Delta RGB value\\n\" +\n\n            \"hsl.z = (fmax + fmin) / 2.0; // Luminance\\n\" +\n\n            \"if (delta == 0.0)\t\t//This is a gray, no chroma...\\n\" +\n            \"{\\n\" +\n            \"    hsl.x = 0.0;\t// Hue\\n\" +\n            \"    hsl.y = 0.0;\t// Saturation\\n\" +\n            \"}\\n\" +\n            \"else                                    //Chromatic data...\\n\" +\n            \"{\\n\" +\n            \"    if (hsl.z < 0.5)\\n\" +\n            \"        hsl.y = delta / (fmax + fmin); // Saturation\\n\" +\n            \"    else\\n\" +\n            \"        hsl.y = delta / (2.0 - fmax - fmin); // Saturation\\n\" +\n            \"\\n\" +\n            \"    lowp float deltaR = (((fmax - color.r) / 6.0) + (delta / 2.0)) / delta;\\n\" +\n            \"    lowp float deltaG = (((fmax - color.g) / 6.0) + (delta / 2.0)) / delta;\\n\" +\n            \"    lowp float deltaB = (((fmax - color.b) / 6.0) + (delta / 2.0)) / delta;\\n\" +\n            \"\\n\" +\n            \"    if (color.r == fmax )\\n\" +\n            \"        hsl.x = deltaB - deltaG; // Hue\\n\" +\n            \"    else if (color.g == fmax)\\n\" +\n            \"        hsl.x = (1.0 / 3.0) + deltaR - deltaB; // Hue\\n\" +\n            \"    else if (color.b == fmax)\\n\" +\n            \"        hsl.x = (2.0 / 3.0) + deltaG - deltaR; // Hue\\n\" +\n\n            \"    if (hsl.x < 0.0)\\n\" +\n            \"        hsl.x += 1.0; // Hue\\n\" +\n            \"    else if (hsl.x > 1.0)\\n\" +\n            \"        hsl.x -= 1.0; // Hue\\n\" +\n            \"}\\n\" +\n            \"\\n\" +\n            \"return hsl;\\n\" +\n            \"}\\n\" +\n\n            \"lowp float HueToRGB(lowp float f1, lowp float f2, lowp float hue)\\n\" +\n            \"{\\n\" +\n            \"    if (hue < 0.0)\\n\" +\n            \"        hue += 1.0;\\n\" +\n            \"    else if (hue > 1.0)\\n\" +\n            \"        hue -= 1.0;\\n\" +\n            \"    lowp float res;\\n\" +\n            \"    if ((6.0 * hue) < 1.0)\\n\" +\n            \"        res = f1 + (f2 - f1) * 6.0 * hue;\\n\" +\n            \"    else if ((2.0 * hue) < 1.0)\\n\" +\n            \"        res = f2;\\n\" +\n            \"    else if ((3.0 * hue) < 2.0)\\n\" +\n            \"        res = f1 + (f2 - f1) * ((2.0 / 3.0) - hue) * 6.0;\\n\" +\n            \"    else\\n\" +\n            \"        res = f1;\\n\" +\n            \"    return res;\\n\" +\n            \"}\\n\" +\n\n            \"lowp vec3 HSLToRGB(lowp vec3 hsl)\\n\" +\n            \"{\\n\" +\n            \"    lowp vec3 rgb;\\n\" +\n\n            \"    if (hsl.y == 0.0)\\n\" +\n            \"        rgb = vec3(hsl.z); // Luminance\\n\" +\n            \"    else\\n\" +\n            \"    {\\n\" +\n            \"        lowp float f2;\\n\" +\n\n            \"        if (hsl.z < 0.5)\\n\" +\n            \"            f2 = hsl.z * (1.0 + hsl.y);\\n\" +\n            \"        else\\n\" +\n            \"            f2 = (hsl.z + hsl.y) - (hsl.y * hsl.z);\\n\" +\n\n            \"        lowp float f1 = 2.0 * hsl.z - f2;\\n\" +\n\n            \"        rgb.r = HueToRGB(f1, f2, hsl.x + (1.0/3.0));\\n\" +\n            \"        rgb.g = HueToRGB(f1, f2, hsl.x);\\n\" +\n            \"        rgb.b= HueToRGB(f1, f2, hsl.x - (1.0/3.0));\\n\" +\n            \"    }\\n\" +\n\n            \"    return rgb;\\n  \" +\n            \"}\\n\" +\n\n            \"lowp float RGBToL(lowp vec3 color)\\n\" +\n            \"{\\n\" +\n            \"    lowp float fmin = min(min(color.r, color.g), color.b);    //Min. value of RGB\\n\" +\n            \"    lowp float fmax = max(max(color.r, color.g), color.b);    //Max. value of RGB\\n\" +\n\n            \"    return (fmax + fmin) / 2.0; // Luminance\\n\" +\n            \"}\\n\" +\n\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"    lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n\n            \"    // Alternative way:\\n\" +\n            \"    //lowp vec3 lightness = RGBToL(textureColor.rgb);\\n\" +\n            \"    lowp vec3 lightness = textureColor.rgb;\\n\" +\n\n            \"    const lowp float a = 0.25;\\n\" +\n            \"    const lowp float b = 0.333;\\n\" +\n            \"    const lowp float scale = 0.7;\\n\" +\n\n            \"    lowp vec3 shadows = shadowsShift * (clamp((lightness - b) / -a + 0.5, 0.0, 1.0) * scale);\\n\" +\n            \"    lowp vec3 midtones = midtonesShift * (clamp((lightness - b) / a + 0.5, 0.0, 1.0) *\\n\" +\n            \"        clamp((lightness + b - 1.0) / -a + 0.5, 0.0, 1.0) * scale);\\n\" +\n            \"    lowp vec3 highlights = highlightsShift * (clamp((lightness + b - 1.0) / a + 0.5, 0.0, 1.0) * scale);\\n\" +\n\n            \"    mediump vec3 newColor = textureColor.rgb + shadows + midtones + highlights;\\n\" +\n            \"    newColor = clamp(newColor, 0.0, 1.0);\\n    \" +\n\n            \"    if (preserveLuminosity != 0) {\\n   \" +\n            \"        lowp vec3 newHSL = RGBToHSL(newColor);\\n\" +\n            \"        lowp float oldLum = RGBToL(textureColor.rgb);\\n\" +\n            \"        textureColor.rgb = HSLToRGB(vec3(newHSL.x, newHSL.y, oldLum));\\n\" +\n            \"        gl_FragColor = textureColor;\\n\" +\n            \"    } else {\\n\" +\n            \"        gl_FragColor = vec4(newColor.rgb, textureColor.w);\\n\" +\n            \"    }\\n\" +\n            \"}\\n\";\n\n    private int shadowsLocation;\n    private int midtonesLocation;\n    private int highlightsLocation;\n    private int preserveLuminosityLocation;\n\n    private float[] showdows;\n    private float[] midtones;\n    private float[] highlights;\n    private boolean preserveLuminosity;\n\n\n    public GPUImageColorBalanceFilter() {\n        super(NO_FILTER_VERTEX_SHADER, GPU_IMAGE_COLOR_BALANCE_FRAGMENT_SHADER);\n        this.showdows = new float[]{0.0f, 0.0f, 0.0f};\n        this.midtones = new float[]{0.0f, 0.0f, 0.0f};\n        this.highlights = new float[]{0.0f, 0.0f, 0.0f};\n        this.preserveLuminosity = true;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        shadowsLocation = GLES20.glGetUniformLocation(getProgram(), \"shadowsShift\");\n        midtonesLocation = GLES20.glGetUniformLocation(getProgram(), \"midtonesShift\");\n        highlightsLocation = GLES20.glGetUniformLocation(getProgram(), \"highlightsShift\");\n        preserveLuminosityLocation = GLES20.glGetUniformLocation(getProgram(), \"preserveLuminosity\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setMidtones(midtones);\n        setShowdows(showdows);\n        setHighlights(highlights);\n        setPreserveLuminosity(preserveLuminosity);\n    }\n\n    public void setShowdows(float[] showdows) {\n        this.showdows = showdows;\n        setFloatVec3(shadowsLocation, showdows);\n    }\n\n    public void setMidtones(float[] midtones) {\n        this.midtones = midtones;\n        setFloatVec3(midtonesLocation, midtones);\n    }\n\n    public void setHighlights(float[] highlights) {\n        this.highlights = highlights;\n        setFloatVec3(highlightsLocation, highlights);\n    }\n\n    public void setPreserveLuminosity(boolean preserveLuminosity) {\n        this.preserveLuminosity = preserveLuminosity;\n        setInteger(preserveLuminosityLocation, preserveLuminosity ? 1 : 0);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageColorBlendFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\npublic class GPUImageColorBlendFilter extends GPUImageTwoInputFilter {\n    public static final String COLOR_BLEND_FRAGMENT_SHADER = \"varying highp vec2 textureCoordinate;\\n\" +\n            \" varying highp vec2 textureCoordinate2;\\n\" +\n            \" \\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform sampler2D inputImageTexture2;\\n\" +\n            \" \\n\" +\n            \" highp float lum(lowp vec3 c) {\\n\" +\n            \"     return dot(c, vec3(0.3, 0.59, 0.11));\\n\" +\n            \" }\\n\" +\n            \" \\n\" +\n            \" lowp vec3 clipcolor(lowp vec3 c) {\\n\" +\n            \"     highp float l = lum(c);\\n\" +\n            \"     lowp float n = min(min(c.r, c.g), c.b);\\n\" +\n            \"     lowp float x = max(max(c.r, c.g), c.b);\\n\" +\n            \"     \\n\" +\n            \"     if (n < 0.0) {\\n\" +\n            \"         c.r = l + ((c.r - l) * l) / (l - n);\\n\" +\n            \"         c.g = l + ((c.g - l) * l) / (l - n);\\n\" +\n            \"         c.b = l + ((c.b - l) * l) / (l - n);\\n\" +\n            \"     }\\n\" +\n            \"     if (x > 1.0) {\\n\" +\n            \"         c.r = l + ((c.r - l) * (1.0 - l)) / (x - l);\\n\" +\n            \"         c.g = l + ((c.g - l) * (1.0 - l)) / (x - l);\\n\" +\n            \"         c.b = l + ((c.b - l) * (1.0 - l)) / (x - l);\\n\" +\n            \"     }\\n\" +\n            \"     \\n\" +\n            \"     return c;\\n\" +\n            \" }\\n\" +\n            \"\\n\" +\n            \" lowp vec3 setlum(lowp vec3 c, highp float l) {\\n\" +\n            \"     highp float d = l - lum(c);\\n\" +\n            \"     c = c + vec3(d);\\n\" +\n            \"     return clipcolor(c);\\n\" +\n            \" }\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"   highp vec4 baseColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"   highp vec4 overlayColor = texture2D(inputImageTexture2, textureCoordinate2);\\n\" +\n            \"\\n\" +\n            \"     gl_FragColor = vec4(baseColor.rgb * (1.0 - overlayColor.a) + setlum(overlayColor.rgb, lum(baseColor.rgb)) * overlayColor.a, baseColor.a);\\n\" +\n            \" }\";\n\n    public GPUImageColorBlendFilter() {\n        super(COLOR_BLEND_FRAGMENT_SHADER);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageColorBurnBlendFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\npublic class GPUImageColorBurnBlendFilter extends GPUImageTwoInputFilter {\n    public static final String COLOR_BURN_BLEND_FRAGMENT_SHADER = \"varying highp vec2 textureCoordinate;\\n\" +\n            \" varying highp vec2 textureCoordinate2;\\n\" +\n            \"\\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform sampler2D inputImageTexture2;\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"    mediump vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"    mediump vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);\\n\" +\n            \"    mediump vec4 whiteColor = vec4(1.0);\\n\" +\n            \"    gl_FragColor = whiteColor - (whiteColor - textureColor) / textureColor2;\\n\" +\n            \" }\";\n\n    public GPUImageColorBurnBlendFilter() {\n        super(COLOR_BURN_BLEND_FRAGMENT_SHADER);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageColorDodgeBlendFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\npublic class GPUImageColorDodgeBlendFilter extends GPUImageTwoInputFilter {\n    public static final String COLOR_DODGE_BLEND_FRAGMENT_SHADER = \"precision mediump float;\\n\" +\n            \" \\n\" +\n            \" varying highp vec2 textureCoordinate;\\n\" +\n            \" varying highp vec2 textureCoordinate2;\\n\" +\n            \" \\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform sampler2D inputImageTexture2;\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"     vec4 base = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"     vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);\\n\" +\n            \"     \\n\" +\n            \"     vec3 baseOverlayAlphaProduct = vec3(overlay.a * base.a);\\n\" +\n            \"     vec3 rightHandProduct = overlay.rgb * (1.0 - base.a) + base.rgb * (1.0 - overlay.a);\\n\" +\n            \"     \\n\" +\n            \"     vec3 firstBlendColor = baseOverlayAlphaProduct + rightHandProduct;\\n\" +\n            \"     vec3 overlayRGB = clamp((overlay.rgb / clamp(overlay.a, 0.01, 1.0)) * step(0.0, overlay.a), 0.0, 0.99);\\n\" +\n            \"     \\n\" +\n            \"     vec3 secondBlendColor = (base.rgb * overlay.a) / (1.0 - overlayRGB) + rightHandProduct;\\n\" +\n            \"     \\n\" +\n            \"     vec3 colorChoice = step((overlay.rgb * base.a + base.rgb * overlay.a), baseOverlayAlphaProduct);\\n\" +\n            \"     \\n\" +\n            \"     gl_FragColor = vec4(mix(firstBlendColor, secondBlendColor, colorChoice), 1.0);\\n\" +\n            \" }\";\n\n    public GPUImageColorDodgeBlendFilter() {\n        super(COLOR_DODGE_BLEND_FRAGMENT_SHADER);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageColorInvertFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\n/**\n * Invert all the colors in the image.\n */\npublic class GPUImageColorInvertFilter extends GPUImageFilter {\n    public static final String COLOR_INVERT_FRAGMENT_SHADER = \"\" +\n            \"varying highp vec2 textureCoordinate;\\n\" +\n            \"\\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"\\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"    lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"    \\n\" +\n            \"    gl_FragColor = vec4((1.0 - textureColor.rgb), textureColor.w);\\n\" +\n            \"}\";\n\n    public GPUImageColorInvertFilter() {\n        super(NO_FILTER_VERTEX_SHADER, COLOR_INVERT_FRAGMENT_SHADER);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageColorMatrixFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\n/**\n * Applies a ColorMatrix to the image.\n */\npublic class GPUImageColorMatrixFilter extends GPUImageFilter {\n    public static final String COLOR_MATRIX_FRAGMENT_SHADER = \"\" +\n            \"varying highp vec2 textureCoordinate;\\n\" +\n            \"\\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"\\n\" +\n            \"uniform lowp mat4 colorMatrix;\\n\" +\n            \"uniform lowp float intensity;\\n\" +\n            \"\\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"    lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"    lowp vec4 outputColor = textureColor * colorMatrix;\\n\" +\n            \"    \\n\" +\n            \"    gl_FragColor = (intensity * outputColor) + ((1.0 - intensity) * textureColor);\\n\" +\n            \"}\";\n\n    private float intensity;\n    private float[] colorMatrix;\n    private int colorMatrixLocation;\n    private int intensityLocation;\n\n    public GPUImageColorMatrixFilter() {\n        this(1.0f, new float[]{\n                1.0f, 0.0f, 0.0f, 0.0f,\n                0.0f, 1.0f, 0.0f, 0.0f,\n                0.0f, 0.0f, 1.0f, 0.0f,\n                0.0f, 0.0f, 0.0f, 1.0f\n        });\n    }\n\n    public GPUImageColorMatrixFilter(final float intensity, final float[] colorMatrix) {\n        super(NO_FILTER_VERTEX_SHADER, COLOR_MATRIX_FRAGMENT_SHADER);\n        this.intensity = intensity;\n        this.colorMatrix = colorMatrix;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        colorMatrixLocation = GLES20.glGetUniformLocation(getProgram(), \"colorMatrix\");\n        intensityLocation = GLES20.glGetUniformLocation(getProgram(), \"intensity\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setIntensity(intensity);\n        setColorMatrix(colorMatrix);\n    }\n\n    public void setIntensity(final float intensity) {\n        this.intensity = intensity;\n        setFloat(intensityLocation, intensity);\n    }\n\n    public void setColorMatrix(final float[] colorMatrix) {\n        this.colorMatrix = colorMatrix;\n        setUniformMatrix4f(colorMatrixLocation, colorMatrix);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageContrastFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\n/**\n * Changes the contrast of the image.<br>\n * <br>\n * contrast value ranges from 0.0 to 4.0, with 1.0 as the normal level\n */\npublic class GPUImageContrastFilter extends GPUImageFilter {\n    public static final String CONTRAST_FRAGMENT_SHADER = \"\" +\n            \"varying highp vec2 textureCoordinate;\\n\" +\n            \" \\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform lowp float contrast;\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"     lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"     \\n\" +\n            \"     gl_FragColor = vec4(((textureColor.rgb - vec3(0.5)) * contrast + vec3(0.5)), textureColor.w);\\n\" +\n            \" }\";\n\n    private int contrastLocation;\n    private float contrast;\n\n    public GPUImageContrastFilter() {\n        this(1.2f);\n    }\n\n    public GPUImageContrastFilter(float contrast) {\n        super(NO_FILTER_VERTEX_SHADER, CONTRAST_FRAGMENT_SHADER);\n        this.contrast = contrast;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        contrastLocation = GLES20.glGetUniformLocation(getProgram(), \"contrast\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setContrast(contrast);\n    }\n\n    public void setContrast(final float contrast) {\n        this.contrast = contrast;\n        setFloat(contrastLocation, this.contrast);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageCrosshatchFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\n/**\n * crossHatchSpacing: The fractional width of the image to use as the spacing for the crosshatch. The default is 0.03.\n * lineWidth: A relative width for the crosshatch lines. The default is 0.003.\n */\npublic class GPUImageCrosshatchFilter extends GPUImageFilter {\n    public static final String CROSSHATCH_FRAGMENT_SHADER = \"\" +\n            \"varying highp vec2 textureCoordinate;\\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"uniform highp float crossHatchSpacing;\\n\" +\n            \"uniform highp float lineWidth;\\n\" +\n            \"const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);\\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"highp float luminance = dot(texture2D(inputImageTexture, textureCoordinate).rgb, W);\\n\" +\n            \"lowp vec4 colorToDisplay = vec4(1.0, 1.0, 1.0, 1.0);\\n\" +\n            \"if (luminance < 1.00)\\n\" +\n            \"{\\n\" +\n            \"if (mod(textureCoordinate.x + textureCoordinate.y, crossHatchSpacing) <= lineWidth)\\n\" +\n            \"{\\n\" +\n            \"colorToDisplay = vec4(0.0, 0.0, 0.0, 1.0);\\n\" +\n            \"}\\n\" +\n            \"}\\n\" +\n            \"if (luminance < 0.75)\\n\" +\n            \"{\\n\" +\n            \"if (mod(textureCoordinate.x - textureCoordinate.y, crossHatchSpacing) <= lineWidth)\\n\" +\n            \"{\\n\" +\n            \"colorToDisplay = vec4(0.0, 0.0, 0.0, 1.0);\\n\" +\n            \"}\\n\" +\n            \"}\\n\" +\n            \"if (luminance < 0.50)\\n\" +\n            \"{\\n\" +\n            \"if (mod(textureCoordinate.x + textureCoordinate.y - (crossHatchSpacing / 2.0), crossHatchSpacing) <= lineWidth)\\n\" +\n            \"{\\n\" +\n            \"colorToDisplay = vec4(0.0, 0.0, 0.0, 1.0);\\n\" +\n            \"}\\n\" +\n            \"}\\n\" +\n            \"if (luminance < 0.3)\\n\" +\n            \"{\\n\" +\n            \"if (mod(textureCoordinate.x - textureCoordinate.y - (crossHatchSpacing / 2.0), crossHatchSpacing) <= lineWidth)\\n\" +\n            \"{\\n\" +\n            \"colorToDisplay = vec4(0.0, 0.0, 0.0, 1.0);\\n\" +\n            \"}\\n\" +\n            \"}\\n\" +\n            \"gl_FragColor = colorToDisplay;\\n\" +\n            \"}\\n\";\n\n    private float crossHatchSpacing;\n    private int crossHatchSpacingLocation;\n    private float lineWidth;\n    private int lineWidthLocation;\n\n    /**\n     * Using default values of crossHatchSpacing: 0.03f and lineWidth: 0.003f.\n     */\n    public GPUImageCrosshatchFilter() {\n        this(0.03f, 0.003f);\n    }\n\n    public GPUImageCrosshatchFilter(float crossHatchSpacing, float lineWidth) {\n        super(NO_FILTER_VERTEX_SHADER, CROSSHATCH_FRAGMENT_SHADER);\n        this.crossHatchSpacing = crossHatchSpacing;\n        this.lineWidth = lineWidth;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        crossHatchSpacingLocation = GLES20.glGetUniformLocation(getProgram(), \"crossHatchSpacing\");\n        lineWidthLocation = GLES20.glGetUniformLocation(getProgram(), \"lineWidth\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setCrossHatchSpacing(crossHatchSpacing);\n        setLineWidth(lineWidth);\n    }\n\n    /**\n     * The fractional width of the image to use as the spacing for the crosshatch. The default is 0.03.\n     *\n     * @param crossHatchSpacing default 0.03\n     */\n    public void setCrossHatchSpacing(final float crossHatchSpacing) {\n        float singlePixelSpacing;\n        if (getOutputWidth() != 0) {\n            singlePixelSpacing = 1.0f / (float) getOutputWidth();\n        } else {\n            singlePixelSpacing = 1.0f / 2048.0f;\n        }\n\n        if (crossHatchSpacing < singlePixelSpacing) {\n            this.crossHatchSpacing = singlePixelSpacing;\n        } else {\n            this.crossHatchSpacing = crossHatchSpacing;\n        }\n\n        setFloat(crossHatchSpacingLocation, this.crossHatchSpacing);\n    }\n\n    /**\n     * A relative width for the crosshatch lines. The default is 0.003.\n     *\n     * @param lineWidth default 0.003\n     */\n    public void setLineWidth(final float lineWidth) {\n        this.lineWidth = lineWidth;\n        setFloat(lineWidthLocation, this.lineWidth);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageDarkenBlendFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\npublic class GPUImageDarkenBlendFilter extends GPUImageTwoInputFilter {\n    public static final String DARKEN_BLEND_FRAGMENT_SHADER = \"varying highp vec2 textureCoordinate;\\n\" +\n            \" varying highp vec2 textureCoordinate2;\\n\" +\n            \"\\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform sampler2D inputImageTexture2;\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"    lowp vec4 base = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"    lowp vec4 overlayer = texture2D(inputImageTexture2, textureCoordinate2);\\n\" +\n            \"    \\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\" +\n            \" }\";\n\n    public GPUImageDarkenBlendFilter() {\n        super(DARKEN_BLEND_FRAGMENT_SHADER);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageDifferenceBlendFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\npublic class GPUImageDifferenceBlendFilter extends GPUImageTwoInputFilter {\n    public static final String DIFFERENCE_BLEND_FRAGMENT_SHADER = \"varying highp vec2 textureCoordinate;\\n\" +\n            \" varying highp vec2 textureCoordinate2;\\n\" +\n            \"\\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform sampler2D inputImageTexture2;\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"     mediump vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"     mediump vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);\\n\" +\n            \"     gl_FragColor = vec4(abs(textureColor2.rgb - textureColor.rgb), textureColor.a);\\n\" +\n            \" }\";\n\n    public GPUImageDifferenceBlendFilter() {\n        super(DIFFERENCE_BLEND_FRAGMENT_SHADER);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageDilationFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\n/**\n * For each pixel, this sets it to the maximum value of the red channel in a rectangular neighborhood extending\n * out dilationRadius pixels from the center.\n * This extends out bright features, and is most commonly used with black-and-white thresholded images.\n */\npublic class GPUImageDilationFilter extends GPUImageTwoPassTextureSamplingFilter {\n    public static final String VERTEX_SHADER_1 =\n            \"attribute vec4 position;\\n\" +\n                    \"attribute vec2 inputTextureCoordinate;\\n\" +\n                    \"\\n\" +\n                    \"uniform float texelWidthOffset; \\n\" +\n                    \"uniform float texelHeightOffset; \\n\" +\n                    \"\\n\" +\n                    \"varying vec2 centerTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepNegativeTextureCoordinate;\\n\" +\n                    \"\\n\" +\n                    \"void main()\\n\" +\n                    \"{\\n\" +\n                    \"gl_Position = position;\\n\" +\n                    \"\\n\" +\n                    \"vec2 offset = vec2(texelWidthOffset, texelHeightOffset);\\n\" +\n                    \"\\n\" +\n                    \"centerTextureCoordinate = inputTextureCoordinate;\\n\" +\n                    \"oneStepNegativeTextureCoordinate = inputTextureCoordinate - offset;\\n\" +\n                    \"oneStepPositiveTextureCoordinate = inputTextureCoordinate + offset;\\n\" +\n                    \"}\\n\";\n\n    public static final String VERTEX_SHADER_2 =\n            \"attribute vec4 position;\\n\" +\n                    \"attribute vec2 inputTextureCoordinate;\\n\" +\n                    \"\\n\" +\n                    \"uniform float texelWidthOffset;\\n\" +\n                    \"uniform float texelHeightOffset;\\n\" +\n                    \"\\n\" +\n                    \"varying vec2 centerTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepNegativeTextureCoordinate;\\n\" +\n                    \"varying vec2 twoStepsPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 twoStepsNegativeTextureCoordinate;\\n\" +\n                    \"\\n\" +\n                    \"void main()\\n\" +\n                    \"{\\n\" +\n                    \"gl_Position = position;\\n\" +\n                    \"\\n\" +\n                    \"vec2 offset = vec2(texelWidthOffset, texelHeightOffset);\\n\" +\n                    \"\\n\" +\n                    \"centerTextureCoordinate = inputTextureCoordinate;\\n\" +\n                    \"oneStepNegativeTextureCoordinate = inputTextureCoordinate - offset;\\n\" +\n                    \"oneStepPositiveTextureCoordinate = inputTextureCoordinate + offset;\\n\" +\n                    \"twoStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 2.0);\\n\" +\n                    \"twoStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 2.0);\\n\" +\n                    \"}\\n\";\n\n    public static final String VERTEX_SHADER_3 =\n            \"attribute vec4 position;\\n\" +\n                    \"attribute vec2 inputTextureCoordinate;\\n\" +\n                    \"\\n\" +\n                    \"uniform float texelWidthOffset;\\n\" +\n                    \"uniform float texelHeightOffset;\\n\" +\n                    \"\\n\" +\n                    \"varying vec2 centerTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepNegativeTextureCoordinate;\\n\" +\n                    \"varying vec2 twoStepsPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 twoStepsNegativeTextureCoordinate;\\n\" +\n                    \"varying vec2 threeStepsPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 threeStepsNegativeTextureCoordinate;\\n\" +\n                    \"\\n\" +\n                    \"void main()\\n\" +\n                    \"{\\n\" +\n                    \"gl_Position = position;\\n\" +\n                    \"\\n\" +\n                    \"vec2 offset = vec2(texelWidthOffset, texelHeightOffset);\\n\" +\n                    \"\\n\" +\n                    \"centerTextureCoordinate = inputTextureCoordinate;\\n\" +\n                    \"oneStepNegativeTextureCoordinate = inputTextureCoordinate - offset;\\n\" +\n                    \"oneStepPositiveTextureCoordinate = inputTextureCoordinate + offset;\\n\" +\n                    \"twoStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 2.0);\\n\" +\n                    \"twoStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 2.0);\\n\" +\n                    \"threeStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 3.0);\\n\" +\n                    \"threeStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 3.0);\\n\" +\n                    \"}\\n\";\n\n    public static final String VERTEX_SHADER_4 =\n\n            \"attribute vec4 position;\\n\" +\n                    \"attribute vec2 inputTextureCoordinate;\\n\" +\n                    \"\\n\" +\n                    \"uniform float texelWidthOffset;\\n\" +\n                    \"uniform float texelHeightOffset;\\n\" +\n                    \"\\n\" +\n                    \"varying vec2 centerTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepNegativeTextureCoordinate;\\n\" +\n                    \"varying vec2 twoStepsPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 twoStepsNegativeTextureCoordinate;\\n\" +\n                    \"varying vec2 threeStepsPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 threeStepsNegativeTextureCoordinate;\\n\" +\n                    \"varying vec2 fourStepsPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 fourStepsNegativeTextureCoordinate;\\n\" +\n                    \"\\n\" +\n                    \"void main()\\n\" +\n                    \"{\\n\" +\n                    \"gl_Position = position;\\n\" +\n                    \"\\n\" +\n                    \"vec2 offset = vec2(texelWidthOffset, texelHeightOffset);\\n\" +\n                    \"\\n\" +\n                    \"centerTextureCoordinate = inputTextureCoordinate;\\n\" +\n                    \"oneStepNegativeTextureCoordinate = inputTextureCoordinate - offset;\\n\" +\n                    \"oneStepPositiveTextureCoordinate = inputTextureCoordinate + offset;\\n\" +\n                    \"twoStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 2.0);\\n\" +\n                    \"twoStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 2.0);\\n\" +\n                    \"threeStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 3.0);\\n\" +\n                    \"threeStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 3.0);\\n\" +\n                    \"fourStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 4.0);\\n\" +\n                    \"fourStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 4.0);\\n\" +\n                    \"}\\n\";\n\n\n    public static final String FRAGMENT_SHADER_1 =\n            \"precision lowp float;\\n\" +\n                    \"\\n\" +\n                    \"varying vec2 centerTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepNegativeTextureCoordinate;\\n\" +\n                    \"\\n\" +\n                    \"uniform sampler2D inputImageTexture;\\n\" +\n                    \"\\n\" +\n                    \"void main()\\n\" +\n                    \"{\\n\" +\n                    \"float centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate).r;\\n\" +\n                    \"float oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate).r;\\n\" +\n                    \"float oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate).r;\\n\" +\n                    \"\\n\" +\n                    \"lowp float maxValue = max(centerIntensity, oneStepPositiveIntensity);\\n\" +\n                    \"maxValue = max(maxValue, oneStepNegativeIntensity);\\n\" +\n                    \"\\n\" +\n                    \"gl_FragColor = vec4(vec3(maxValue), 1.0);\\n\" +\n                    \"}\\n\";\n\n    public static final String FRAGMENT_SHADER_2 =\n            \"precision lowp float;\\n\" +\n                    \"\\n\" +\n                    \"varying vec2 centerTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepNegativeTextureCoordinate;\\n\" +\n                    \"varying vec2 twoStepsPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 twoStepsNegativeTextureCoordinate;\\n\" +\n                    \"\\n\" +\n                    \"uniform sampler2D inputImageTexture;\\n\" +\n                    \"\\n\" +\n                    \"void main()\\n\" +\n                    \"{\\n\" +\n                    \"float centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate).r;\\n\" +\n                    \"float oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate).r;\\n\" +\n                    \"float oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate).r;\\n\" +\n                    \"float twoStepsPositiveIntensity = texture2D(inputImageTexture, twoStepsPositiveTextureCoordinate).r;\\n\" +\n                    \"float twoStepsNegativeIntensity = texture2D(inputImageTexture, twoStepsNegativeTextureCoordinate).r;\\n\" +\n                    \"\\n\" +\n                    \"lowp float maxValue = max(centerIntensity, oneStepPositiveIntensity);\\n\" +\n                    \"maxValue = max(maxValue, oneStepNegativeIntensity);\\n\" +\n                    \"maxValue = max(maxValue, twoStepsPositiveIntensity);\\n\" +\n                    \"maxValue = max(maxValue, twoStepsNegativeIntensity);\\n\" +\n                    \"\\n\" +\n                    \"gl_FragColor = vec4(vec3(maxValue), 1.0);\\n\" +\n                    \"}\\n\";\n\n    public static final String FRAGMENT_SHADER_3 =\n            \"precision lowp float;\\n\" +\n                    \"\\n\" +\n                    \"varying vec2 centerTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepNegativeTextureCoordinate;\\n\" +\n                    \"varying vec2 twoStepsPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 twoStepsNegativeTextureCoordinate;\\n\" +\n                    \"varying vec2 threeStepsPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 threeStepsNegativeTextureCoordinate;\\n\" +\n                    \"\\n\" +\n                    \"uniform sampler2D inputImageTexture;\\n\" +\n                    \"\\n\" +\n                    \"void main()\\n\" +\n                    \"{\\n\" +\n                    \"float centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate).r;\\n\" +\n                    \"float oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate).r;\\n\" +\n                    \"float oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate).r;\\n\" +\n                    \"float twoStepsPositiveIntensity = texture2D(inputImageTexture, twoStepsPositiveTextureCoordinate).r;\\n\" +\n                    \"float twoStepsNegativeIntensity = texture2D(inputImageTexture, twoStepsNegativeTextureCoordinate).r;\\n\" +\n                    \"float threeStepsPositiveIntensity = texture2D(inputImageTexture, threeStepsPositiveTextureCoordinate).r;\\n\" +\n                    \"float threeStepsNegativeIntensity = texture2D(inputImageTexture, threeStepsNegativeTextureCoordinate).r;\\n\" +\n                    \"\\n\" +\n                    \"lowp float maxValue = max(centerIntensity, oneStepPositiveIntensity);\\n\" +\n                    \"maxValue = max(maxValue, oneStepNegativeIntensity);\\n\" +\n                    \"maxValue = max(maxValue, twoStepsPositiveIntensity);\\n\" +\n                    \"maxValue = max(maxValue, twoStepsNegativeIntensity);\\n\" +\n                    \"maxValue = max(maxValue, threeStepsPositiveIntensity);\\n\" +\n                    \"maxValue = max(maxValue, threeStepsNegativeIntensity);\\n\" +\n                    \"\\n\" +\n                    \"gl_FragColor = vec4(vec3(maxValue), 1.0);\\n\" +\n                    \"}\\n\";\n\n    public static final String FRAGMENT_SHADER_4 =\n            \"precision lowp float;\\n\" +\n                    \"\\n\" +\n                    \"varying vec2 centerTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepNegativeTextureCoordinate;\\n\" +\n                    \"varying vec2 twoStepsPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 twoStepsNegativeTextureCoordinate;\\n\" +\n                    \"varying vec2 threeStepsPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 threeStepsNegativeTextureCoordinate;\\n\" +\n                    \"varying vec2 fourStepsPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 fourStepsNegativeTextureCoordinate;\\n\" +\n                    \"\\n\" +\n                    \"uniform sampler2D inputImageTexture;\\n\" +\n                    \"\\n\" +\n                    \"void main()\\n\" +\n                    \"{\\n\" +\n                    \"float centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate).r;\\n\" +\n                    \"float oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate).r;\\n\" +\n                    \"float oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate).r;\\n\" +\n                    \"float twoStepsPositiveIntensity = texture2D(inputImageTexture, twoStepsPositiveTextureCoordinate).r;\\n\" +\n                    \"float twoStepsNegativeIntensity = texture2D(inputImageTexture, twoStepsNegativeTextureCoordinate).r;\\n\" +\n                    \"float threeStepsPositiveIntensity = texture2D(inputImageTexture, threeStepsPositiveTextureCoordinate).r;\\n\" +\n                    \"float threeStepsNegativeIntensity = texture2D(inputImageTexture, threeStepsNegativeTextureCoordinate).r;\\n\" +\n                    \"float fourStepsPositiveIntensity = texture2D(inputImageTexture, fourStepsPositiveTextureCoordinate).r;\\n\" +\n                    \"float fourStepsNegativeIntensity = texture2D(inputImageTexture, fourStepsNegativeTextureCoordinate).r;\\n\" +\n                    \"\\n\" +\n                    \"lowp float maxValue = max(centerIntensity, oneStepPositiveIntensity);\\n\" +\n                    \"maxValue = max(maxValue, oneStepNegativeIntensity);\\n\" +\n                    \"maxValue = max(maxValue, twoStepsPositiveIntensity);\\n\" +\n                    \"maxValue = max(maxValue, twoStepsNegativeIntensity);\\n\" +\n                    \"maxValue = max(maxValue, threeStepsPositiveIntensity);\\n\" +\n                    \"maxValue = max(maxValue, threeStepsNegativeIntensity);\\n\" +\n                    \"maxValue = max(maxValue, fourStepsPositiveIntensity);\\n\" +\n                    \"maxValue = max(maxValue, fourStepsNegativeIntensity);\\n\" +\n                    \"\\n\" +\n                    \"gl_FragColor = vec4(vec3(maxValue), 1.0);\\n\" +\n                    \"}\\n\";\n\n\n    public GPUImageDilationFilter() {\n        this(1);\n    }\n\n    /**\n     * Acceptable values for dilationRadius, which sets the distance in pixels to sample out from the center,\n     * are 1, 2, 3, and 4.\n     *\n     * @param radius 1, 2, 3 or 4\n     */\n    public GPUImageDilationFilter(int radius) {\n        this(getVertexShader(radius), getFragmentShader(radius));\n    }\n\n    private GPUImageDilationFilter(String vertexShader, String fragmentShader) {\n        super(vertexShader, fragmentShader, vertexShader, fragmentShader);\n    }\n\n    private static String getVertexShader(int radius) {\n        switch (radius) {\n            case 0:\n            case 1:\n                return VERTEX_SHADER_1;\n            case 2:\n                return VERTEX_SHADER_2;\n            case 3:\n                return VERTEX_SHADER_3;\n            default:\n                return VERTEX_SHADER_4;\n        }\n    }\n\n    private static String getFragmentShader(int radius) {\n        switch (radius) {\n            case 0:\n            case 1:\n                return FRAGMENT_SHADER_1;\n            case 2:\n                return FRAGMENT_SHADER_2;\n            case 3:\n                return FRAGMENT_SHADER_3;\n            default:\n                return FRAGMENT_SHADER_4;\n        }\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageDirectionalSobelEdgeDetectionFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\n\npublic class GPUImageDirectionalSobelEdgeDetectionFilter extends GPUImage3x3TextureSamplingFilter {\n    public static final String DIRECTIONAL_SOBEL_EDGE_DETECTION_FRAGMENT_SHADER = \"\" +\n            \"precision mediump float;\\n\" +\n            \"\\n\" +\n            \"varying vec2 textureCoordinate;\\n\" +\n            \"varying vec2 leftTextureCoordinate;\\n\" +\n            \"varying vec2 rightTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"varying vec2 topTextureCoordinate;\\n\" +\n            \"varying vec2 topLeftTextureCoordinate;\\n\" +\n            \"varying vec2 topRightTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"varying vec2 bottomTextureCoordinate;\\n\" +\n            \"varying vec2 bottomLeftTextureCoordinate;\\n\" +\n            \"varying vec2 bottomRightTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"\\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"    float bottomLeftIntensity = texture2D(inputImageTexture, bottomLeftTextureCoordinate).r;\\n\" +\n            \"    float topRightIntensity = texture2D(inputImageTexture, topRightTextureCoordinate).r;\\n\" +\n            \"    float topLeftIntensity = texture2D(inputImageTexture, topLeftTextureCoordinate).r;\\n\" +\n            \"    float bottomRightIntensity = texture2D(inputImageTexture, bottomRightTextureCoordinate).r;\\n\" +\n            \"    float leftIntensity = texture2D(inputImageTexture, leftTextureCoordinate).r;\\n\" +\n            \"    float rightIntensity = texture2D(inputImageTexture, rightTextureCoordinate).r;\\n\" +\n            \"    float bottomIntensity = texture2D(inputImageTexture, bottomTextureCoordinate).r;\\n\" +\n            \"    float topIntensity = texture2D(inputImageTexture, topTextureCoordinate).r;\\n\" +\n            \"\\n\" +\n            \"    vec2 gradientDirection;\\n\" +\n            \"    gradientDirection.x = -bottomLeftIntensity - 2.0 * leftIntensity - topLeftIntensity + bottomRightIntensity + 2.0 * rightIntensity + topRightIntensity;\\n\" +\n            \"    gradientDirection.y = -topLeftIntensity - 2.0 * topIntensity - topRightIntensity + bottomLeftIntensity + 2.0 * bottomIntensity + bottomRightIntensity;\\n\" +\n            \"\\n\" +\n            \"    float gradientMagnitude = length(gradientDirection);\\n\" +\n            \"    vec2 normalizedDirection = normalize(gradientDirection);\\n\" +\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\" +\n            \"    normalizedDirection = (normalizedDirection + 1.0) * 0.5; // Place -1.0 - 1.0 within 0 - 1.0\\n\" +\n            \"\\n\" +\n            \"    gl_FragColor = vec4(gradientMagnitude, normalizedDirection.x, normalizedDirection.y, 1.0);\\n\" +\n            \"}\";\n\n    public GPUImageDirectionalSobelEdgeDetectionFilter() {\n        super(DIRECTIONAL_SOBEL_EDGE_DETECTION_FRAGMENT_SHADER);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageDissolveBlendFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\n/**\n * Mix ranges from 0.0 (only image 1) to 1.0 (only image 2), with 0.5 (half of either) as the normal level\n */\npublic class GPUImageDissolveBlendFilter extends GPUImageMixBlendFilter {\n    public static final String DISSOLVE_BLEND_FRAGMENT_SHADER = \"varying highp vec2 textureCoordinate;\\n\" +\n            \" varying highp vec2 textureCoordinate2;\\n\" +\n            \"\\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform sampler2D inputImageTexture2;\\n\" +\n            \" uniform lowp float mixturePercent;\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"    lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"    lowp vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);\\n\" +\n            \"    \\n\" +\n            \"    gl_FragColor = mix(textureColor, textureColor2, mixturePercent);\\n\" +\n            \" }\";\n\n    public GPUImageDissolveBlendFilter() {\n        super(DISSOLVE_BLEND_FRAGMENT_SHADER);\n    }\n\n    public GPUImageDissolveBlendFilter(float mix) {\n        super(DISSOLVE_BLEND_FRAGMENT_SHADER, mix);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageDivideBlendFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\npublic class GPUImageDivideBlendFilter extends GPUImageTwoInputFilter {\n    public static final String DIVIDE_BLEND_FRAGMENT_SHADER = \"varying highp vec2 textureCoordinate;\\n\" +\n            \" varying highp vec2 textureCoordinate2;\\n\" +\n            \"\\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform sampler2D inputImageTexture2;\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"   mediump vec4 base = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"   mediump vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);\\n\" +\n            \"   \\n\" +\n            \"   mediump float ra;\\n\" +\n            \"   if (overlay.a == 0.0 || ((base.r / overlay.r) > (base.a / overlay.a)))\\n\" +\n            \"     ra = overlay.a * base.a + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);\\n\" +\n            \"   else\\n\" +\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\" +\n            \"\\n\" +\n            \"   mediump float ga;\\n\" +\n            \"   if (overlay.a == 0.0 || ((base.g / overlay.g) > (base.a / overlay.a)))\\n\" +\n            \"     ga = overlay.a * base.a + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);\\n\" +\n            \"   else\\n\" +\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\" +\n            \"   \\n\" +\n            \"   mediump float ba;\\n\" +\n            \"   if (overlay.a == 0.0 || ((base.b / overlay.b) > (base.a / overlay.a)))\\n\" +\n            \"     ba = overlay.a * base.a + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);\\n\" +\n            \"   else\\n\" +\n            \"     ba = (base.b * overlay.a * overlay.a) / overlay.b + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);\\n\" +\n            \"\\n\" +\n            \"   mediump float a = overlay.a + base.a - overlay.a * base.a;\\n\" +\n            \"   \\n\" +\n            \"   gl_FragColor = vec4(ra, ga, ba, a);\\n\" +\n            \" }\";\n\n    public GPUImageDivideBlendFilter() {\n        super(DIVIDE_BLEND_FRAGMENT_SHADER);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageEmbossFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\n/**\n * Applies an emboss effect to the image.<br>\n * <br>\n * Intensity ranges from 0.0 to 4.0, with 1.0 as the normal level\n */\npublic class GPUImageEmbossFilter extends GPUImage3x3ConvolutionFilter {\n    private float intensity;\n\n    public GPUImageEmbossFilter() {\n        this(1.0f);\n    }\n\n    public GPUImageEmbossFilter(final float intensity) {\n        super();\n        this.intensity = intensity;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setIntensity(intensity);\n    }\n\n    public void setIntensity(final float intensity) {\n        this.intensity = intensity;\n        setConvolutionKernel(new float[]{\n                intensity * (-2.0f), -intensity, 0.0f,\n                -intensity, 1.0f, intensity,\n                0.0f, intensity, intensity * 2.0f,\n        });\n    }\n\n    public float getIntensity() {\n        return intensity;\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageExclusionBlendFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\npublic class GPUImageExclusionBlendFilter extends GPUImageTwoInputFilter {\n    public static final String EXCLUSION_BLEND_FRAGMENT_SHADER = \"varying highp vec2 textureCoordinate;\\n\" +\n            \" varying highp vec2 textureCoordinate2;\\n\" +\n            \"\\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform sampler2D inputImageTexture2;\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"     mediump vec4 base = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"     mediump vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);\\n\" +\n            \"     \\n\" +\n            \"     //     Dca = (Sca.Da + Dca.Sa - 2.Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa)\\n\" +\n            \"     \\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\" +\n            \" }\";\n\n    public GPUImageExclusionBlendFilter() {\n        super(EXCLUSION_BLEND_FRAGMENT_SHADER);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageExposureFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\n/**\n * exposure: The adjusted exposure (-10.0 - 10.0, with 0.0 as the default)\n */\npublic class GPUImageExposureFilter extends GPUImageFilter {\n    public static final String EXPOSURE_FRAGMENT_SHADER = \"\" +\n            \" varying highp vec2 textureCoordinate;\\n\" +\n            \" \\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform highp float exposure;\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"     highp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"     \\n\" +\n            \"     gl_FragColor = vec4(textureColor.rgb * pow(2.0, exposure), textureColor.w);\\n\" +\n            \" } \";\n\n    private int exposureLocation;\n    private float exposure;\n\n    public GPUImageExposureFilter() {\n        this(1.0f);\n    }\n\n    public GPUImageExposureFilter(final float exposure) {\n        super(NO_FILTER_VERTEX_SHADER, EXPOSURE_FRAGMENT_SHADER);\n        this.exposure = exposure;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        exposureLocation = GLES20.glGetUniformLocation(getProgram(), \"exposure\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setExposure(exposure);\n    }\n\n    public void setExposure(final float exposure) {\n        this.exposure = exposure;\n        setFloat(exposureLocation, this.exposure);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageFalseColorFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\npublic class GPUImageFalseColorFilter extends GPUImageFilter {\n    public static final String FALSECOLOR_FRAGMENT_SHADER = \"\" +\n            \"precision lowp float;\\n\" +\n            \"\\n\" +\n            \"varying highp vec2 textureCoordinate;\\n\" +\n            \"\\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"uniform float intensity;\\n\" +\n            \"uniform vec3 firstColor;\\n\" +\n            \"uniform vec3 secondColor;\\n\" +\n            \"\\n\" +\n            \"const mediump vec3 luminanceWeighting = vec3(0.2125, 0.7154, 0.0721);\\n\" +\n            \"\\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"float luminance = dot(textureColor.rgb, luminanceWeighting);\\n\" +\n            \"\\n\" +\n            \"gl_FragColor = vec4( mix(firstColor.rgb, secondColor.rgb, luminance), textureColor.a);\\n\" +\n            \"}\\n\";\n\n    private float[] firstColor;\n    private int firstColorLocation;\n    private float[] secondColor;\n    private int secondColorLocation;\n\n    public GPUImageFalseColorFilter() {\n        this(0f, 0f, 0.5f, 1f, 0f, 0f);\n    }\n\n    public GPUImageFalseColorFilter(float firstRed, float firstGreen, float firstBlue, float secondRed, float secondGreen, float secondBlue) {\n        this(new float[]{firstRed, firstGreen, firstBlue}, new float[]{secondRed, secondGreen, secondBlue});\n    }\n\n    public GPUImageFalseColorFilter(float[] firstColor, float[] secondColor) {\n        super(NO_FILTER_VERTEX_SHADER, FALSECOLOR_FRAGMENT_SHADER);\n        this.firstColor = firstColor;\n        this.secondColor = secondColor;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        firstColorLocation = GLES20.glGetUniformLocation(getProgram(), \"firstColor\");\n        secondColorLocation = GLES20.glGetUniformLocation(getProgram(), \"secondColor\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setFirstColor(firstColor);\n        setSecondColor(secondColor);\n    }\n\n    public void setFirstColor(final float[] firstColor) {\n        this.firstColor = firstColor;\n        setFloatVec3(firstColorLocation, firstColor);\n    }\n\n    public void setSecondColor(final float[] secondColor) {\n        this.secondColor = secondColor;\n        setFloatVec3(secondColorLocation, secondColor);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.content.Context;\nimport android.content.res.AssetManager;\nimport android.graphics.PointF;\nimport android.opengl.GLES20;\n\nimport java.io.InputStream;\nimport java.nio.FloatBuffer;\nimport java.util.LinkedList;\n\nimport jp.co.cyberagent.android.gpuimage.util.OpenGlUtils;\n\npublic class GPUImageFilter {\n    public static final String NO_FILTER_VERTEX_SHADER = \"\" +\n            \"attribute vec4 position;\\n\" +\n            \"attribute vec4 inputTextureCoordinate;\\n\" +\n            \" \\n\" +\n            \"varying vec2 textureCoordinate;\\n\" +\n            \" \\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"    gl_Position = position;\\n\" +\n            \"    textureCoordinate = inputTextureCoordinate.xy;\\n\" +\n            \"}\";\n    public static final String NO_FILTER_FRAGMENT_SHADER = \"\" +\n            \"varying highp vec2 textureCoordinate;\\n\" +\n            \" \\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \" \\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"     gl_FragColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"}\";\n\n    private final LinkedList<Runnable> runOnDraw;\n    private final String vertexShader;\n    private final String fragmentShader;\n    private int glProgId;\n    private int glAttribPosition;\n    private int glUniformTexture;\n    private int glAttribTextureCoordinate;\n    private int outputWidth;\n    private int outputHeight;\n    private boolean isInitialized;\n\n    public GPUImageFilter() {\n        this(NO_FILTER_VERTEX_SHADER, NO_FILTER_FRAGMENT_SHADER);\n    }\n\n    public GPUImageFilter(final String vertexShader, final String fragmentShader) {\n        runOnDraw = new LinkedList<>();\n        this.vertexShader = vertexShader;\n        this.fragmentShader = fragmentShader;\n    }\n\n    private final void init() {\n        onInit();\n        onInitialized();\n    }\n\n    public void onInit() {\n        glProgId = OpenGlUtils.loadProgram(vertexShader, fragmentShader);\n        glAttribPosition = GLES20.glGetAttribLocation(glProgId, \"position\");\n        glUniformTexture = GLES20.glGetUniformLocation(glProgId, \"inputImageTexture\");\n        glAttribTextureCoordinate = GLES20.glGetAttribLocation(glProgId, \"inputTextureCoordinate\");\n        isInitialized = true;\n    }\n\n    public void onInitialized() {\n    }\n\n    public void ifNeedInit() {\n        if (!isInitialized) init();\n    }\n\n    public final void destroy() {\n        isInitialized = false;\n        GLES20.glDeleteProgram(glProgId);\n        onDestroy();\n    }\n\n    public void onDestroy() {\n    }\n\n    public void onOutputSizeChanged(final int width, final int height) {\n        outputWidth = width;\n        outputHeight = height;\n    }\n\n    public void onDraw(final int textureId, final FloatBuffer cubeBuffer,\n                       final FloatBuffer textureBuffer) {\n        GLES20.glUseProgram(glProgId);\n        runPendingOnDrawTasks();\n        if (!isInitialized) {\n            return;\n        }\n\n        cubeBuffer.position(0);\n        GLES20.glVertexAttribPointer(glAttribPosition, 2, GLES20.GL_FLOAT, false, 0, cubeBuffer);\n        GLES20.glEnableVertexAttribArray(glAttribPosition);\n        textureBuffer.position(0);\n        GLES20.glVertexAttribPointer(glAttribTextureCoordinate, 2, GLES20.GL_FLOAT, false, 0,\n                textureBuffer);\n        GLES20.glEnableVertexAttribArray(glAttribTextureCoordinate);\n        if (textureId != OpenGlUtils.NO_TEXTURE) {\n            GLES20.glActiveTexture(GLES20.GL_TEXTURE0);\n            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);\n            GLES20.glUniform1i(glUniformTexture, 0);\n        }\n        onDrawArraysPre();\n        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);\n        GLES20.glDisableVertexAttribArray(glAttribPosition);\n        GLES20.glDisableVertexAttribArray(glAttribTextureCoordinate);\n        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);\n    }\n\n    protected void onDrawArraysPre() {\n    }\n\n    protected void runPendingOnDrawTasks() {\n        synchronized (runOnDraw) {\n            while (!runOnDraw.isEmpty()) {\n                runOnDraw.removeFirst().run();\n            }\n        }\n    }\n\n    public boolean isInitialized() {\n        return isInitialized;\n    }\n\n    public int getOutputWidth() {\n        return outputWidth;\n    }\n\n    public int getOutputHeight() {\n        return outputHeight;\n    }\n\n    public int getProgram() {\n        return glProgId;\n    }\n\n    public int getAttribPosition() {\n        return glAttribPosition;\n    }\n\n    public int getAttribTextureCoordinate() {\n        return glAttribTextureCoordinate;\n    }\n\n    public int getUniformTexture() {\n        return glUniformTexture;\n    }\n\n    protected void setInteger(final int location, final int intValue) {\n        runOnDraw(new Runnable() {\n            @Override\n            public void run() {\n                ifNeedInit();\n                GLES20.glUniform1i(location, intValue);\n            }\n        });\n    }\n\n    protected void setFloat(final int location, final float floatValue) {\n        runOnDraw(new Runnable() {\n            @Override\n            public void run() {\n                ifNeedInit();\n                GLES20.glUniform1f(location, floatValue);\n            }\n        });\n    }\n\n    protected void setFloatVec2(final int location, final float[] arrayValue) {\n        runOnDraw(new Runnable() {\n            @Override\n            public void run() {\n                ifNeedInit();\n                GLES20.glUniform2fv(location, 1, FloatBuffer.wrap(arrayValue));\n            }\n        });\n    }\n\n    protected void setFloatVec3(final int location, final float[] arrayValue) {\n        runOnDraw(new Runnable() {\n            @Override\n            public void run() {\n                ifNeedInit();\n                GLES20.glUniform3fv(location, 1, FloatBuffer.wrap(arrayValue));\n            }\n        });\n    }\n\n    protected void setFloatVec4(final int location, final float[] arrayValue) {\n        runOnDraw(new Runnable() {\n            @Override\n            public void run() {\n                ifNeedInit();\n                GLES20.glUniform4fv(location, 1, FloatBuffer.wrap(arrayValue));\n            }\n        });\n    }\n\n    protected void setFloatArray(final int location, final float[] arrayValue) {\n        runOnDraw(new Runnable() {\n            @Override\n            public void run() {\n                ifNeedInit();\n                GLES20.glUniform1fv(location, arrayValue.length, FloatBuffer.wrap(arrayValue));\n            }\n        });\n    }\n\n    protected void setPoint(final int location, final PointF point) {\n        runOnDraw(new Runnable() {\n            @Override\n            public void run() {\n                ifNeedInit();\n                float[] vec2 = new float[2];\n                vec2[0] = point.x;\n                vec2[1] = point.y;\n                GLES20.glUniform2fv(location, 1, vec2, 0);\n            }\n        });\n    }\n\n    protected void setUniformMatrix3f(final int location, final float[] matrix) {\n        runOnDraw(new Runnable() {\n\n            @Override\n            public void run() {\n                ifNeedInit();\n                GLES20.glUniformMatrix3fv(location, 1, false, matrix, 0);\n            }\n        });\n    }\n\n    protected void setUniformMatrix4f(final int location, final float[] matrix) {\n        runOnDraw(new Runnable() {\n\n            @Override\n            public void run() {\n                ifNeedInit();\n                GLES20.glUniformMatrix4fv(location, 1, false, matrix, 0);\n            }\n        });\n    }\n\n    protected void runOnDraw(final Runnable runnable) {\n        synchronized (runOnDraw) {\n            runOnDraw.addLast(runnable);\n        }\n    }\n\n    public static String loadShader(String file, Context context) {\n        try {\n            AssetManager assetManager = context.getAssets();\n            InputStream ims = assetManager.open(file);\n\n            String re = convertStreamToString(ims);\n            ims.close();\n            return re;\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n        return \"\";\n    }\n\n    public static String convertStreamToString(java.io.InputStream is) {\n        java.util.Scanner s = new java.util.Scanner(is).useDelimiter(\"\\\\A\");\n        return s.hasNext() ? s.next() : \"\";\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageFilterGroup.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.annotation.SuppressLint;\nimport android.opengl.GLES20;\n\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.FloatBuffer;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport jp.co.cyberagent.android.gpuimage.util.Rotation;\nimport jp.co.cyberagent.android.gpuimage.util.TextureRotationUtil;\n\nimport static jp.co.cyberagent.android.gpuimage.GPUImageRenderer.CUBE;\nimport static jp.co.cyberagent.android.gpuimage.util.TextureRotationUtil.TEXTURE_NO_ROTATION;\n\n/**\n * Resembles a filter that consists of multiple filters applied after each\n * other.\n */\npublic class GPUImageFilterGroup extends GPUImageFilter {\n\n    private List<GPUImageFilter> filters;\n    private List<GPUImageFilter> mergedFilters;\n    private int[] frameBuffers;\n    private int[] frameBufferTextures;\n\n    private final FloatBuffer glCubeBuffer;\n    private final FloatBuffer glTextureBuffer;\n    private final FloatBuffer glTextureFlipBuffer;\n\n    /**\n     * Instantiates a new GPUImageFilterGroup with no filters.\n     */\n    public GPUImageFilterGroup() {\n        this(null);\n    }\n\n    /**\n     * Instantiates a new GPUImageFilterGroup with the given filters.\n     *\n     * @param filters the filters which represent this filter\n     */\n    public GPUImageFilterGroup(List<GPUImageFilter> filters) {\n        this.filters = filters;\n        if (this.filters == null) {\n            this.filters = new ArrayList<>();\n        } else {\n            updateMergedFilters();\n        }\n\n        glCubeBuffer = ByteBuffer.allocateDirect(CUBE.length * 4)\n                .order(ByteOrder.nativeOrder())\n                .asFloatBuffer();\n        glCubeBuffer.put(CUBE).position(0);\n\n        glTextureBuffer = ByteBuffer.allocateDirect(TEXTURE_NO_ROTATION.length * 4)\n                .order(ByteOrder.nativeOrder())\n                .asFloatBuffer();\n        glTextureBuffer.put(TEXTURE_NO_ROTATION).position(0);\n\n        float[] flipTexture = TextureRotationUtil.getRotation(Rotation.NORMAL, false, true);\n        glTextureFlipBuffer = ByteBuffer.allocateDirect(flipTexture.length * 4)\n                .order(ByteOrder.nativeOrder())\n                .asFloatBuffer();\n        glTextureFlipBuffer.put(flipTexture).position(0);\n    }\n\n    public void addFilter(GPUImageFilter aFilter) {\n        if (aFilter == null) {\n            return;\n        }\n        filters.add(aFilter);\n        updateMergedFilters();\n    }\n\n    /*\n     * (non-Javadoc)\n     * @see jp.co.cyberagent.android.gpuimage.filter.GPUImageFilter#onInit()\n     */\n    @Override\n    public void onInit() {\n        super.onInit();\n        for (GPUImageFilter filter : filters) {\n            filter.ifNeedInit();\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     * @see jp.co.cyberagent.android.gpuimage.filter.GPUImageFilter#onDestroy()\n     */\n    @Override\n    public void onDestroy() {\n        destroyFramebuffers();\n        for (GPUImageFilter filter : filters) {\n            filter.destroy();\n        }\n        super.onDestroy();\n    }\n\n    private void destroyFramebuffers() {\n        if (frameBufferTextures != null) {\n            GLES20.glDeleteTextures(frameBufferTextures.length, frameBufferTextures, 0);\n            frameBufferTextures = null;\n        }\n        if (frameBuffers != null) {\n            GLES20.glDeleteFramebuffers(frameBuffers.length, frameBuffers, 0);\n            frameBuffers = null;\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     * @see\n     * jp.co.cyberagent.android.gpuimage.filter.GPUImageFilter#onOutputSizeChanged(int,\n     * int)\n     */\n    @Override\n    public void onOutputSizeChanged(final int width, final int height) {\n        super.onOutputSizeChanged(width, height);\n        if (frameBuffers != null) {\n            destroyFramebuffers();\n        }\n\n        int size = filters.size();\n        for (int i = 0; i < size; i++) {\n            filters.get(i).onOutputSizeChanged(width, height);\n        }\n\n        if (mergedFilters != null && mergedFilters.size() > 0) {\n            size = mergedFilters.size();\n            frameBuffers = new int[size - 1];\n            frameBufferTextures = new int[size - 1];\n\n            for (int i = 0; i < size - 1; i++) {\n                GLES20.glGenFramebuffers(1, frameBuffers, i);\n                GLES20.glGenTextures(1, frameBufferTextures, i);\n                GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, frameBufferTextures[i]);\n                GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0,\n                        GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);\n                GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,\n                        GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);\n                GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,\n                        GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);\n                GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,\n                        GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);\n                GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,\n                        GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);\n\n                GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBuffers[i]);\n                GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,\n                        GLES20.GL_TEXTURE_2D, frameBufferTextures[i], 0);\n\n                GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);\n                GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);\n            }\n        }\n    }\n\n    /*\n     * (non-Javadoc)\n     * @see jp.co.cyberagent.android.gpuimage.filter.GPUImageFilter#onDraw(int,\n     * java.nio.FloatBuffer, java.nio.FloatBuffer)\n     */\n    @SuppressLint(\"WrongCall\")\n    @Override\n    public void onDraw(final int textureId, final FloatBuffer cubeBuffer,\n                       final FloatBuffer textureBuffer) {\n        runPendingOnDrawTasks();\n        if (!isInitialized() || frameBuffers == null || frameBufferTextures == null) {\n            return;\n        }\n        if (mergedFilters != null) {\n            int size = mergedFilters.size();\n            int previousTexture = textureId;\n            for (int i = 0; i < size; i++) {\n                GPUImageFilter filter = mergedFilters.get(i);\n                boolean isNotLast = i < size - 1;\n                if (isNotLast) {\n                    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBuffers[i]);\n                    GLES20.glClearColor(0, 0, 0, 0);\n                }\n\n                if (i == 0) {\n                    filter.onDraw(previousTexture, cubeBuffer, textureBuffer);\n                } else if (i == size - 1) {\n                    filter.onDraw(previousTexture, glCubeBuffer, (size % 2 == 0) ? glTextureFlipBuffer : glTextureBuffer);\n                } else {\n                    filter.onDraw(previousTexture, glCubeBuffer, glTextureBuffer);\n                }\n\n                if (isNotLast) {\n                    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);\n                    previousTexture = frameBufferTextures[i];\n                }\n            }\n        }\n    }\n\n    /**\n     * Gets the filters.\n     *\n     * @return the filters\n     */\n    public List<GPUImageFilter> getFilters() {\n        return filters;\n    }\n\n    public List<GPUImageFilter> getMergedFilters() {\n        return mergedFilters;\n    }\n\n    public void updateMergedFilters() {\n        if (filters == null) {\n            return;\n        }\n\n        if (mergedFilters == null) {\n            mergedFilters = new ArrayList<>();\n        } else {\n            mergedFilters.clear();\n        }\n\n        List<GPUImageFilter> filters;\n        for (GPUImageFilter filter : this.filters) {\n            if (filter instanceof GPUImageFilterGroup) {\n                ((GPUImageFilterGroup) filter).updateMergedFilters();\n                filters = ((GPUImageFilterGroup) filter).getMergedFilters();\n                if (filters == null || filters.isEmpty())\n                    continue;\n                mergedFilters.addAll(filters);\n                continue;\n            }\n            mergedFilters.add(filter);\n        }\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageGammaFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\n/**\n * gamma value ranges from 0.0 to 3.0, with 1.0 as the normal level\n */\npublic class GPUImageGammaFilter extends GPUImageFilter {\n    public static final String GAMMA_FRAGMENT_SHADER = \"\" +\n            \"varying highp vec2 textureCoordinate;\\n\" +\n            \" \\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform lowp float gamma;\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"     lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"     \\n\" +\n            \"     gl_FragColor = vec4(pow(textureColor.rgb, vec3(gamma)), textureColor.w);\\n\" +\n            \" }\";\n\n    private int gammaLocation;\n    private float gamma;\n\n    public GPUImageGammaFilter() {\n        this(1.2f);\n    }\n\n    public GPUImageGammaFilter(final float gamma) {\n        super(NO_FILTER_VERTEX_SHADER, GAMMA_FRAGMENT_SHADER);\n        this.gamma = gamma;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        gammaLocation = GLES20.glGetUniformLocation(getProgram(), \"gamma\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setGamma(gamma);\n    }\n\n    public void setGamma(final float gamma) {\n        this.gamma = gamma;\n        setFloat(gammaLocation, this.gamma);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageGaussianBlurFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\n/**\n * A more generalized 9x9 Gaussian blur filter\n * blurSize value ranging from 0.0 on up, with a default of 1.0\n */\npublic class GPUImageGaussianBlurFilter extends GPUImageTwoPassTextureSamplingFilter {\n    public static final String VERTEX_SHADER =\n            \"attribute vec4 position;\\n\" +\n                    \"attribute vec4 inputTextureCoordinate;\\n\" +\n                    \"\\n\" +\n                    \"const int GAUSSIAN_SAMPLES = 9;\\n\" +\n                    \"\\n\" +\n                    \"uniform float texelWidthOffset;\\n\" +\n                    \"uniform float texelHeightOffset;\\n\" +\n                    \"\\n\" +\n                    \"varying vec2 textureCoordinate;\\n\" +\n                    \"varying vec2 blurCoordinates[GAUSSIAN_SAMPLES];\\n\" +\n                    \"\\n\" +\n                    \"void main()\\n\" +\n                    \"{\\n\" +\n                    \"\tgl_Position = position;\\n\" +\n                    \"\ttextureCoordinate = inputTextureCoordinate.xy;\\n\" +\n                    \"\t\\n\" +\n                    \"\t// Calculate the positions for the blur\\n\" +\n                    \"\tint multiplier = 0;\\n\" +\n                    \"\tvec2 blurStep;\\n\" +\n                    \"   vec2 singleStepOffset = vec2(texelHeightOffset, texelWidthOffset);\\n\" +\n                    \"    \\n\" +\n                    \"\tfor (int i = 0; i < GAUSSIAN_SAMPLES; i++)\\n\" +\n                    \"   {\\n\" +\n                    \"\t\tmultiplier = (i - ((GAUSSIAN_SAMPLES - 1) / 2));\\n\" +\n                    \"       // Blur in x (horizontal)\\n\" +\n                    \"       blurStep = float(multiplier) * singleStepOffset;\\n\" +\n                    \"\t\tblurCoordinates[i] = inputTextureCoordinate.xy + blurStep;\\n\" +\n                    \"\t}\\n\" +\n                    \"}\\n\";\n\n    public static final String FRAGMENT_SHADER =\n            \"uniform sampler2D inputImageTexture;\\n\" +\n                    \"\\n\" +\n                    \"const lowp int GAUSSIAN_SAMPLES = 9;\\n\" +\n                    \"\\n\" +\n                    \"varying highp vec2 textureCoordinate;\\n\" +\n                    \"varying highp vec2 blurCoordinates[GAUSSIAN_SAMPLES];\\n\" +\n                    \"\\n\" +\n                    \"void main()\\n\" +\n                    \"{\\n\" +\n                    \"\tlowp vec3 sum = vec3(0.0);\\n\" +\n                    \"   lowp vec4 fragColor=texture2D(inputImageTexture,textureCoordinate);\\n\" +\n                    \"\t\\n\" +\n                    \"    sum += texture2D(inputImageTexture, blurCoordinates[0]).rgb * 0.05;\\n\" +\n                    \"    sum += texture2D(inputImageTexture, blurCoordinates[1]).rgb * 0.09;\\n\" +\n                    \"    sum += texture2D(inputImageTexture, blurCoordinates[2]).rgb * 0.12;\\n\" +\n                    \"    sum += texture2D(inputImageTexture, blurCoordinates[3]).rgb * 0.15;\\n\" +\n                    \"    sum += texture2D(inputImageTexture, blurCoordinates[4]).rgb * 0.18;\\n\" +\n                    \"    sum += texture2D(inputImageTexture, blurCoordinates[5]).rgb * 0.15;\\n\" +\n                    \"    sum += texture2D(inputImageTexture, blurCoordinates[6]).rgb * 0.12;\\n\" +\n                    \"    sum += texture2D(inputImageTexture, blurCoordinates[7]).rgb * 0.09;\\n\" +\n                    \"    sum += texture2D(inputImageTexture, blurCoordinates[8]).rgb * 0.05;\\n\" +\n                    \"\\n\" +\n                    \"\tgl_FragColor = vec4(sum,fragColor.a);\\n\" +\n                    \"}\";\n\n    protected float blurSize;\n\n    public GPUImageGaussianBlurFilter() {\n        this(1f);\n    }\n\n    public GPUImageGaussianBlurFilter(float blurSize) {\n        super(VERTEX_SHADER, FRAGMENT_SHADER, VERTEX_SHADER, FRAGMENT_SHADER);\n        this.blurSize = blurSize;\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setBlurSize(blurSize);\n    }\n\n    @Override\n    public float getVerticalTexelOffsetRatio() {\n        return blurSize;\n    }\n\n    @Override\n    public float getHorizontalTexelOffsetRatio() {\n        return blurSize;\n    }\n\n    /**\n     * A multiplier for the blur size, ranging from 0.0 on up, with a default of 1.0\n     *\n     * @param blurSize from 0.0 on up, default 1.0\n     */\n    public void setBlurSize(float blurSize) {\n        this.blurSize = blurSize;\n        runOnDraw(new Runnable() {\n            @Override\n            public void run() {\n                initTexelOffsets();\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageGlassSphereFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.graphics.PointF;\nimport android.opengl.GLES20;\n\npublic class GPUImageGlassSphereFilter extends GPUImageFilter {\n    public static final String SPHERE_FRAGMENT_SHADER = \"\" +\n            \"varying highp vec2 textureCoordinate;\\n\" +\n            \"\\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"\\n\" +\n            \"uniform highp vec2 center;\\n\" +\n            \"uniform highp float radius;\\n\" +\n            \"uniform highp float aspectRatio;\\n\" +\n            \"uniform highp float refractiveIndex;\\n\" +\n            \"// uniform vec3 lightPosition;\\n\" +\n            \"const highp vec3 lightPosition = vec3(-0.5, 0.5, 1.0);\\n\" +\n            \"const highp vec3 ambientLightPosition = vec3(0.0, 0.0, 1.0);\\n\" +\n            \"\\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"highp vec2 textureCoordinateToUse = vec2(textureCoordinate.x, (textureCoordinate.y * aspectRatio + 0.5 - 0.5 * aspectRatio));\\n\" +\n            \"highp float distanceFromCenter = distance(center, textureCoordinateToUse);\\n\" +\n            \"lowp float checkForPresenceWithinSphere = step(distanceFromCenter, radius);\\n\" +\n            \"\\n\" +\n            \"distanceFromCenter = distanceFromCenter / radius;\\n\" +\n            \"\\n\" +\n            \"highp float normalizedDepth = radius * sqrt(1.0 - distanceFromCenter * distanceFromCenter);\\n\" +\n            \"highp vec3 sphereNormal = normalize(vec3(textureCoordinateToUse - center, normalizedDepth));\\n\" +\n            \"\\n\" +\n            \"highp vec3 refractedVector = 2.0 * refract(vec3(0.0, 0.0, -1.0), sphereNormal, refractiveIndex);\\n\" +\n            \"refractedVector.xy = -refractedVector.xy;\\n\" +\n            \"\\n\" +\n            \"highp vec3 finalSphereColor = texture2D(inputImageTexture, (refractedVector.xy + 1.0) * 0.5).rgb;\\n\" +\n            \"\\n\" +\n            \"// Grazing angle lighting\\n\" +\n            \"highp float lightingIntensity = 2.5 * (1.0 - pow(clamp(dot(ambientLightPosition, sphereNormal), 0.0, 1.0), 0.25));\\n\" +\n            \"finalSphereColor += lightingIntensity;\\n\" +\n            \"\\n\" +\n            \"// Specular lighting\\n\" +\n            \"lightingIntensity  = clamp(dot(normalize(lightPosition), sphereNormal), 0.0, 1.0);\\n\" +\n            \"lightingIntensity  = pow(lightingIntensity, 15.0);\\n\" +\n            \"finalSphereColor += vec3(0.8, 0.8, 0.8) * lightingIntensity;\\n\" +\n            \"\\n\" +\n            \"gl_FragColor = vec4(finalSphereColor, 1.0) * checkForPresenceWithinSphere;\\n\" +\n            \"}\\n\";\n\n    private PointF center;\n    private int centerLocation;\n    private float radius;\n    private int radiusLocation;\n    private float aspectRatio;\n    private int aspectRatioLocation;\n    private float refractiveIndex;\n    private int refractiveIndexLocation;\n\n    public GPUImageGlassSphereFilter() {\n        this(new PointF(0.5f, 0.5f), 0.25f, 0.71f);\n    }\n\n    public GPUImageGlassSphereFilter(PointF center, float radius, float refractiveIndex) {\n        super(NO_FILTER_VERTEX_SHADER, SPHERE_FRAGMENT_SHADER);\n        this.center = center;\n        this.radius = radius;\n        this.refractiveIndex = refractiveIndex;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        centerLocation = GLES20.glGetUniformLocation(getProgram(), \"center\");\n        radiusLocation = GLES20.glGetUniformLocation(getProgram(), \"radius\");\n        aspectRatioLocation = GLES20.glGetUniformLocation(getProgram(), \"aspectRatio\");\n        refractiveIndexLocation = GLES20.glGetUniformLocation(getProgram(), \"refractiveIndex\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setAspectRatio(aspectRatio);\n        setRadius(radius);\n        setCenter(center);\n        setRefractiveIndex(refractiveIndex);\n    }\n\n    @Override\n    public void onOutputSizeChanged(int width, int height) {\n        aspectRatio = (float) height / width;\n        setAspectRatio(aspectRatio);\n        super.onOutputSizeChanged(width, height);\n    }\n\n    private void setAspectRatio(float aspectRatio) {\n        this.aspectRatio = aspectRatio;\n        setFloat(aspectRatioLocation, aspectRatio);\n    }\n\n    public void setRefractiveIndex(float refractiveIndex) {\n        this.refractiveIndex = refractiveIndex;\n        setFloat(refractiveIndexLocation, refractiveIndex);\n    }\n\n    public void setCenter(PointF center) {\n        this.center = center;\n        setPoint(centerLocation, center);\n    }\n\n    public void setRadius(float radius) {\n        this.radius = radius;\n        setFloat(radiusLocation, radius);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageGrayscaleFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\n/**\n * Applies a grayscale effect to the image.\n */\npublic class GPUImageGrayscaleFilter extends GPUImageFilter {\n    public static final String GRAYSCALE_FRAGMENT_SHADER = \"\" +\n            \"precision highp float;\\n\" +\n            \"\\n\" +\n            \"varying vec2 textureCoordinate;\\n\" +\n            \"\\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"\\n\" +\n            \"const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);\\n\" +\n            \"\\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"  lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"  float luminance = dot(textureColor.rgb, W);\\n\" +\n            \"\\n\" +\n            \"  gl_FragColor = vec4(vec3(luminance), textureColor.a);\\n\" +\n            \"}\";\n\n    public GPUImageGrayscaleFilter() {\n        super(NO_FILTER_VERTEX_SHADER, GRAYSCALE_FRAGMENT_SHADER);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageHalftoneFilter.java",
    "content": "package jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\npublic class GPUImageHalftoneFilter extends GPUImageFilter {\n    public static final String HALFTONE_FRAGMENT_SHADER = \"\" +\n            \"varying highp vec2 textureCoordinate;\\n\" +\n\n            \"uniform sampler2D inputImageTexture;\\n\" +\n\n            \"uniform highp float fractionalWidthOfPixel;\\n\" +\n            \"uniform highp float aspectRatio;\\n\" +\n\n            \"const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);\\n\" +\n\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"  highp vec2 sampleDivisor = vec2(fractionalWidthOfPixel, fractionalWidthOfPixel / aspectRatio);\\n\" +\n            \"  highp vec2 samplePos = textureCoordinate - mod(textureCoordinate, sampleDivisor) + 0.5 * sampleDivisor;\\n\" +\n            \"  highp vec2 textureCoordinateToUse = vec2(textureCoordinate.x, (textureCoordinate.y * aspectRatio + 0.5 - 0.5 * aspectRatio));\\n\" +\n            \"  highp vec2 adjustedSamplePos = vec2(samplePos.x, (samplePos.y * aspectRatio + 0.5 - 0.5 * aspectRatio));\\n\" +\n            \"  highp float distanceFromSamplePoint = distance(adjustedSamplePos, textureCoordinateToUse);\\n\" +\n            \"  lowp vec3 sampledColor = texture2D(inputImageTexture, samplePos).rgb;\\n\" +\n            \"  highp float dotScaling = 1.0 - dot(sampledColor, W);\\n\" +\n            \"  lowp float checkForPresenceWithinDot = 1.0 - step(distanceFromSamplePoint, (fractionalWidthOfPixel * 0.5) * dotScaling);\\n\" +\n            \"  gl_FragColor = vec4(vec3(checkForPresenceWithinDot), 1.0);\\n\" +\n            \"}\";\n\n    private int fractionalWidthOfPixelLocation;\n    private int aspectRatioLocation;\n\n    private float fractionalWidthOfAPixel;\n    private float aspectRatio;\n\n    public GPUImageHalftoneFilter() {\n        this(0.01f);\n    }\n\n    public GPUImageHalftoneFilter(float fractionalWidthOfAPixel) {\n        super(NO_FILTER_VERTEX_SHADER, HALFTONE_FRAGMENT_SHADER);\n        this.fractionalWidthOfAPixel = fractionalWidthOfAPixel;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        fractionalWidthOfPixelLocation = GLES20.glGetUniformLocation(getProgram(), \"fractionalWidthOfPixel\");\n        aspectRatioLocation = GLES20.glGetUniformLocation(getProgram(), \"aspectRatio\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setFractionalWidthOfAPixel(fractionalWidthOfAPixel);\n        setAspectRatio(aspectRatio);\n    }\n\n    @Override\n    public void onOutputSizeChanged(final int width, final int height) {\n        super.onOutputSizeChanged(width, height);\n        setAspectRatio((float) height / (float) width);\n    }\n\n    public void setFractionalWidthOfAPixel(final float fractionalWidthOfAPixel) {\n        this.fractionalWidthOfAPixel = fractionalWidthOfAPixel;\n        setFloat(fractionalWidthOfPixelLocation, this.fractionalWidthOfAPixel);\n    }\n\n    public void setAspectRatio(final float aspectRatio) {\n        this.aspectRatio = aspectRatio;\n        setFloat(aspectRatioLocation, this.aspectRatio);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageHardLightBlendFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\npublic class GPUImageHardLightBlendFilter extends GPUImageTwoInputFilter {\n    public static final String HARD_LIGHT_BLEND_FRAGMENT_SHADER = \"varying highp vec2 textureCoordinate;\\n\" +\n            \" varying highp vec2 textureCoordinate2;\\n\" +\n            \"\\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform sampler2D inputImageTexture2;\\n\" +\n            \"\\n\" +\n            \" const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);\\n\" +\n            \"\\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"     mediump vec4 base = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"     mediump vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);\\n\" +\n            \"\\n\" +\n            \"     highp float ra;\\n\" +\n            \"     if (2.0 * overlay.r < overlay.a) {\\n\" +\n            \"         ra = 2.0 * overlay.r * base.r + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);\\n\" +\n            \"     } else {\\n\" +\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\" +\n            \"     \\n\" +\n            \"     highp float ga;\\n\" +\n            \"     if (2.0 * overlay.g < overlay.a) {\\n\" +\n            \"         ga = 2.0 * overlay.g * base.g + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);\\n\" +\n            \"     } else {\\n\" +\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\" +\n            \"     \\n\" +\n            \"     highp float ba;\\n\" +\n            \"     if (2.0 * overlay.b < overlay.a) {\\n\" +\n            \"         ba = 2.0 * overlay.b * base.b + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);\\n\" +\n            \"     } else {\\n\" +\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\" +\n            \"     \\n\" +\n            \"     gl_FragColor = vec4(ra, ga, ba, 1.0);\\n\" +\n            \" }\";\n\n    public GPUImageHardLightBlendFilter() {\n        super(HARD_LIGHT_BLEND_FRAGMENT_SHADER);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageHazeFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\n/**\n * The haze filter can be used to add or remove haze.\n * <p>\n * This is similar to a UV filter.\n */\npublic class GPUImageHazeFilter extends GPUImageFilter {\n    public static final String HAZE_FRAGMENT_SHADER = \"\" +\n            \"varying highp vec2 textureCoordinate;\\n\" +\n            \"\\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"\\n\" +\n            \"uniform lowp float distance;\\n\" +\n            \"uniform highp float slope;\\n\" +\n            \"\\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"\t//todo reconsider precision modifiers\t \\n\" +\n            \"\t highp vec4 color = vec4(1.0);//todo reimplement as a parameter\\n\" +\n            \"\\n\" +\n            \"\t highp float  d = textureCoordinate.y * slope  +  distance; \\n\" +\n            \"\\n\" +\n            \"\t highp vec4 c = texture2D(inputImageTexture, textureCoordinate) ; // consider using unpremultiply\\n\" +\n            \"\\n\" +\n            \"\t c = (c - d * color) / (1.0 -d);\\n\" +\n            \"\\n\" +\n            \"\t gl_FragColor = c; //consider using premultiply(c);\\n\" +\n            \"}\\n\";\n\n    private float distance;\n    private int distanceLocation;\n    private float slope;\n    private int slopeLocation;\n\n    public GPUImageHazeFilter() {\n        this(0.2f, 0.0f);\n    }\n\n    public GPUImageHazeFilter(float distance, float slope) {\n        super(NO_FILTER_VERTEX_SHADER, HAZE_FRAGMENT_SHADER);\n        this.distance = distance;\n        this.slope = slope;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        distanceLocation = GLES20.glGetUniformLocation(getProgram(), \"distance\");\n        slopeLocation = GLES20.glGetUniformLocation(getProgram(), \"slope\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setDistance(distance);\n        setSlope(slope);\n    }\n\n    /**\n     * Strength of the color applied. Default 0. Values between -.3 and .3 are best.\n     *\n     * @param distance -0.3 to 0.3 are best, default 0\n     */\n    public void setDistance(float distance) {\n        this.distance = distance;\n        setFloat(distanceLocation, distance);\n    }\n\n    /**\n     * Amount of color change. Default 0. Values between -.3 and .3 are best.\n     *\n     * @param slope -0.3 to 0.3 are best, default 0\n     */\n    public void setSlope(float slope) {\n        this.slope = slope;\n        setFloat(slopeLocation, slope);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageHighlightShadowFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\n/**\n * Adjusts the shadows and highlights of an image\n * shadows: Increase to lighten shadows, from 0.0 to 1.0, with 0.0 as the default.\n * highlights: Decrease to darken highlights, from 0.0 to 1.0, with 1.0 as the default.\n */\npublic class GPUImageHighlightShadowFilter extends GPUImageFilter {\n    public static final String HIGHLIGHT_SHADOW_FRAGMENT_SHADER = \"\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" varying highp vec2 textureCoordinate;\\n\" +\n            \"  \\n\" +\n            \" uniform lowp float shadows;\\n\" +\n            \" uniform lowp float highlights;\\n\" +\n            \" \\n\" +\n            \" const mediump vec3 luminanceWeighting = vec3(0.3, 0.3, 0.3);\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \" \tlowp vec4 source = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \" \tmediump float luminance = dot(source.rgb, luminanceWeighting);\\n\" +\n            \" \\n\" +\n            \" \tmediump 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\" +\n            \" \tmediump 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\" +\n            \" \tlowp 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            \" \\n\" +\n            \" \tgl_FragColor = vec4(result.rgb, source.a);\\n\" +\n            \" }\";\n\n    private int shadowsLocation;\n    private float shadows;\n    private int highlightsLocation;\n    private float highlights;\n\n    public GPUImageHighlightShadowFilter() {\n        this(0.0f, 1.0f);\n    }\n\n    public GPUImageHighlightShadowFilter(final float shadows, final float highlights) {\n        super(NO_FILTER_VERTEX_SHADER, HIGHLIGHT_SHADOW_FRAGMENT_SHADER);\n        this.highlights = highlights;\n        this.shadows = shadows;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        highlightsLocation = GLES20.glGetUniformLocation(getProgram(), \"highlights\");\n        shadowsLocation = GLES20.glGetUniformLocation(getProgram(), \"shadows\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setHighlights(highlights);\n        setShadows(shadows);\n    }\n\n    public void setHighlights(final float highlights) {\n        this.highlights = highlights;\n        setFloat(highlightsLocation, this.highlights);\n    }\n\n    public void setShadows(final float shadows) {\n        this.shadows = shadows;\n        setFloat(shadowsLocation, this.shadows);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageHueBlendFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\npublic class GPUImageHueBlendFilter extends GPUImageTwoInputFilter {\n    public static final String HUE_BLEND_FRAGMENT_SHADER = \"varying highp vec2 textureCoordinate;\\n\" +\n            \" varying highp vec2 textureCoordinate2;\\n\" +\n            \" \\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform sampler2D inputImageTexture2;\\n\" +\n            \" \\n\" +\n            \" highp float lum(lowp vec3 c) {\\n\" +\n            \"     return dot(c, vec3(0.3, 0.59, 0.11));\\n\" +\n            \" }\\n\" +\n            \" \\n\" +\n            \" lowp vec3 clipcolor(lowp vec3 c) {\\n\" +\n            \"     highp float l = lum(c);\\n\" +\n            \"     lowp float n = min(min(c.r, c.g), c.b);\\n\" +\n            \"     lowp float x = max(max(c.r, c.g), c.b);\\n\" +\n            \"     \\n\" +\n            \"     if (n < 0.0) {\\n\" +\n            \"         c.r = l + ((c.r - l) * l) / (l - n);\\n\" +\n            \"         c.g = l + ((c.g - l) * l) / (l - n);\\n\" +\n            \"         c.b = l + ((c.b - l) * l) / (l - n);\\n\" +\n            \"     }\\n\" +\n            \"     if (x > 1.0) {\\n\" +\n            \"         c.r = l + ((c.r - l) * (1.0 - l)) / (x - l);\\n\" +\n            \"         c.g = l + ((c.g - l) * (1.0 - l)) / (x - l);\\n\" +\n            \"         c.b = l + ((c.b - l) * (1.0 - l)) / (x - l);\\n\" +\n            \"     }\\n\" +\n            \"     \\n\" +\n            \"     return c;\\n\" +\n            \" }\\n\" +\n            \" \\n\" +\n            \" lowp vec3 setlum(lowp vec3 c, highp float l) {\\n\" +\n            \"     highp float d = l - lum(c);\\n\" +\n            \"     c = c + vec3(d);\\n\" +\n            \"     return clipcolor(c);\\n\" +\n            \" }\\n\" +\n            \" \\n\" +\n            \" highp float sat(lowp vec3 c) {\\n\" +\n            \"     lowp float n = min(min(c.r, c.g), c.b);\\n\" +\n            \"     lowp float x = max(max(c.r, c.g), c.b);\\n\" +\n            \"     return x - n;\\n\" +\n            \" }\\n\" +\n            \" \\n\" +\n            \" lowp float mid(lowp float cmin, lowp float cmid, lowp float cmax, highp float s) {\\n\" +\n            \"     return ((cmid - cmin) * s) / (cmax - cmin);\\n\" +\n            \" }\\n\" +\n            \" \\n\" +\n            \" lowp vec3 setsat(lowp vec3 c, highp float s) {\\n\" +\n            \"     if (c.r > c.g) {\\n\" +\n            \"         if (c.r > c.b) {\\n\" +\n            \"             if (c.g > c.b) {\\n\" +\n            \"                 /* g is mid, b is min */\\n\" +\n            \"                 c.g = mid(c.b, c.g, c.r, s);\\n\" +\n            \"                 c.b = 0.0;\\n\" +\n            \"             } else {\\n\" +\n            \"                 /* b is mid, g is min */\\n\" +\n            \"                 c.b = mid(c.g, c.b, c.r, s);\\n\" +\n            \"                 c.g = 0.0;\\n\" +\n            \"             }\\n\" +\n            \"             c.r = s;\\n\" +\n            \"         } else {\\n\" +\n            \"             /* b is max, r is mid, g is min */\\n\" +\n            \"             c.r = mid(c.g, c.r, c.b, s);\\n\" +\n            \"             c.b = s;\\n\" +\n            \"             c.r = 0.0;\\n\" +\n            \"         }\\n\" +\n            \"     } else if (c.r > c.b) {\\n\" +\n            \"         /* g is max, r is mid, b is min */\\n\" +\n            \"         c.r = mid(c.b, c.r, c.g, s);\\n\" +\n            \"         c.g = s;\\n\" +\n            \"         c.b = 0.0;\\n\" +\n            \"     } else if (c.g > c.b) {\\n\" +\n            \"         /* g is max, b is mid, r is min */\\n\" +\n            \"         c.b = mid(c.r, c.b, c.g, s);\\n\" +\n            \"         c.g = s;\\n\" +\n            \"         c.r = 0.0;\\n\" +\n            \"     } else if (c.b > c.g) {\\n\" +\n            \"         /* b is max, g is mid, r is min */\\n\" +\n            \"         c.g = mid(c.r, c.g, c.b, s);\\n\" +\n            \"         c.b = s;\\n\" +\n            \"         c.r = 0.0;\\n\" +\n            \"     } else {\\n\" +\n            \"         c = vec3(0.0);\\n\" +\n            \"     }\\n\" +\n            \"     return c;\\n\" +\n            \" }\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"   highp vec4 baseColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"   highp vec4 overlayColor = texture2D(inputImageTexture2, textureCoordinate2);\\n\" +\n            \"     \\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\" +\n            \" }\";\n\n    public GPUImageHueBlendFilter() {\n        super(HUE_BLEND_FRAGMENT_SHADER);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageHueFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\npublic class GPUImageHueFilter extends GPUImageFilter {\n    public static final String HUE_FRAGMENT_SHADER = \"\" +\n            \"precision highp float;\\n\" +\n            \"varying highp vec2 textureCoordinate;\\n\" +\n            \"\\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"uniform mediump float hueAdjust;\\n\" +\n            \"const highp vec4 kRGBToYPrime = vec4 (0.299, 0.587, 0.114, 0.0);\\n\" +\n            \"const highp vec4 kRGBToI = vec4 (0.595716, -0.274453, -0.321263, 0.0);\\n\" +\n            \"const highp vec4 kRGBToQ = vec4 (0.211456, -0.522591, 0.31135, 0.0);\\n\" +\n            \"\\n\" +\n            \"const highp vec4 kYIQToR = vec4 (1.0, 0.9563, 0.6210, 0.0);\\n\" +\n            \"const highp vec4 kYIQToG = vec4 (1.0, -0.2721, -0.6474, 0.0);\\n\" +\n            \"const highp vec4 kYIQToB = vec4 (1.0, -1.1070, 1.7046, 0.0);\\n\" +\n            \"\\n\" +\n            \"void main ()\\n\" +\n            \"{\\n\" +\n            \"    // Sample the input pixel\\n\" +\n            \"    highp vec4 color = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"\\n\" +\n            \"    // Convert to YIQ\\n\" +\n            \"    highp float YPrime = dot (color, kRGBToYPrime);\\n\" +\n            \"    highp float I = dot (color, kRGBToI);\\n\" +\n            \"    highp float Q = dot (color, kRGBToQ);\\n\" +\n            \"\\n\" +\n            \"    // Calculate the hue and chroma\\n\" +\n            \"    highp float hue = atan (Q, I);\\n\" +\n            \"    highp float chroma = sqrt (I * I + Q * Q);\\n\" +\n            \"\\n\" +\n            \"    // Make the user's adjustments\\n\" +\n            \"    hue += (-hueAdjust); //why negative rotation?\\n\" +\n            \"\\n\" +\n            \"    // Convert back to YIQ\\n\" +\n            \"    Q = chroma * sin (hue);\\n\" +\n            \"    I = chroma * cos (hue);\\n\" +\n            \"\\n\" +\n            \"    // Convert back to RGB\\n\" +\n            \"    highp vec4 yIQ = vec4 (YPrime, I, Q, 0.0);\\n\" +\n            \"    color.r = dot (yIQ, kYIQToR);\\n\" +\n            \"    color.g = dot (yIQ, kYIQToG);\\n\" +\n            \"    color.b = dot (yIQ, kYIQToB);\\n\" +\n            \"\\n\" +\n            \"    // Save the result\\n\" +\n            \"    gl_FragColor = color;\\n\" +\n            \"}\\n\";\n\n    private float hue;\n    private int hueLocation;\n\n    public GPUImageHueFilter() {\n        this(90.0f);\n    }\n\n    public GPUImageHueFilter(final float hue) {\n        super(NO_FILTER_VERTEX_SHADER, HUE_FRAGMENT_SHADER);\n        this.hue = hue;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        hueLocation = GLES20.glGetUniformLocation(getProgram(), \"hueAdjust\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setHue(hue);\n    }\n\n    public void setHue(final float hue) {\n        this.hue = hue;\n        float hueAdjust = (this.hue % 360.0f) * (float) Math.PI / 180.0f;\n        setFloat(hueLocation, hueAdjust);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageKuwaharaFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\n/**\n * Kuwahara image abstraction, drawn from the work of Kyprianidis, et. al. in their publication\n * \"Anisotropic Kuwahara Filtering on the GPU\" within the GPU Pro collection. This produces an oil-painting-like\n * image, but it is extremely computationally expensive, so it can take seconds to render a frame on an iPad 2.\n * This might be best used for still images.\n */\npublic class GPUImageKuwaharaFilter extends GPUImageFilter {\n    public static final String KUWAHARA_FRAGMENT_SHADER = \"\" +\n            \"varying highp vec2 textureCoordinate;\\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"uniform int radius;\\n\" +\n            \"\\n\" +\n            \"precision highp float;\\n\" +\n            \"\\n\" +\n            \"const vec2 src_size = vec2 (1.0 / 768.0, 1.0 / 1024.0);\\n\" +\n            \"\\n\" +\n            \"void main (void) \\n\" +\n            \"{\\n\" +\n            \"vec2 uv = textureCoordinate;\\n\" +\n            \"float n = float((radius + 1) * (radius + 1));\\n\" +\n            \"int i; int j;\\n\" +\n            \"vec3 m0 = vec3(0.0); vec3 m1 = vec3(0.0); vec3 m2 = vec3(0.0); vec3 m3 = vec3(0.0);\\n\" +\n            \"vec3 s0 = vec3(0.0); vec3 s1 = vec3(0.0); vec3 s2 = vec3(0.0); vec3 s3 = vec3(0.0);\\n\" +\n            \"vec3 c;\\n\" +\n            \"\\n\" +\n            \"for (j = -radius; j <= 0; ++j)  {\\n\" +\n            \"for (i = -radius; i <= 0; ++i)  {\\n\" +\n            \"c = texture2D(inputImageTexture, uv + vec2(i,j) * src_size).rgb;\\n\" +\n            \"m0 += c;\\n\" +\n            \"s0 += c * c;\\n\" +\n            \"}\\n\" +\n            \"}\\n\" +\n            \"\\n\" +\n            \"for (j = -radius; j <= 0; ++j)  {\\n\" +\n            \"for (i = 0; i <= radius; ++i)  {\\n\" +\n            \"c = texture2D(inputImageTexture, uv + vec2(i,j) * src_size).rgb;\\n\" +\n            \"m1 += c;\\n\" +\n            \"s1 += c * c;\\n\" +\n            \"}\\n\" +\n            \"}\\n\" +\n            \"\\n\" +\n            \"for (j = 0; j <= radius; ++j)  {\\n\" +\n            \"for (i = 0; i <= radius; ++i)  {\\n\" +\n            \"c = texture2D(inputImageTexture, uv + vec2(i,j) * src_size).rgb;\\n\" +\n            \"m2 += c;\\n\" +\n            \"s2 += c * c;\\n\" +\n            \"}\\n\" +\n            \"}\\n\" +\n            \"\\n\" +\n            \"for (j = 0; j <= radius; ++j)  {\\n\" +\n            \"for (i = -radius; i <= 0; ++i)  {\\n\" +\n            \"c = texture2D(inputImageTexture, uv + vec2(i,j) * src_size).rgb;\\n\" +\n            \"m3 += c;\\n\" +\n            \"s3 += c * c;\\n\" +\n            \"}\\n\" +\n            \"}\\n\" +\n            \"\\n\" +\n            \"\\n\" +\n            \"float min_sigma2 = 1e+2;\\n\" +\n            \"m0 /= n;\\n\" +\n            \"s0 = abs(s0 / n - m0 * m0);\\n\" +\n            \"\\n\" +\n            \"float sigma2 = s0.r + s0.g + s0.b;\\n\" +\n            \"if (sigma2 < min_sigma2) {\\n\" +\n            \"min_sigma2 = sigma2;\\n\" +\n            \"gl_FragColor = vec4(m0, 1.0);\\n\" +\n            \"}\\n\" +\n            \"\\n\" +\n            \"m1 /= n;\\n\" +\n            \"s1 = abs(s1 / n - m1 * m1);\\n\" +\n            \"\\n\" +\n            \"sigma2 = s1.r + s1.g + s1.b;\\n\" +\n            \"if (sigma2 < min_sigma2) {\\n\" +\n            \"min_sigma2 = sigma2;\\n\" +\n            \"gl_FragColor = vec4(m1, 1.0);\\n\" +\n            \"}\\n\" +\n            \"\\n\" +\n            \"m2 /= n;\\n\" +\n            \"s2 = abs(s2 / n - m2 * m2);\\n\" +\n            \"\\n\" +\n            \"sigma2 = s2.r + s2.g + s2.b;\\n\" +\n            \"if (sigma2 < min_sigma2) {\\n\" +\n            \"min_sigma2 = sigma2;\\n\" +\n            \"gl_FragColor = vec4(m2, 1.0);\\n\" +\n            \"}\\n\" +\n            \"\\n\" +\n            \"m3 /= n;\\n\" +\n            \"s3 = abs(s3 / n - m3 * m3);\\n\" +\n            \"\\n\" +\n            \"sigma2 = s3.r + s3.g + s3.b;\\n\" +\n            \"if (sigma2 < min_sigma2) {\\n\" +\n            \"min_sigma2 = sigma2;\\n\" +\n            \"gl_FragColor = vec4(m3, 1.0);\\n\" +\n            \"}\\n\" +\n            \"}\\n\";\n\n    private int radius;\n    private int radiusLocation;\n\n    public GPUImageKuwaharaFilter() {\n        this(3);\n    }\n\n    public GPUImageKuwaharaFilter(int radius) {\n        super(NO_FILTER_VERTEX_SHADER, KUWAHARA_FRAGMENT_SHADER);\n        this.radius = radius;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        radiusLocation = GLES20.glGetUniformLocation(getProgram(), \"radius\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setRadius(radius);\n    }\n\n    /**\n     * The radius to sample from when creating the brush-stroke effect, with a default of 3.\n     * The larger the radius, the slower the filter.\n     *\n     * @param radius default 3\n     */\n    public void setRadius(final int radius) {\n        this.radius = radius;\n        setInteger(radiusLocation, radius);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageLaplacianFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\npublic class GPUImageLaplacianFilter extends GPUImage3x3TextureSamplingFilter {\n    public static final String LAPLACIAN_FRAGMENT_SHADER = \"\" +\n            \"precision highp float;\\n\" +\n            \"\\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"\\n\" +\n            \"uniform mediump mat3 convolutionMatrix;\\n\" +\n            \"\\n\" +\n            \"varying vec2 textureCoordinate;\\n\" +\n            \"varying vec2 leftTextureCoordinate;\\n\" +\n            \"varying vec2 rightTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"varying vec2 topTextureCoordinate;\\n\" +\n            \"varying vec2 topLeftTextureCoordinate;\\n\" +\n            \"varying vec2 topRightTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"varying vec2 bottomTextureCoordinate;\\n\" +\n            \"varying vec2 bottomLeftTextureCoordinate;\\n\" +\n            \"varying vec2 bottomRightTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"mediump vec3 bottomColor = texture2D(inputImageTexture, bottomTextureCoordinate).rgb;\\n\" +\n            \"mediump vec3 bottomLeftColor = texture2D(inputImageTexture, bottomLeftTextureCoordinate).rgb;\\n\" +\n            \"mediump vec3 bottomRightColor = texture2D(inputImageTexture, bottomRightTextureCoordinate).rgb;\\n\" +\n            \"mediump vec4 centerColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"mediump vec3 leftColor = texture2D(inputImageTexture, leftTextureCoordinate).rgb;\\n\" +\n            \"mediump vec3 rightColor = texture2D(inputImageTexture, rightTextureCoordinate).rgb;\\n\" +\n            \"mediump vec3 topColor = texture2D(inputImageTexture, topTextureCoordinate).rgb;\\n\" +\n            \"mediump vec3 topRightColor = texture2D(inputImageTexture, topRightTextureCoordinate).rgb;\\n\" +\n            \"mediump vec3 topLeftColor = texture2D(inputImageTexture, topLeftTextureCoordinate).rgb;\\n\" +\n            \"\\n\" +\n            \"mediump vec3 resultColor = topLeftColor * convolutionMatrix[0][0] + topColor * convolutionMatrix[0][1] + topRightColor * convolutionMatrix[0][2];\\n\" +\n            \"resultColor += leftColor * convolutionMatrix[1][0] + centerColor.rgb * convolutionMatrix[1][1] + rightColor * convolutionMatrix[1][2];\\n\" +\n            \"resultColor += bottomLeftColor * convolutionMatrix[2][0] + bottomColor * convolutionMatrix[2][1] + bottomRightColor * convolutionMatrix[2][2];\\n\" +\n            \"\\n\" +\n            \"// Normalize the results to allow for negative gradients in the 0.0-1.0 colorspace\\n\" +\n            \"resultColor = resultColor + 0.5;\\n\" +\n            \"\\n\" +\n            \"gl_FragColor = vec4(resultColor, centerColor.a);\\n\" +\n            \"}\\n\";\n\n    private float[] convolutionKernel;\n    private int uniformConvolutionMatrix;\n\n    public GPUImageLaplacianFilter() {\n        this(new float[]{\n                0.5f, 1.0f, 0.5f,\n                1.0f, -6.0f, 1.0f,\n                0.5f, 1.0f, 0.5f\n        });\n    }\n\n    private GPUImageLaplacianFilter(final float[] convolutionKernel) {\n        super(LAPLACIAN_FRAGMENT_SHADER);\n        this.convolutionKernel = convolutionKernel;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        uniformConvolutionMatrix = GLES20.glGetUniformLocation(getProgram(), \"convolutionMatrix\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setConvolutionKernel(convolutionKernel);\n    }\n\n    private void setConvolutionKernel(final float[] convolutionKernel) {\n        this.convolutionKernel = convolutionKernel;\n        setUniformMatrix3f(uniformConvolutionMatrix, this.convolutionKernel);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageLevelsFilter.java",
    "content": "package jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\n/**\n * Created by vashisthg 30/05/14.\n */\npublic class GPUImageLevelsFilter extends GPUImageFilter {\n\n    private static final String LOGTAG = GPUImageLevelsFilter.class.getSimpleName();\n\n    public static final String LEVELS_FRAGMET_SHADER =\n\n            \" varying highp vec2 textureCoordinate;\\n\" +\n                    \" \\n\" +\n                    \" uniform sampler2D inputImageTexture;\\n\" +\n                    \" uniform mediump vec3 levelMinimum;\\n\" +\n                    \" uniform mediump vec3 levelMiddle;\\n\" +\n                    \" uniform mediump vec3 levelMaximum;\\n\" +\n                    \" uniform mediump vec3 minOutput;\\n\" +\n                    \" uniform mediump vec3 maxOutput;\\n\" +\n                    \" \\n\" +\n                    \" void main()\\n\" +\n                    \" {\\n\" +\n                    \"     mediump vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n                    \"     \\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                    \" }\\n\";\n\n    private int minLocation;\n    private float[] min;\n    private int midLocation;\n    private float[] mid;\n    private int maxLocation;\n    private float[] max;\n    private int minOutputLocation;\n    private float[] minOutput;\n    private int maxOutputLocation;\n    private float[] maxOutput;\n\n    public GPUImageLevelsFilter() {\n        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});\n    }\n\n    private GPUImageLevelsFilter(final float[] min, final float[] mid, final float[] max, final float[] minOUt, final float[] maxOut) {\n        super(NO_FILTER_VERTEX_SHADER, LEVELS_FRAGMET_SHADER);\n\n        this.min = min;\n        this.mid = mid;\n        this.max = max;\n        minOutput = minOUt;\n        maxOutput = maxOut;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        minLocation = GLES20.glGetUniformLocation(getProgram(), \"levelMinimum\");\n        midLocation = GLES20.glGetUniformLocation(getProgram(), \"levelMiddle\");\n        maxLocation = GLES20.glGetUniformLocation(getProgram(), \"levelMaximum\");\n        minOutputLocation = GLES20.glGetUniformLocation(getProgram(), \"minOutput\");\n        maxOutputLocation = GLES20.glGetUniformLocation(getProgram(), \"maxOutput\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setMin(0.0f, 1.0f, 1.0f, 0.0f, 1.0f);\n        updateUniforms();\n    }\n\n\n    public void updateUniforms() {\n        setFloatVec3(minLocation, min);\n        setFloatVec3(midLocation, mid);\n        setFloatVec3(maxLocation, max);\n        setFloatVec3(minOutputLocation, minOutput);\n        setFloatVec3(maxOutputLocation, maxOutput);\n    }\n\n    public void setMin(float min, float mid, float max, float minOut, float maxOut) {\n        setRedMin(min, mid, max, minOut, maxOut);\n        setGreenMin(min, mid, max, minOut, maxOut);\n        setBlueMin(min, mid, max, minOut, maxOut);\n    }\n\n    public void setMin(float min, float mid, float max) {\n        setMin(min, mid, max, 0.0f, 1.0f);\n    }\n\n    public void setRedMin(float min, float mid, float max, float minOut, float maxOut) {\n        this.min[0] = min;\n        this.mid[0] = mid;\n        this.max[0] = max;\n        minOutput[0] = minOut;\n        maxOutput[0] = maxOut;\n        updateUniforms();\n    }\n\n    public void setRedMin(float min, float mid, float max) {\n        setRedMin(min, mid, max, 0, 1);\n    }\n\n    public void setGreenMin(float min, float mid, float max, float minOut, float maxOut) {\n        this.min[1] = min;\n        this.mid[1] = mid;\n        this.max[1] = max;\n        minOutput[1] = minOut;\n        maxOutput[1] = maxOut;\n        updateUniforms();\n    }\n\n    public void setGreenMin(float min, float mid, float max) {\n        setGreenMin(min, mid, max, 0, 1);\n    }\n\n    public void setBlueMin(float min, float mid, float max, float minOut, float maxOut) {\n        this.min[2] = min;\n        this.mid[2] = mid;\n        this.max[2] = max;\n        minOutput[2] = minOut;\n        maxOutput[2] = maxOut;\n        updateUniforms();\n    }\n\n    public void setBlueMin(float min, float mid, float max) {\n        setBlueMin(min, mid, max, 0, 1);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageLightenBlendFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\npublic class GPUImageLightenBlendFilter extends GPUImageTwoInputFilter {\n    public static final String LIGHTEN_BLEND_FRAGMENT_SHADER = \"varying highp vec2 textureCoordinate;\\n\" +\n            \" varying highp vec2 textureCoordinate2;\\n\" +\n            \"\\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform sampler2D inputImageTexture2;\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"    lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"    lowp vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);\\n\" +\n            \"    \\n\" +\n            \"    gl_FragColor = max(textureColor, textureColor2);\\n\" +\n            \" }\";\n\n    public GPUImageLightenBlendFilter() {\n        super(LIGHTEN_BLEND_FRAGMENT_SHADER);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageLinearBurnBlendFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\npublic class GPUImageLinearBurnBlendFilter extends GPUImageTwoInputFilter {\n    public static final String LINEAR_BURN_BLEND_FRAGMENT_SHADER = \"varying highp vec2 textureCoordinate;\\n\" +\n            \" varying highp vec2 textureCoordinate2;\\n\" +\n            \" \\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform sampler2D inputImageTexture2;\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"     mediump vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"     mediump vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);\\n\" +\n            \"     \\n\" +\n            \"     gl_FragColor = vec4(clamp(textureColor.rgb + textureColor2.rgb - vec3(1.0), vec3(0.0), vec3(1.0)), textureColor.a);\\n\" +\n            \" }\";\n\n    public GPUImageLinearBurnBlendFilter() {\n        super(LINEAR_BURN_BLEND_FRAGMENT_SHADER);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageLookupFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\npublic class GPUImageLookupFilter extends GPUImageTwoInputFilter {\n\n    public static final String LOOKUP_FRAGMENT_SHADER = \"varying highp vec2 textureCoordinate;\\n\" +\n            \" varying highp vec2 textureCoordinate2; // TODO: This is not used\\n\" +\n            \" \\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform sampler2D inputImageTexture2; // lookup texture\\n\" +\n            \" \\n\" +\n            \" uniform lowp float intensity;\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"     highp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"     \\n\" +\n            \"     highp float blueColor = textureColor.b * 63.0;\\n\" +\n            \"     \\n\" +\n            \"     highp vec2 quad1;\\n\" +\n            \"     quad1.y = floor(floor(blueColor) / 8.0);\\n\" +\n            \"     quad1.x = floor(blueColor) - (quad1.y * 8.0);\\n\" +\n            \"     \\n\" +\n            \"     highp vec2 quad2;\\n\" +\n            \"     quad2.y = floor(ceil(blueColor) / 8.0);\\n\" +\n            \"     quad2.x = ceil(blueColor) - (quad2.y * 8.0);\\n\" +\n            \"     \\n\" +\n            \"     highp vec2 texPos1;\\n\" +\n            \"     texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);\\n\" +\n            \"     texPos1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);\\n\" +\n            \"     \\n\" +\n            \"     highp vec2 texPos2;\\n\" +\n            \"     texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);\\n\" +\n            \"     texPos2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);\\n\" +\n            \"     \\n\" +\n            \"     lowp vec4 newColor1 = texture2D(inputImageTexture2, texPos1);\\n\" +\n            \"     lowp vec4 newColor2 = texture2D(inputImageTexture2, texPos2);\\n\" +\n            \"     \\n\" +\n            \"     lowp vec4 newColor = mix(newColor1, newColor2, fract(blueColor));\\n\" +\n            \"     gl_FragColor = mix(textureColor, vec4(newColor.rgb, textureColor.w), intensity);\\n\" +\n            \" }\";\n\n    private int intensityLocation;\n    private float intensity;\n\n    public GPUImageLookupFilter() {\n        this(1.0f);\n    }\n\n    public GPUImageLookupFilter(final float intensity) {\n        super(LOOKUP_FRAGMENT_SHADER);\n        this.intensity = intensity;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        intensityLocation = GLES20.glGetUniformLocation(getProgram(), \"intensity\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setIntensity(intensity);\n    }\n\n    public void setIntensity(final float intensity) {\n        this.intensity = intensity;\n        setFloat(intensityLocation, this.intensity);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageLuminanceFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\npublic class GPUImageLuminanceFilter extends GPUImageFilter {\n\n    public static final String LUMINANCE_FRAGMENT_SHADER = \"\" +\n            \"precision highp float;\\n\" +\n            \"\\n\" +\n            \"varying vec2 textureCoordinate;\\n\" +\n            \"\\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"\\n\" +\n            \"// Values from \\\"Graphics Shaders: Theory and Practice\\\" by Bailey and Cunningham\\n\" +\n            \"const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);\\n\" +\n            \"\\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"    lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"    float luminance = dot(textureColor.rgb, W);\\n\" +\n            \"    \\n\" +\n            \"    gl_FragColor = vec4(vec3(luminance), textureColor.a);\\n\" +\n            \"}\";\n\n    public GPUImageLuminanceFilter() {\n        super(NO_FILTER_VERTEX_SHADER, LUMINANCE_FRAGMENT_SHADER);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageLuminanceThresholdFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\npublic class GPUImageLuminanceThresholdFilter extends GPUImageFilter {\n\n    public static final String LUMINANCE_THRESHOLD_FRAGMENT_SHADER = \"\" +\n            \"varying highp vec2 textureCoordinate;\\n\" +\n            \"\\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"uniform highp float threshold;\\n\" +\n            \"\\n\" +\n            \"const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);\\n\" +\n            \"\\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"    highp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"    highp float luminance = dot(textureColor.rgb, W);\\n\" +\n            \"    highp float thresholdResult = step(threshold, luminance);\\n\" +\n            \"    \\n\" +\n            \"    gl_FragColor = vec4(vec3(thresholdResult), textureColor.w);\\n\" +\n            \"}\";\n\n    private int uniformThresholdLocation;\n    private float threshold;\n\n    public GPUImageLuminanceThresholdFilter() {\n        this(0.5f);\n    }\n\n    public GPUImageLuminanceThresholdFilter(float threshold) {\n        super(NO_FILTER_VERTEX_SHADER, LUMINANCE_THRESHOLD_FRAGMENT_SHADER);\n        this.threshold = threshold;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        uniformThresholdLocation = GLES20.glGetUniformLocation(getProgram(), \"threshold\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setThreshold(threshold);\n    }\n\n    public void setThreshold(final float threshold) {\n        this.threshold = threshold;\n        setFloat(uniformThresholdLocation, threshold);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageLuminosityBlendFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\npublic class GPUImageLuminosityBlendFilter extends GPUImageTwoInputFilter {\n    public static final String LUMINOSITY_BLEND_FRAGMENT_SHADER = \"varying highp vec2 textureCoordinate;\\n\" +\n            \" varying highp vec2 textureCoordinate2;\\n\" +\n            \" \\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform sampler2D inputImageTexture2;\\n\" +\n            \" \\n\" +\n            \" highp float lum(lowp vec3 c) {\\n\" +\n            \"     return dot(c, vec3(0.3, 0.59, 0.11));\\n\" +\n            \" }\\n\" +\n            \" \\n\" +\n            \" lowp vec3 clipcolor(lowp vec3 c) {\\n\" +\n            \"     highp float l = lum(c);\\n\" +\n            \"     lowp float n = min(min(c.r, c.g), c.b);\\n\" +\n            \"     lowp float x = max(max(c.r, c.g), c.b);\\n\" +\n            \"     \\n\" +\n            \"     if (n < 0.0) {\\n\" +\n            \"         c.r = l + ((c.r - l) * l) / (l - n);\\n\" +\n            \"         c.g = l + ((c.g - l) * l) / (l - n);\\n\" +\n            \"         c.b = l + ((c.b - l) * l) / (l - n);\\n\" +\n            \"     }\\n\" +\n            \"     if (x > 1.0) {\\n\" +\n            \"         c.r = l + ((c.r - l) * (1.0 - l)) / (x - l);\\n\" +\n            \"         c.g = l + ((c.g - l) * (1.0 - l)) / (x - l);\\n\" +\n            \"         c.b = l + ((c.b - l) * (1.0 - l)) / (x - l);\\n\" +\n            \"     }\\n\" +\n            \"     \\n\" +\n            \"     return c;\\n\" +\n            \" }\\n\" +\n            \" \\n\" +\n            \" lowp vec3 setlum(lowp vec3 c, highp float l) {\\n\" +\n            \"     highp float d = l - lum(c);\\n\" +\n            \"     c = c + vec3(d);\\n\" +\n            \"     return clipcolor(c);\\n\" +\n            \" }\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"   highp vec4 baseColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"   highp vec4 overlayColor = texture2D(inputImageTexture2, textureCoordinate2);\\n\" +\n            \"     \\n\" +\n            \"     gl_FragColor = vec4(baseColor.rgb * (1.0 - overlayColor.a) + setlum(baseColor.rgb, lum(overlayColor.rgb)) * overlayColor.a, baseColor.a);\\n\" +\n            \" }\";\n\n    public GPUImageLuminosityBlendFilter() {\n        super(LUMINOSITY_BLEND_FRAGMENT_SHADER);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageMixBlendFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\npublic class GPUImageMixBlendFilter extends GPUImageTwoInputFilter {\n\n    private int mixLocation;\n    private float mix;\n\n    public GPUImageMixBlendFilter(String fragmentShader) {\n        this(fragmentShader, 0.5f);\n    }\n\n    public GPUImageMixBlendFilter(String fragmentShader, float mix) {\n        super(fragmentShader);\n        this.mix = mix;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        mixLocation = GLES20.glGetUniformLocation(getProgram(), \"mixturePercent\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setMix(mix);\n    }\n\n    /**\n     * @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\n     */\n    public void setMix(final float mix) {\n        this.mix = mix;\n        setFloat(mixLocation, this.mix);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageMonochromeFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\n/**\n * Converts the image to a single-color version, based on the luminance of each pixel\n * intensity: The degree to which the specific color replaces the normal image color (0.0 - 1.0, with 1.0 as the default)\n * color: The color to use as the basis for the effect, with (0.6, 0.45, 0.3, 1.0) as the default.\n */\npublic class GPUImageMonochromeFilter extends GPUImageFilter {\n    public static final String MONOCHROME_FRAGMENT_SHADER = \"\" +\n            \" precision lowp float;\\n\" +\n            \"  \\n\" +\n            \"  varying highp vec2 textureCoordinate;\\n\" +\n            \"  \\n\" +\n            \"  uniform sampler2D inputImageTexture;\\n\" +\n            \"  uniform float intensity;\\n\" +\n            \"  uniform vec3 filterColor;\\n\" +\n            \"  \\n\" +\n            \"  const mediump vec3 luminanceWeighting = vec3(0.2125, 0.7154, 0.0721);\\n\" +\n            \"  \\n\" +\n            \"  void main()\\n\" +\n            \"  {\\n\" +\n            \" \t//desat, then apply overlay blend\\n\" +\n            \" \tlowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \" \tfloat luminance = dot(textureColor.rgb, luminanceWeighting);\\n\" +\n            \" \t\\n\" +\n            \" \tlowp vec4 desat = vec4(vec3(luminance), 1.0);\\n\" +\n            \" \t\\n\" +\n            \" \t//overlay\\n\" +\n            \" \tlowp vec4 outputColor = vec4(\\n\" +\n            \"                                  (desat.r < 0.5 ? (2.0 * desat.r * filterColor.r) : (1.0 - 2.0 * (1.0 - desat.r) * (1.0 - filterColor.r))),\\n\" +\n            \"                                  (desat.g < 0.5 ? (2.0 * desat.g * filterColor.g) : (1.0 - 2.0 * (1.0 - desat.g) * (1.0 - filterColor.g))),\\n\" +\n            \"                                  (desat.b < 0.5 ? (2.0 * desat.b * filterColor.b) : (1.0 - 2.0 * (1.0 - desat.b) * (1.0 - filterColor.b))),\\n\" +\n            \"                                  1.0\\n\" +\n            \"                                  );\\n\" +\n            \" \t\\n\" +\n            \" \t//which is better, or are they equal?\\n\" +\n            \" \tgl_FragColor = vec4( mix(textureColor.rgb, outputColor.rgb, intensity), textureColor.a);\\n\" +\n            \"  }\";\n\n    private int intensityLocation;\n    private float intensity;\n    private int filterColorLocation;\n    private float[] color;\n\n    public GPUImageMonochromeFilter() {\n        this(1.0f, new float[]{0.6f, 0.45f, 0.3f, 1.0f});\n    }\n\n    public GPUImageMonochromeFilter(final float intensity, final float[] color) {\n        super(NO_FILTER_VERTEX_SHADER, MONOCHROME_FRAGMENT_SHADER);\n        this.intensity = intensity;\n        this.color = color;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        intensityLocation = GLES20.glGetUniformLocation(getProgram(), \"intensity\");\n        filterColorLocation = GLES20.glGetUniformLocation(getProgram(), \"filterColor\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setIntensity(1.0f);\n        setColor(new float[]{0.6f, 0.45f, 0.3f, 1.f});\n    }\n\n    public void setIntensity(final float intensity) {\n        this.intensity = intensity;\n        setFloat(intensityLocation, this.intensity);\n    }\n\n    public void setColor(final float[] color) {\n        this.color = color;\n        setColor(this.color[0], this.color[1], this.color[2]);\n\n    }\n\n    public void setColor(final float red, final float green, final float blue) {\n        setFloatVec3(filterColorLocation, new float[]{red, green, blue});\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageMultiplyBlendFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\npublic class GPUImageMultiplyBlendFilter extends GPUImageTwoInputFilter {\n    public static final String MULTIPLY_BLEND_FRAGMENT_SHADER = \"varying highp vec2 textureCoordinate;\\n\" +\n            \" varying highp vec2 textureCoordinate2;\\n\" +\n            \"\\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform sampler2D inputImageTexture2;\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"     lowp vec4 base = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"     lowp vec4 overlayer = texture2D(inputImageTexture2, textureCoordinate2);\\n\" +\n            \"          \\n\" +\n            \"     gl_FragColor = overlayer * base + overlayer * (1.0 - base.a) + base * (1.0 - overlayer.a);\\n\" +\n            \" }\";\n\n    public GPUImageMultiplyBlendFilter() {\n        super(MULTIPLY_BLEND_FRAGMENT_SHADER);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageNonMaximumSuppressionFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\npublic class GPUImageNonMaximumSuppressionFilter extends GPUImage3x3TextureSamplingFilter {\n    public static final String NMS_FRAGMENT_SHADER = \"\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"\\n\" +\n            \"varying highp vec2 textureCoordinate;\\n\" +\n            \"varying highp vec2 leftTextureCoordinate;\\n\" +\n            \"varying highp vec2 rightTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"varying highp vec2 topTextureCoordinate;\\n\" +\n            \"varying highp vec2 topLeftTextureCoordinate;\\n\" +\n            \"varying highp vec2 topRightTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"varying highp vec2 bottomTextureCoordinate;\\n\" +\n            \"varying highp vec2 bottomLeftTextureCoordinate;\\n\" +\n            \"varying highp vec2 bottomRightTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"lowp float bottomColor = texture2D(inputImageTexture, bottomTextureCoordinate).r;\\n\" +\n            \"lowp float bottomLeftColor = texture2D(inputImageTexture, bottomLeftTextureCoordinate).r;\\n\" +\n            \"lowp float bottomRightColor = texture2D(inputImageTexture, bottomRightTextureCoordinate).r;\\n\" +\n            \"lowp vec4 centerColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"lowp float leftColor = texture2D(inputImageTexture, leftTextureCoordinate).r;\\n\" +\n            \"lowp float rightColor = texture2D(inputImageTexture, rightTextureCoordinate).r;\\n\" +\n            \"lowp float topColor = texture2D(inputImageTexture, topTextureCoordinate).r;\\n\" +\n            \"lowp float topRightColor = texture2D(inputImageTexture, topRightTextureCoordinate).r;\\n\" +\n            \"lowp float topLeftColor = texture2D(inputImageTexture, topLeftTextureCoordinate).r;\\n\" +\n            \"\\n\" +\n            \"// Use a tiebreaker for pixels to the left and immediately above this one\\n\" +\n            \"lowp float multiplier = 1.0 - step(centerColor.r, topColor);\\n\" +\n            \"multiplier = multiplier * 1.0 - step(centerColor.r, topLeftColor);\\n\" +\n            \"multiplier = multiplier * 1.0 - step(centerColor.r, leftColor);\\n\" +\n            \"multiplier = multiplier * 1.0 - step(centerColor.r, bottomLeftColor);\\n\" +\n            \"\\n\" +\n            \"lowp float maxValue = max(centerColor.r, bottomColor);\\n\" +\n            \"maxValue = max(maxValue, bottomRightColor);\\n\" +\n            \"maxValue = max(maxValue, rightColor);\\n\" +\n            \"maxValue = max(maxValue, topRightColor);\\n\" +\n            \"\\n\" +\n            \"gl_FragColor = vec4((centerColor.rgb * step(maxValue, centerColor.r) * multiplier), 1.0);\\n\" +\n            \"}\\n\";\n\n    public GPUImageNonMaximumSuppressionFilter() {\n        super(NMS_FRAGMENT_SHADER);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageNormalBlendFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\n/**\n * 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.\n * <p>\n * D = C1 * C1a + C2 * C2a * (1 - C1a)\n * 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:\n * <p>\n * Da = C1a + C2a * (1 - C1a)\n * The resultant color is premultiplied with the alpha. To restore the color to the unmultiplied values, just divide by Da, the resultant alpha.\n * <p>\n * http://stackoverflow.com/questions/1724946/blend-mode-on-a-transparent-and-semi-transparent-background\n * <p>\n * For some reason Photoshop behaves\n * D = C1 + C2 * C2a * (1 - C1a)\n */\npublic class GPUImageNormalBlendFilter extends GPUImageTwoInputFilter {\n    public static final String NORMAL_BLEND_FRAGMENT_SHADER = \"varying highp vec2 textureCoordinate;\\n\" +\n            \" varying highp vec2 textureCoordinate2;\\n\" +\n            \" \\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform sampler2D inputImageTexture2;\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"     lowp vec4 c2 = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"\\t lowp vec4 c1 = texture2D(inputImageTexture2, textureCoordinate2);\\n\" +\n            \"     \\n\" +\n            \"     lowp vec4 outputColor;\\n\" +\n            \"     \\n\" +\n            \"     outputColor.r = c1.r + c2.r * c2.a * (1.0 - c1.a);\\n\" +\n            \"\\n\" +\n            \"     outputColor.g = c1.g + c2.g * c2.a * (1.0 - c1.a);\\n\" +\n            \"     \\n\" +\n            \"     outputColor.b = c1.b + c2.b * c2.a * (1.0 - c1.a);\\n\" +\n            \"     \\n\" +\n            \"     outputColor.a = c1.a + c2.a * (1.0 - c1.a);\\n\" +\n            \"     \\n\" +\n            \"     gl_FragColor = outputColor;\\n\" +\n            \" }\";\n\n    public GPUImageNormalBlendFilter() {\n        super(NORMAL_BLEND_FRAGMENT_SHADER);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageOpacityFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\n/**\n * Adjusts the alpha channel of the incoming image\n * opacity: The value to multiply the incoming alpha channel for each pixel by (0.0 - 1.0, with 1.0 as the default)\n */\npublic class GPUImageOpacityFilter extends GPUImageFilter {\n    public static final String OPACITY_FRAGMENT_SHADER = \"\" +\n            \"  varying highp vec2 textureCoordinate;\\n\" +\n            \"  \\n\" +\n            \"  uniform sampler2D inputImageTexture;\\n\" +\n            \"  uniform lowp float opacity;\\n\" +\n            \"  \\n\" +\n            \"  void main()\\n\" +\n            \"  {\\n\" +\n            \"      lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"      \\n\" +\n            \"      gl_FragColor = vec4(textureColor.rgb, textureColor.a * opacity);\\n\" +\n            \"  }\\n\";\n\n    private int opacityLocation;\n    private float opacity;\n\n    public GPUImageOpacityFilter() {\n        this(1.0f);\n    }\n\n    public GPUImageOpacityFilter(final float opacity) {\n        super(NO_FILTER_VERTEX_SHADER, OPACITY_FRAGMENT_SHADER);\n        this.opacity = opacity;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        opacityLocation = GLES20.glGetUniformLocation(getProgram(), \"opacity\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setOpacity(opacity);\n    }\n\n    public void setOpacity(final float opacity) {\n        this.opacity = opacity;\n        setFloat(opacityLocation, this.opacity);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageOverlayBlendFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\npublic class GPUImageOverlayBlendFilter extends GPUImageTwoInputFilter {\n    public static final String OVERLAY_BLEND_FRAGMENT_SHADER = \"varying highp vec2 textureCoordinate;\\n\" +\n            \" varying highp vec2 textureCoordinate2;\\n\" +\n            \"\\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform sampler2D inputImageTexture2;\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"     mediump vec4 base = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"     mediump vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);\\n\" +\n            \"     \\n\" +\n            \"     mediump float ra;\\n\" +\n            \"     if (2.0 * base.r < base.a) {\\n\" +\n            \"         ra = 2.0 * overlay.r * base.r + overlay.r * (1.0 - base.a) + base.r * (1.0 - overlay.a);\\n\" +\n            \"     } else {\\n\" +\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\" +\n            \"     \\n\" +\n            \"     mediump float ga;\\n\" +\n            \"     if (2.0 * base.g < base.a) {\\n\" +\n            \"         ga = 2.0 * overlay.g * base.g + overlay.g * (1.0 - base.a) + base.g * (1.0 - overlay.a);\\n\" +\n            \"     } else {\\n\" +\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\" +\n            \"     \\n\" +\n            \"     mediump float ba;\\n\" +\n            \"     if (2.0 * base.b < base.a) {\\n\" +\n            \"         ba = 2.0 * overlay.b * base.b + overlay.b * (1.0 - base.a) + base.b * (1.0 - overlay.a);\\n\" +\n            \"     } else {\\n\" +\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\" +\n            \"     \\n\" +\n            \"     gl_FragColor = vec4(ra, ga, ba, 1.0);\\n\" +\n            \" }\";\n\n    public GPUImageOverlayBlendFilter() {\n        super(OVERLAY_BLEND_FRAGMENT_SHADER);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImagePixelationFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\n/**\n * Applies a grayscale effect to the image.\n */\npublic class GPUImagePixelationFilter extends GPUImageFilter {\n    public static final String PIXELATION_FRAGMENT_SHADER = \"\" +\n            \"precision highp float;\\n\" +\n\n            \"varying vec2 textureCoordinate;\\n\" +\n\n            \"uniform float imageWidthFactor;\\n\" +\n            \"uniform float imageHeightFactor;\\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"uniform float pixel;\\n\" +\n\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"  vec2 uv  = textureCoordinate.xy;\\n\" +\n            \"  float dx = pixel * imageWidthFactor;\\n\" +\n            \"  float dy = pixel * imageHeightFactor;\\n\" +\n            \"  vec2 coord = vec2(dx * floor(uv.x / dx), dy * floor(uv.y / dy));\\n\" +\n            \"  vec3 tc = texture2D(inputImageTexture, coord).xyz;\\n\" +\n            \"  gl_FragColor = vec4(tc, 1.0);\\n\" +\n            \"}\";\n\n    private int imageWidthFactorLocation;\n    private int imageHeightFactorLocation;\n    private float pixel;\n    private int pixelLocation;\n\n    public GPUImagePixelationFilter() {\n        super(NO_FILTER_VERTEX_SHADER, PIXELATION_FRAGMENT_SHADER);\n        pixel = 1.0f;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        imageWidthFactorLocation = GLES20.glGetUniformLocation(getProgram(), \"imageWidthFactor\");\n        imageHeightFactorLocation = GLES20.glGetUniformLocation(getProgram(), \"imageHeightFactor\");\n        pixelLocation = GLES20.glGetUniformLocation(getProgram(), \"pixel\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setPixel(pixel);\n    }\n\n    @Override\n    public void onOutputSizeChanged(final int width, final int height) {\n        super.onOutputSizeChanged(width, height);\n        setFloat(imageWidthFactorLocation, 1.0f / width);\n        setFloat(imageHeightFactorLocation, 1.0f / height);\n    }\n\n    public void setPixel(final float pixel) {\n        this.pixel = pixel;\n        setFloat(pixelLocation, this.pixel);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImagePosterizeFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\n/**\n * Reduces the color range of the image. <br>\n * <br>\n * colorLevels: ranges from 1 to 256, with a default of 10\n */\npublic class GPUImagePosterizeFilter extends GPUImageFilter {\n    public static final String POSTERIZE_FRAGMENT_SHADER = \"\" +\n            \"varying highp vec2 textureCoordinate;\\n\" +\n            \"\\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"uniform highp float colorLevels;\\n\" +\n            \"\\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"   highp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"   \\n\" +\n            \"   gl_FragColor = floor((textureColor * colorLevels) + vec4(0.5)) / colorLevels;\\n\" +\n            \"}\";\n\n    private int glUniformColorLevels;\n    private int colorLevels;\n\n    public GPUImagePosterizeFilter() {\n        this(10);\n    }\n\n    public GPUImagePosterizeFilter(final int colorLevels) {\n        super(GPUImageFilter.NO_FILTER_VERTEX_SHADER, POSTERIZE_FRAGMENT_SHADER);\n        this.colorLevels = colorLevels;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        glUniformColorLevels = GLES20.glGetUniformLocation(getProgram(), \"colorLevels\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setColorLevels(colorLevels);\n    }\n\n    public void setColorLevels(final int colorLevels) {\n        this.colorLevels = colorLevels;\n        setFloat(glUniformColorLevels, colorLevels);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageRGBDilationFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\n/**\n * For each pixel, this sets it to the maximum value of each color channel in a rectangular neighborhood extending\n * out dilationRadius pixels from the center.\n * This extends out brighter colors, and can be used for abstraction of color images.\n */\npublic class GPUImageRGBDilationFilter extends GPUImageTwoPassTextureSamplingFilter {\n    public static final String VERTEX_SHADER_1 =\n            \"attribute vec4 position;\\n\" +\n                    \"attribute vec2 inputTextureCoordinate;\\n\" +\n                    \"\\n\" +\n                    \"uniform float texelWidthOffset; \\n\" +\n                    \"uniform float texelHeightOffset; \\n\" +\n                    \"\\n\" +\n                    \"varying vec2 centerTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepNegativeTextureCoordinate;\\n\" +\n                    \"\\n\" +\n                    \"void main()\\n\" +\n                    \"{\\n\" +\n                    \"gl_Position = position;\\n\" +\n                    \"\\n\" +\n                    \"vec2 offset = vec2(texelWidthOffset, texelHeightOffset);\\n\" +\n                    \"\\n\" +\n                    \"centerTextureCoordinate = inputTextureCoordinate;\\n\" +\n                    \"oneStepNegativeTextureCoordinate = inputTextureCoordinate - offset;\\n\" +\n                    \"oneStepPositiveTextureCoordinate = inputTextureCoordinate + offset;\\n\" +\n                    \"}\\n\";\n\n    public static final String VERTEX_SHADER_2 =\n            \"attribute vec4 position;\\n\" +\n                    \"attribute vec2 inputTextureCoordinate;\\n\" +\n                    \"\\n\" +\n                    \"uniform float texelWidthOffset;\\n\" +\n                    \"uniform float texelHeightOffset;\\n\" +\n                    \"\\n\" +\n                    \"varying vec2 centerTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepNegativeTextureCoordinate;\\n\" +\n                    \"varying vec2 twoStepsPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 twoStepsNegativeTextureCoordinate;\\n\" +\n                    \"\\n\" +\n                    \"void main()\\n\" +\n                    \"{\\n\" +\n                    \"gl_Position = position;\\n\" +\n                    \"\\n\" +\n                    \"vec2 offset = vec2(texelWidthOffset, texelHeightOffset);\\n\" +\n                    \"\\n\" +\n                    \"centerTextureCoordinate = inputTextureCoordinate;\\n\" +\n                    \"oneStepNegativeTextureCoordinate = inputTextureCoordinate - offset;\\n\" +\n                    \"oneStepPositiveTextureCoordinate = inputTextureCoordinate + offset;\\n\" +\n                    \"twoStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 2.0);\\n\" +\n                    \"twoStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 2.0);\\n\" +\n                    \"}\\n\";\n\n    public static final String VERTEX_SHADER_3 =\n            \"attribute vec4 position;\\n\" +\n                    \"attribute vec2 inputTextureCoordinate;\\n\" +\n                    \"\\n\" +\n                    \"uniform float texelWidthOffset;\\n\" +\n                    \"uniform float texelHeightOffset;\\n\" +\n                    \"\\n\" +\n                    \"varying vec2 centerTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepNegativeTextureCoordinate;\\n\" +\n                    \"varying vec2 twoStepsPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 twoStepsNegativeTextureCoordinate;\\n\" +\n                    \"varying vec2 threeStepsPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 threeStepsNegativeTextureCoordinate;\\n\" +\n                    \"\\n\" +\n                    \"void main()\\n\" +\n                    \"{\\n\" +\n                    \"gl_Position = position;\\n\" +\n                    \"\\n\" +\n                    \"vec2 offset = vec2(texelWidthOffset, texelHeightOffset);\\n\" +\n                    \"\\n\" +\n                    \"centerTextureCoordinate = inputTextureCoordinate;\\n\" +\n                    \"oneStepNegativeTextureCoordinate = inputTextureCoordinate - offset;\\n\" +\n                    \"oneStepPositiveTextureCoordinate = inputTextureCoordinate + offset;\\n\" +\n                    \"twoStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 2.0);\\n\" +\n                    \"twoStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 2.0);\\n\" +\n                    \"threeStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 3.0);\\n\" +\n                    \"threeStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 3.0);\\n\" +\n                    \"}\\n\";\n\n    public static final String VERTEX_SHADER_4 =\n            \"attribute vec4 position;\\n\" +\n                    \"attribute vec2 inputTextureCoordinate;\\n\" +\n                    \"\\n\" +\n                    \"uniform float texelWidthOffset;\\n\" +\n                    \"uniform float texelHeightOffset;\\n\" +\n                    \"\\n\" +\n                    \"varying vec2 centerTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepNegativeTextureCoordinate;\\n\" +\n                    \"varying vec2 twoStepsPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 twoStepsNegativeTextureCoordinate;\\n\" +\n                    \"varying vec2 threeStepsPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 threeStepsNegativeTextureCoordinate;\\n\" +\n                    \"varying vec2 fourStepsPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 fourStepsNegativeTextureCoordinate;\\n\" +\n                    \"\\n\" +\n                    \"void main()\\n\" +\n                    \"{\\n\" +\n                    \"gl_Position = position;\\n\" +\n                    \"\\n\" +\n                    \"vec2 offset = vec2(texelWidthOffset, texelHeightOffset);\\n\" +\n                    \"\\n\" +\n                    \"centerTextureCoordinate = inputTextureCoordinate;\\n\" +\n                    \"oneStepNegativeTextureCoordinate = inputTextureCoordinate - offset;\\n\" +\n                    \"oneStepPositiveTextureCoordinate = inputTextureCoordinate + offset;\\n\" +\n                    \"twoStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 2.0);\\n\" +\n                    \"twoStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 2.0);\\n\" +\n                    \"threeStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 3.0);\\n\" +\n                    \"threeStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 3.0);\\n\" +\n                    \"fourStepsNegativeTextureCoordinate = inputTextureCoordinate - (offset * 4.0);\\n\" +\n                    \"fourStepsPositiveTextureCoordinate = inputTextureCoordinate + (offset * 4.0);\\n\" +\n                    \"}\\n\";\n\n\n    public static final String FRAGMENT_SHADER_1 =\n            \"precision highp float;\\n\" +\n                    \"\\n\" +\n                    \"varying vec2 centerTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepNegativeTextureCoordinate;\\n\" +\n                    \"\\n\" +\n                    \"uniform sampler2D inputImageTexture;\\n\" +\n                    \"\\n\" +\n                    \"void main()\\n\" +\n                    \"{\\n\" +\n                    \"lowp vec4 centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate);\\n\" +\n                    \"lowp vec4 oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate);\\n\" +\n                    \"lowp vec4 oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate);\\n\" +\n                    \"\\n\" +\n                    \"lowp vec4 maxValue = max(centerIntensity, oneStepPositiveIntensity);\\n\" +\n                    \"\\n\" +\n                    \"gl_FragColor = max(maxValue, oneStepNegativeIntensity);\\n\" +\n                    \"}\\n\";\n\n    public static final String FRAGMENT_SHADER_2 =\n            \"precision highp float;\\n\" +\n                    \"\\n\" +\n                    \"varying vec2 centerTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepNegativeTextureCoordinate;\\n\" +\n                    \"varying vec2 twoStepsPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 twoStepsNegativeTextureCoordinate;\\n\" +\n                    \"\\n\" +\n                    \"uniform sampler2D inputImageTexture;\\n\" +\n                    \"\\n\" +\n                    \"void main()\\n\" +\n                    \"{\\n\" +\n                    \"lowp vec4 centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate);\\n\" +\n                    \"lowp vec4 oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate);\\n\" +\n                    \"lowp vec4 oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate);\\n\" +\n                    \"lowp vec4 twoStepsPositiveIntensity = texture2D(inputImageTexture, twoStepsPositiveTextureCoordinate);\\n\" +\n                    \"lowp vec4 twoStepsNegativeIntensity = texture2D(inputImageTexture, twoStepsNegativeTextureCoordinate);\\n\" +\n                    \"\\n\" +\n                    \"lowp vec4 maxValue = max(centerIntensity, oneStepPositiveIntensity);\\n\" +\n                    \"maxValue = max(maxValue, oneStepNegativeIntensity);\\n\" +\n                    \"maxValue = max(maxValue, twoStepsPositiveIntensity);\\n\" +\n                    \"maxValue = max(maxValue, twoStepsNegativeIntensity);\\n\" +\n                    \"\\n\" +\n                    \"gl_FragColor = max(maxValue, twoStepsNegativeIntensity);\\n\" +\n                    \"}\\n\";\n\n    public static final String FRAGMENT_SHADER_3 =\n            \"precision highp float;\\n\" +\n                    \"\\n\" +\n                    \"varying vec2 centerTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepNegativeTextureCoordinate;\\n\" +\n                    \"varying vec2 twoStepsPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 twoStepsNegativeTextureCoordinate;\\n\" +\n                    \"varying vec2 threeStepsPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 threeStepsNegativeTextureCoordinate;\\n\" +\n                    \"\\n\" +\n                    \"uniform sampler2D inputImageTexture;\\n\" +\n                    \"\\n\" +\n                    \"void main()\\n\" +\n                    \"{\\n\" +\n                    \"lowp vec4 centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate);\\n\" +\n                    \"lowp vec4 oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate);\\n\" +\n                    \"lowp vec4 oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate);\\n\" +\n                    \"lowp vec4 twoStepsPositiveIntensity = texture2D(inputImageTexture, twoStepsPositiveTextureCoordinate);\\n\" +\n                    \"lowp vec4 twoStepsNegativeIntensity = texture2D(inputImageTexture, twoStepsNegativeTextureCoordinate);\\n\" +\n                    \"lowp vec4 threeStepsPositiveIntensity = texture2D(inputImageTexture, threeStepsPositiveTextureCoordinate);\\n\" +\n                    \"lowp vec4 threeStepsNegativeIntensity = texture2D(inputImageTexture, threeStepsNegativeTextureCoordinate);\\n\" +\n                    \"\\n\" +\n                    \"lowp vec4 maxValue = max(centerIntensity, oneStepPositiveIntensity);\\n\" +\n                    \"maxValue = max(maxValue, oneStepNegativeIntensity);\\n\" +\n                    \"maxValue = max(maxValue, twoStepsPositiveIntensity);\\n\" +\n                    \"maxValue = max(maxValue, twoStepsNegativeIntensity);\\n\" +\n                    \"maxValue = max(maxValue, threeStepsPositiveIntensity);\\n\" +\n                    \"\\n\" +\n                    \"gl_FragColor = max(maxValue, threeStepsNegativeIntensity);\\n\" +\n                    \"}\\n\";\n\n    public static final String FRAGMENT_SHADER_4 =\n            \"precision highp float;\\n\" +\n                    \"\\n\" +\n                    \"varying vec2 centerTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 oneStepNegativeTextureCoordinate;\\n\" +\n                    \"varying vec2 twoStepsPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 twoStepsNegativeTextureCoordinate;\\n\" +\n                    \"varying vec2 threeStepsPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 threeStepsNegativeTextureCoordinate;\\n\" +\n                    \"varying vec2 fourStepsPositiveTextureCoordinate;\\n\" +\n                    \"varying vec2 fourStepsNegativeTextureCoordinate;\\n\" +\n                    \"\\n\" +\n                    \"uniform sampler2D inputImageTexture;\\n\" +\n                    \"\\n\" +\n                    \"void main()\\n\" +\n                    \"{\\n\" +\n                    \"lowp vec4 centerIntensity = texture2D(inputImageTexture, centerTextureCoordinate);\\n\" +\n                    \"lowp vec4 oneStepPositiveIntensity = texture2D(inputImageTexture, oneStepPositiveTextureCoordinate);\\n\" +\n                    \"lowp vec4 oneStepNegativeIntensity = texture2D(inputImageTexture, oneStepNegativeTextureCoordinate);\\n\" +\n                    \"lowp vec4 twoStepsPositiveIntensity = texture2D(inputImageTexture, twoStepsPositiveTextureCoordinate);\\n\" +\n                    \"lowp vec4 twoStepsNegativeIntensity = texture2D(inputImageTexture, twoStepsNegativeTextureCoordinate);\\n\" +\n                    \"lowp vec4 threeStepsPositiveIntensity = texture2D(inputImageTexture, threeStepsPositiveTextureCoordinate);\\n\" +\n                    \"lowp vec4 threeStepsNegativeIntensity = texture2D(inputImageTexture, threeStepsNegativeTextureCoordinate);\\n\" +\n                    \"lowp vec4 fourStepsPositiveIntensity = texture2D(inputImageTexture, fourStepsPositiveTextureCoordinate);\\n\" +\n                    \"lowp vec4 fourStepsNegativeIntensity = texture2D(inputImageTexture, fourStepsNegativeTextureCoordinate);\\n\" +\n                    \"\\n\" +\n                    \"lowp vec4 maxValue = max(centerIntensity, oneStepPositiveIntensity);\\n\" +\n                    \"maxValue = max(maxValue, oneStepNegativeIntensity);\\n\" +\n                    \"maxValue = max(maxValue, twoStepsPositiveIntensity);\\n\" +\n                    \"maxValue = max(maxValue, twoStepsNegativeIntensity);\\n\" +\n                    \"maxValue = max(maxValue, threeStepsPositiveIntensity);\\n\" +\n                    \"maxValue = max(maxValue, threeStepsNegativeIntensity);\\n\" +\n                    \"maxValue = max(maxValue, fourStepsPositiveIntensity);\\n\" +\n                    \"\\n\" +\n                    \"gl_FragColor = max(maxValue, fourStepsNegativeIntensity);\\n\" +\n                    \"}\\n\";\n\n\n    public GPUImageRGBDilationFilter() {\n        this(1);\n    }\n\n    /**\n     * Acceptable values for dilationRadius, which sets the distance in pixels to sample out\n     * from the center, are 1, 2, 3, and 4.\n     *\n     * @param radius 1, 2, 3 or 4\n     */\n    public GPUImageRGBDilationFilter(int radius) {\n        this(getVertexShader(radius), getFragmentShader(radius));\n    }\n\n    private GPUImageRGBDilationFilter(String vertexShader, String fragmentShader) {\n        super(vertexShader, fragmentShader, vertexShader, fragmentShader);\n    }\n\n    private static String getVertexShader(int radius) {\n        switch (radius) {\n            case 0:\n            case 1:\n                return VERTEX_SHADER_1;\n            case 2:\n                return VERTEX_SHADER_2;\n            case 3:\n                return VERTEX_SHADER_3;\n            default:\n                return VERTEX_SHADER_4;\n        }\n    }\n\n    private static String getFragmentShader(int radius) {\n        switch (radius) {\n            case 0:\n            case 1:\n                return FRAGMENT_SHADER_1;\n            case 2:\n                return FRAGMENT_SHADER_2;\n            case 3:\n                return FRAGMENT_SHADER_3;\n            default:\n                return FRAGMENT_SHADER_4;\n        }\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageRGBFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\n/**\n * Adjusts the individual RGB channels of an image\n * red: Normalized values by which each color channel is multiplied. The range is from 0.0 up, with 1.0 as the default.\n * green:\n * blue:\n */\npublic class GPUImageRGBFilter extends GPUImageFilter {\n    public static final String RGB_FRAGMENT_SHADER = \"\" +\n            \"  varying highp vec2 textureCoordinate;\\n\" +\n            \"  \\n\" +\n            \"  uniform sampler2D inputImageTexture;\\n\" +\n            \"  uniform highp float red;\\n\" +\n            \"  uniform highp float green;\\n\" +\n            \"  uniform highp float blue;\\n\" +\n            \"  \\n\" +\n            \"  void main()\\n\" +\n            \"  {\\n\" +\n            \"      highp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"      \\n\" +\n            \"      gl_FragColor = vec4(textureColor.r * red, textureColor.g * green, textureColor.b * blue, 1.0);\\n\" +\n            \"  }\\n\";\n\n    private int redLocation;\n    private float red;\n    private int greenLocation;\n    private float green;\n    private int blueLocation;\n    private float blue;\n\n    public GPUImageRGBFilter() {\n        this(1.0f, 1.0f, 1.0f);\n    }\n\n    public GPUImageRGBFilter(final float red, final float green, final float blue) {\n        super(NO_FILTER_VERTEX_SHADER, RGB_FRAGMENT_SHADER);\n        this.red = red;\n        this.green = green;\n        this.blue = blue;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        redLocation = GLES20.glGetUniformLocation(getProgram(), \"red\");\n        greenLocation = GLES20.glGetUniformLocation(getProgram(), \"green\");\n        blueLocation = GLES20.glGetUniformLocation(getProgram(), \"blue\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setRed(red);\n        setGreen(green);\n        setBlue(blue);\n    }\n\n    public void setRed(final float red) {\n        this.red = red;\n        setFloat(redLocation, this.red);\n    }\n\n    public void setGreen(final float green) {\n        this.green = green;\n        setFloat(greenLocation, this.green);\n    }\n\n    public void setBlue(final float blue) {\n        this.blue = blue;\n        setFloat(blueLocation, this.blue);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageSaturationBlendFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\npublic class GPUImageSaturationBlendFilter extends GPUImageTwoInputFilter {\n    public static final String SATURATION_BLEND_FRAGMENT_SHADER = \"varying highp vec2 textureCoordinate;\\n\" +\n            \" varying highp vec2 textureCoordinate2;\\n\" +\n            \" \\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform sampler2D inputImageTexture2;\\n\" +\n            \" \\n\" +\n            \" highp float lum(lowp vec3 c) {\\n\" +\n            \"     return dot(c, vec3(0.3, 0.59, 0.11));\\n\" +\n            \" }\\n\" +\n            \" \\n\" +\n            \" lowp vec3 clipcolor(lowp vec3 c) {\\n\" +\n            \"     highp float l = lum(c);\\n\" +\n            \"     lowp float n = min(min(c.r, c.g), c.b);\\n\" +\n            \"     lowp float x = max(max(c.r, c.g), c.b);\\n\" +\n            \"     \\n\" +\n            \"     if (n < 0.0) {\\n\" +\n            \"         c.r = l + ((c.r - l) * l) / (l - n);\\n\" +\n            \"         c.g = l + ((c.g - l) * l) / (l - n);\\n\" +\n            \"         c.b = l + ((c.b - l) * l) / (l - n);\\n\" +\n            \"     }\\n\" +\n            \"     if (x > 1.0) {\\n\" +\n            \"         c.r = l + ((c.r - l) * (1.0 - l)) / (x - l);\\n\" +\n            \"         c.g = l + ((c.g - l) * (1.0 - l)) / (x - l);\\n\" +\n            \"         c.b = l + ((c.b - l) * (1.0 - l)) / (x - l);\\n\" +\n            \"     }\\n\" +\n            \"     \\n\" +\n            \"     return c;\\n\" +\n            \" }\\n\" +\n            \" \\n\" +\n            \" lowp vec3 setlum(lowp vec3 c, highp float l) {\\n\" +\n            \"     highp float d = l - lum(c);\\n\" +\n            \"     c = c + vec3(d);\\n\" +\n            \"     return clipcolor(c);\\n\" +\n            \" }\\n\" +\n            \" \\n\" +\n            \" highp float sat(lowp vec3 c) {\\n\" +\n            \"     lowp float n = min(min(c.r, c.g), c.b);\\n\" +\n            \"     lowp float x = max(max(c.r, c.g), c.b);\\n\" +\n            \"     return x - n;\\n\" +\n            \" }\\n\" +\n            \" \\n\" +\n            \" lowp float mid(lowp float cmin, lowp float cmid, lowp float cmax, highp float s) {\\n\" +\n            \"     return ((cmid - cmin) * s) / (cmax - cmin);\\n\" +\n            \" }\\n\" +\n            \" \\n\" +\n            \" lowp vec3 setsat(lowp vec3 c, highp float s) {\\n\" +\n            \"     if (c.r > c.g) {\\n\" +\n            \"         if (c.r > c.b) {\\n\" +\n            \"             if (c.g > c.b) {\\n\" +\n            \"                 /* g is mid, b is min */\\n\" +\n            \"                 c.g = mid(c.b, c.g, c.r, s);\\n\" +\n            \"                 c.b = 0.0;\\n\" +\n            \"             } else {\\n\" +\n            \"                 /* b is mid, g is min */\\n\" +\n            \"                 c.b = mid(c.g, c.b, c.r, s);\\n\" +\n            \"                 c.g = 0.0;\\n\" +\n            \"             }\\n\" +\n            \"             c.r = s;\\n\" +\n            \"         } else {\\n\" +\n            \"             /* b is max, r is mid, g is min */\\n\" +\n            \"             c.r = mid(c.g, c.r, c.b, s);\\n\" +\n            \"             c.b = s;\\n\" +\n            \"             c.r = 0.0;\\n\" +\n            \"         }\\n\" +\n            \"     } else if (c.r > c.b) {\\n\" +\n            \"         /* g is max, r is mid, b is min */\\n\" +\n            \"         c.r = mid(c.b, c.r, c.g, s);\\n\" +\n            \"         c.g = s;\\n\" +\n            \"         c.b = 0.0;\\n\" +\n            \"     } else if (c.g > c.b) {\\n\" +\n            \"         /* g is max, b is mid, r is min */\\n\" +\n            \"         c.b = mid(c.r, c.b, c.g, s);\\n\" +\n            \"         c.g = s;\\n\" +\n            \"         c.r = 0.0;\\n\" +\n            \"     } else if (c.b > c.g) {\\n\" +\n            \"         /* b is max, g is mid, r is min */\\n\" +\n            \"         c.g = mid(c.r, c.g, c.b, s);\\n\" +\n            \"         c.b = s;\\n\" +\n            \"         c.r = 0.0;\\n\" +\n            \"     } else {\\n\" +\n            \"         c = vec3(0.0);\\n\" +\n            \"     }\\n\" +\n            \"     return c;\\n\" +\n            \" }\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"   highp vec4 baseColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"   highp vec4 overlayColor = texture2D(inputImageTexture2, textureCoordinate2);\\n\" +\n            \"     \\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\" +\n            \" }\";\n\n    public GPUImageSaturationBlendFilter() {\n        super(SATURATION_BLEND_FRAGMENT_SHADER);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageSaturationFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\n/**\n * saturation: The degree of saturation or desaturation to apply to the image (0.0 - 2.0, with 1.0 as the default)\n */\npublic class GPUImageSaturationFilter extends GPUImageFilter {\n    public static final String SATURATION_FRAGMENT_SHADER = \"\" +\n            \" varying highp vec2 textureCoordinate;\\n\" +\n            \" \\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform lowp float saturation;\\n\" +\n            \" \\n\" +\n            \" // Values from \\\"Graphics Shaders: Theory and Practice\\\" by Bailey and Cunningham\\n\" +\n            \" const mediump vec3 luminanceWeighting = vec3(0.2125, 0.7154, 0.0721);\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"    lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"    lowp float luminance = dot(textureColor.rgb, luminanceWeighting);\\n\" +\n            \"    lowp vec3 greyScaleColor = vec3(luminance);\\n\" +\n            \"    \\n\" +\n            \"    gl_FragColor = vec4(mix(greyScaleColor, textureColor.rgb, saturation), textureColor.w);\\n\" +\n            \"     \\n\" +\n            \" }\";\n\n    private int saturationLocation;\n    private float saturation;\n\n    public GPUImageSaturationFilter() {\n        this(1.0f);\n    }\n\n    public GPUImageSaturationFilter(final float saturation) {\n        super(NO_FILTER_VERTEX_SHADER, SATURATION_FRAGMENT_SHADER);\n        this.saturation = saturation;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        saturationLocation = GLES20.glGetUniformLocation(getProgram(), \"saturation\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setSaturation(saturation);\n    }\n\n    public void setSaturation(final float saturation) {\n        this.saturation = saturation;\n        setFloat(saturationLocation, this.saturation);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageScreenBlendFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\npublic class GPUImageScreenBlendFilter extends GPUImageTwoInputFilter {\n    public static final String SCREEN_BLEND_FRAGMENT_SHADER = \"varying highp vec2 textureCoordinate;\\n\" +\n            \" varying highp vec2 textureCoordinate2;\\n\" +\n            \"\\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform sampler2D inputImageTexture2;\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"     mediump vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"     mediump vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);\\n\" +\n            \"     mediump vec4 whiteColor = vec4(1.0);\\n\" +\n            \"     gl_FragColor = whiteColor - ((whiteColor - textureColor2) * (whiteColor - textureColor));\\n\" +\n            \" }\";\n\n    public GPUImageScreenBlendFilter() {\n        super(SCREEN_BLEND_FRAGMENT_SHADER);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageSepiaToneFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\n/**\n * Applies a simple sepia effect.\n */\npublic class GPUImageSepiaToneFilter extends GPUImageColorMatrixFilter {\n\n    public GPUImageSepiaToneFilter() {\n        this(1.0f);\n    }\n\n    public GPUImageSepiaToneFilter(final float intensity) {\n        super(intensity, new float[]{\n                0.3588f, 0.7044f, 0.1368f, 0.0f,\n                0.2990f, 0.5870f, 0.1140f, 0.0f,\n                0.2392f, 0.4696f, 0.0912f, 0.0f,\n                0f, 0f, 0f, 1.0f\n        });\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageSharpenFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\n/**\n * Sharpens the picture. <br>\n * <br>\n * sharpness: from -4.0 to 4.0, with 0.0 as the normal level\n */\npublic class GPUImageSharpenFilter extends GPUImageFilter {\n    public static final String SHARPEN_VERTEX_SHADER = \"\" +\n            \"attribute vec4 position;\\n\" +\n            \"attribute vec4 inputTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"uniform float imageWidthFactor; \\n\" +\n            \"uniform float imageHeightFactor; \\n\" +\n            \"uniform float sharpness;\\n\" +\n            \"\\n\" +\n            \"varying vec2 textureCoordinate;\\n\" +\n            \"varying vec2 leftTextureCoordinate;\\n\" +\n            \"varying vec2 rightTextureCoordinate; \\n\" +\n            \"varying vec2 topTextureCoordinate;\\n\" +\n            \"varying vec2 bottomTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"varying float centerMultiplier;\\n\" +\n            \"varying float edgeMultiplier;\\n\" +\n            \"\\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"    gl_Position = position;\\n\" +\n            \"    \\n\" +\n            \"    mediump vec2 widthStep = vec2(imageWidthFactor, 0.0);\\n\" +\n            \"    mediump vec2 heightStep = vec2(0.0, imageHeightFactor);\\n\" +\n            \"    \\n\" +\n            \"    textureCoordinate = inputTextureCoordinate.xy;\\n\" +\n            \"    leftTextureCoordinate = inputTextureCoordinate.xy - widthStep;\\n\" +\n            \"    rightTextureCoordinate = inputTextureCoordinate.xy + widthStep;\\n\" +\n            \"    topTextureCoordinate = inputTextureCoordinate.xy + heightStep;     \\n\" +\n            \"    bottomTextureCoordinate = inputTextureCoordinate.xy - heightStep;\\n\" +\n            \"    \\n\" +\n            \"    centerMultiplier = 1.0 + 4.0 * sharpness;\\n\" +\n            \"    edgeMultiplier = sharpness;\\n\" +\n            \"}\";\n\n    public static final String SHARPEN_FRAGMENT_SHADER = \"\" +\n            \"precision highp float;\\n\" +\n            \"\\n\" +\n            \"varying highp vec2 textureCoordinate;\\n\" +\n            \"varying highp vec2 leftTextureCoordinate;\\n\" +\n            \"varying highp vec2 rightTextureCoordinate; \\n\" +\n            \"varying highp vec2 topTextureCoordinate;\\n\" +\n            \"varying highp vec2 bottomTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"varying highp float centerMultiplier;\\n\" +\n            \"varying highp float edgeMultiplier;\\n\" +\n            \"\\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"\\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"    mediump vec3 textureColor = texture2D(inputImageTexture, textureCoordinate).rgb;\\n\" +\n            \"    mediump vec3 leftTextureColor = texture2D(inputImageTexture, leftTextureCoordinate).rgb;\\n\" +\n            \"    mediump vec3 rightTextureColor = texture2D(inputImageTexture, rightTextureCoordinate).rgb;\\n\" +\n            \"    mediump vec3 topTextureColor = texture2D(inputImageTexture, topTextureCoordinate).rgb;\\n\" +\n            \"    mediump vec3 bottomTextureColor = texture2D(inputImageTexture, bottomTextureCoordinate).rgb;\\n\" +\n            \"\\n\" +\n            \"    gl_FragColor = vec4((textureColor * centerMultiplier - (leftTextureColor * edgeMultiplier + rightTextureColor * edgeMultiplier + topTextureColor * edgeMultiplier + bottomTextureColor * edgeMultiplier)), texture2D(inputImageTexture, bottomTextureCoordinate).w);\\n\" +\n            \"}\";\n\n    private int sharpnessLocation;\n    private float sharpness;\n    private int imageWidthFactorLocation;\n    private int imageHeightFactorLocation;\n\n    public GPUImageSharpenFilter() {\n        this(0.0f);\n    }\n\n    public GPUImageSharpenFilter(final float sharpness) {\n        super(SHARPEN_VERTEX_SHADER, SHARPEN_FRAGMENT_SHADER);\n        this.sharpness = sharpness;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        sharpnessLocation = GLES20.glGetUniformLocation(getProgram(), \"sharpness\");\n        imageWidthFactorLocation = GLES20.glGetUniformLocation(getProgram(), \"imageWidthFactor\");\n        imageHeightFactorLocation = GLES20.glGetUniformLocation(getProgram(), \"imageHeightFactor\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setSharpness(sharpness);\n    }\n\n    @Override\n    public void onOutputSizeChanged(final int width, final int height) {\n        super.onOutputSizeChanged(width, height);\n        setFloat(imageWidthFactorLocation, 1.0f / width);\n        setFloat(imageHeightFactorLocation, 1.0f / height);\n    }\n\n    public void setSharpness(final float sharpness) {\n        this.sharpness = sharpness;\n        setFloat(sharpnessLocation, this.sharpness);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageSketchFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\n/**\n * Converts video to look like a sketch.\n * This is just the Sobel edge detection filter with the colors inverted.\n */\npublic class GPUImageSketchFilter extends GPUImageFilterGroup {\n    public static final String SKETCH_FRAGMENT_SHADER = \"\" +\n            \"precision mediump float;\\n\" +\n            \"\\n\" +\n            \"varying vec2 textureCoordinate;\\n\" +\n            \"varying vec2 leftTextureCoordinate;\\n\" +\n            \"varying vec2 rightTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"varying vec2 topTextureCoordinate;\\n\" +\n            \"varying vec2 topLeftTextureCoordinate;\\n\" +\n            \"varying vec2 topRightTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"varying vec2 bottomTextureCoordinate;\\n\" +\n            \"varying vec2 bottomLeftTextureCoordinate;\\n\" +\n            \"varying vec2 bottomRightTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"\\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"float bottomLeftIntensity = texture2D(inputImageTexture, bottomLeftTextureCoordinate).r;\\n\" +\n            \"float topRightIntensity = texture2D(inputImageTexture, topRightTextureCoordinate).r;\\n\" +\n            \"float topLeftIntensity = texture2D(inputImageTexture, topLeftTextureCoordinate).r;\\n\" +\n            \"float bottomRightIntensity = texture2D(inputImageTexture, bottomRightTextureCoordinate).r;\\n\" +\n            \"float leftIntensity = texture2D(inputImageTexture, leftTextureCoordinate).r;\\n\" +\n            \"float rightIntensity = texture2D(inputImageTexture, rightTextureCoordinate).r;\\n\" +\n            \"float bottomIntensity = texture2D(inputImageTexture, bottomTextureCoordinate).r;\\n\" +\n            \"float topIntensity = texture2D(inputImageTexture, topTextureCoordinate).r;\\n\" +\n            \"float h = -topLeftIntensity - 2.0 * topIntensity - topRightIntensity + bottomLeftIntensity + 2.0 * bottomIntensity + bottomRightIntensity;\\n\" +\n            \"float v = -bottomLeftIntensity - 2.0 * leftIntensity - topLeftIntensity + bottomRightIntensity + 2.0 * rightIntensity + topRightIntensity;\\n\" +\n            \"\\n\" +\n            \"float mag = 1.0 - length(vec2(h, v));\\n\" +\n            \"\\n\" +\n            \"gl_FragColor = vec4(vec3(mag), 1.0);\\n\" +\n            \"}\\n\";\n\n    public GPUImageSketchFilter() {\n        super();\n        addFilter(new GPUImageGrayscaleFilter());\n        addFilter(new GPUImage3x3TextureSamplingFilter(SKETCH_FRAGMENT_SHADER));\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageSmoothToonFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\n/**\n * This uses a similar process as the GPUImageToonFilter, only it precedes the toon effect\n * with a Gaussian blur to smooth out noise.\n */\npublic class GPUImageSmoothToonFilter extends GPUImageFilterGroup {\n\n    private GPUImageGaussianBlurFilter blurFilter;\n    private GPUImageToonFilter toonFilter;\n\n    /**\n     * Setup and Tear down\n     */\n    public GPUImageSmoothToonFilter() {\n        // First pass: apply a variable Gaussian blur\n        blurFilter = new GPUImageGaussianBlurFilter();\n        addFilter(blurFilter);\n\n        // Second pass: run the Sobel edge detection on this blurred image, along with a posterization effect\n        toonFilter = new GPUImageToonFilter();\n        addFilter(toonFilter);\n\n        getFilters().add(blurFilter);\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setBlurSize(0.5f);\n        setThreshold(0.2f);\n        setQuantizationLevels(10.0f);\n    }\n\n    /**\n     * Accessors\n     */\n    public void setTexelWidth(float value) {\n        toonFilter.setTexelWidth(value);\n    }\n\n    public void setTexelHeight(float value) {\n        toonFilter.setTexelHeight(value);\n    }\n\n    public void setBlurSize(float value) {\n        blurFilter.setBlurSize(value);\n    }\n\n    public void setThreshold(float value) {\n        toonFilter.setThreshold(value);\n    }\n\n    public void setQuantizationLevels(float value) {\n        toonFilter.setQuantizationLevels(value);\n    }\n\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageSobelEdgeDetectionFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\n/**\n * Applies sobel edge detection on the image.\n */\npublic class GPUImageSobelEdgeDetectionFilter extends GPUImageFilterGroup {\n    public static final String SOBEL_EDGE_DETECTION = \"\" +\n            \"precision mediump float;\\n\" +\n            \"\\n\" +\n            \"varying vec2 textureCoordinate;\\n\" +\n            \"varying vec2 leftTextureCoordinate;\\n\" +\n            \"varying vec2 rightTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"varying vec2 topTextureCoordinate;\\n\" +\n            \"varying vec2 topLeftTextureCoordinate;\\n\" +\n            \"varying vec2 topRightTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"varying vec2 bottomTextureCoordinate;\\n\" +\n            \"varying vec2 bottomLeftTextureCoordinate;\\n\" +\n            \"varying vec2 bottomRightTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"\\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"    float bottomLeftIntensity = texture2D(inputImageTexture, bottomLeftTextureCoordinate).r;\\n\" +\n            \"    float topRightIntensity = texture2D(inputImageTexture, topRightTextureCoordinate).r;\\n\" +\n            \"    float topLeftIntensity = texture2D(inputImageTexture, topLeftTextureCoordinate).r;\\n\" +\n            \"    float bottomRightIntensity = texture2D(inputImageTexture, bottomRightTextureCoordinate).r;\\n\" +\n            \"    float leftIntensity = texture2D(inputImageTexture, leftTextureCoordinate).r;\\n\" +\n            \"    float rightIntensity = texture2D(inputImageTexture, rightTextureCoordinate).r;\\n\" +\n            \"    float bottomIntensity = texture2D(inputImageTexture, bottomTextureCoordinate).r;\\n\" +\n            \"    float topIntensity = texture2D(inputImageTexture, topTextureCoordinate).r;\\n\" +\n            \"    float h = -topLeftIntensity - 2.0 * topIntensity - topRightIntensity + bottomLeftIntensity + 2.0 * bottomIntensity + bottomRightIntensity;\\n\" +\n            \"    float v = -bottomLeftIntensity - 2.0 * leftIntensity - topLeftIntensity + bottomRightIntensity + 2.0 * rightIntensity + topRightIntensity;\\n\" +\n            \"\\n\" +\n            \"    float mag = length(vec2(h, v));\\n\" +\n            \"\\n\" +\n            \"    gl_FragColor = vec4(vec3(mag), 1.0);\\n\" +\n            \"}\";\n\n    public GPUImageSobelEdgeDetectionFilter() {\n        super();\n        addFilter(new GPUImageGrayscaleFilter());\n        addFilter(new GPUImage3x3TextureSamplingFilter(SOBEL_EDGE_DETECTION));\n    }\n\n    public void setLineSize(final float size) {\n        ((GPUImage3x3TextureSamplingFilter) getFilters().get(1)).setLineSize(size);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageSobelThresholdFilter.java",
    "content": "package jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\npublic class GPUImageSobelThresholdFilter extends\n        GPUImage3x3TextureSamplingFilter {\n    public static final String SOBEL_THRESHOLD_EDGE_DETECTION = \"\" +\n            \"precision mediump float;\\n\" +\n            \"\\n\" +\n            \"varying vec2 textureCoordinate;\\n\" +\n            \"varying vec2 leftTextureCoordinate;\\n\" +\n            \"varying vec2 rightTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"varying vec2 topTextureCoordinate;\\n\" +\n            \"varying vec2 topLeftTextureCoordinate;\\n\" +\n            \"varying vec2 topRightTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"varying vec2 bottomTextureCoordinate;\\n\" +\n            \"varying vec2 bottomLeftTextureCoordinate;\\n\" +\n            \"varying vec2 bottomRightTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"uniform lowp float threshold;\\n\" +\n            \"\\n\" +\n            \"const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);\\n\" +\n            \"\\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"    float bottomLeftIntensity = texture2D(inputImageTexture, bottomLeftTextureCoordinate).r;\\n\" +\n            \"    float topRightIntensity = texture2D(inputImageTexture, topRightTextureCoordinate).r;\\n\" +\n            \"    float topLeftIntensity = texture2D(inputImageTexture, topLeftTextureCoordinate).r;\\n\" +\n            \"    float bottomRightIntensity = texture2D(inputImageTexture, bottomRightTextureCoordinate).r;\\n\" +\n            \"    float leftIntensity = texture2D(inputImageTexture, leftTextureCoordinate).r;\\n\" +\n            \"    float rightIntensity = texture2D(inputImageTexture, rightTextureCoordinate).r;\\n\" +\n            \"    float bottomIntensity = texture2D(inputImageTexture, bottomTextureCoordinate).r;\\n\" +\n            \"    float topIntensity = texture2D(inputImageTexture, topTextureCoordinate).r;\\n\" +\n            \"    float h = -topLeftIntensity - 2.0 * topIntensity - topRightIntensity + bottomLeftIntensity + 2.0 * bottomIntensity + bottomRightIntensity;\\n\" +\n            \"    float v = -bottomLeftIntensity - 2.0 * leftIntensity - topLeftIntensity + bottomRightIntensity + 2.0 * rightIntensity + topRightIntensity;\\n\" +\n            \"\\n\" +\n            \"    float mag = 1.0 - length(vec2(h, v));\\n\" +\n            \"    mag = step(threshold, mag);\\n\" +\n            \"\\n\" +\n            \"    gl_FragColor = vec4(vec3(mag), 1.0);\\n\" +\n            \"}\\n\";\n\n    private int uniformThresholdLocation;\n    private float threshold;\n\n    public GPUImageSobelThresholdFilter() {\n        this(0.9f);\n    }\n\n    public GPUImageSobelThresholdFilter(float threshold) {\n        super(SOBEL_THRESHOLD_EDGE_DETECTION);\n        this.threshold = threshold;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        uniformThresholdLocation = GLES20.glGetUniformLocation(getProgram(), \"threshold\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setThreshold(threshold);\n    }\n\n    public void setThreshold(final float threshold) {\n        this.threshold = threshold;\n        setFloat(uniformThresholdLocation, threshold);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageSoftLightBlendFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\npublic class GPUImageSoftLightBlendFilter extends GPUImageTwoInputFilter {\n    public static final String SOFT_LIGHT_BLEND_FRAGMENT_SHADER = \"varying highp vec2 textureCoordinate;\\n\" +\n            \" varying highp vec2 textureCoordinate2;\\n\" +\n            \"\\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform sampler2D inputImageTexture2;\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"     mediump vec4 base = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"     mediump vec4 overlay = texture2D(inputImageTexture2, textureCoordinate2);\\n\" +\n            \"     \\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\" +\n            \" }\";\n\n    public GPUImageSoftLightBlendFilter() {\n        super(SOFT_LIGHT_BLEND_FRAGMENT_SHADER);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageSolarizeFilter.java",
    "content": "package jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\npublic class GPUImageSolarizeFilter extends GPUImageFilter {\n    public static final String SOLATIZE_FRAGMENT_SHADER = \"\" +\n            \"varying highp vec2 textureCoordinate;\\n\" +\n            \"\\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"uniform highp float threshold;\\n\" +\n            \"\\n\" +\n            \"const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);\\n\" +\n            \"\\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"    highp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"    highp float luminance = dot(textureColor.rgb, W);\\n\" +\n            \"    highp float thresholdResult = step(luminance, threshold);\\n\" +\n            \"    highp vec3 finalColor = abs(thresholdResult - textureColor.rgb);\\n\" +\n            \"    \\n\" +\n            \"    gl_FragColor = vec4(finalColor, textureColor.w);\\n\" +\n            \"}\";\n\n    private int uniformThresholdLocation;\n    private float threshold;\n\n    public GPUImageSolarizeFilter() {\n        this(0.5f);\n    }\n\n    public GPUImageSolarizeFilter(float threshold) {\n        super(NO_FILTER_VERTEX_SHADER, SOLATIZE_FRAGMENT_SHADER);\n        this.threshold = threshold;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        uniformThresholdLocation = GLES20.glGetUniformLocation(getProgram(), \"threshold\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setThreshold(threshold);\n    }\n\n    public void setThreshold(final float threshold) {\n        this.threshold = threshold;\n        setFloat(uniformThresholdLocation, threshold);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageSourceOverBlendFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\npublic class GPUImageSourceOverBlendFilter extends GPUImageTwoInputFilter {\n    public static final String SOURCE_OVER_BLEND_FRAGMENT_SHADER = \"varying highp vec2 textureCoordinate;\\n\" +\n            \" varying highp vec2 textureCoordinate2;\\n\" +\n            \" \\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform sampler2D inputImageTexture2;\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"   lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"   lowp vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);\\n\" +\n            \"   \\n\" +\n            \"   gl_FragColor = mix(textureColor, textureColor2, textureColor2.a);\\n\" +\n            \" }\";\n\n    public GPUImageSourceOverBlendFilter() {\n        super(SOURCE_OVER_BLEND_FRAGMENT_SHADER);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageSphereRefractionFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.graphics.PointF;\nimport android.opengl.GLES20;\n\npublic class GPUImageSphereRefractionFilter extends GPUImageFilter {\n    public static final String SPHERE_FRAGMENT_SHADER = \"\" +\n            \"varying highp vec2 textureCoordinate;\\n\" +\n            \"\\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"\\n\" +\n            \"uniform highp vec2 center;\\n\" +\n            \"uniform highp float radius;\\n\" +\n            \"uniform highp float aspectRatio;\\n\" +\n            \"uniform highp float refractiveIndex;\\n\" +\n            \"\\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"highp vec2 textureCoordinateToUse = vec2(textureCoordinate.x, (textureCoordinate.y * aspectRatio + 0.5 - 0.5 * aspectRatio));\\n\" +\n            \"highp float distanceFromCenter = distance(center, textureCoordinateToUse);\\n\" +\n            \"lowp float checkForPresenceWithinSphere = step(distanceFromCenter, radius);\\n\" +\n            \"\\n\" +\n            \"distanceFromCenter = distanceFromCenter / radius;\\n\" +\n            \"\\n\" +\n            \"highp float normalizedDepth = radius * sqrt(1.0 - distanceFromCenter * distanceFromCenter);\\n\" +\n            \"highp vec3 sphereNormal = normalize(vec3(textureCoordinateToUse - center, normalizedDepth));\\n\" +\n            \"\\n\" +\n            \"highp vec3 refractedVector = refract(vec3(0.0, 0.0, -1.0), sphereNormal, refractiveIndex);\\n\" +\n            \"\\n\" +\n            \"gl_FragColor = texture2D(inputImageTexture, (refractedVector.xy + 1.0) * 0.5) * checkForPresenceWithinSphere;     \\n\" +\n            \"}\\n\";\n\n    private PointF center;\n    private int centerLocation;\n    private float radius;\n    private int radiusLocation;\n    private float aspectRatio;\n    private int aspectRatioLocation;\n    private float refractiveIndex;\n    private int refractiveIndexLocation;\n\n    public GPUImageSphereRefractionFilter() {\n        this(new PointF(0.5f, 0.5f), 0.25f, 0.71f);\n    }\n\n    public GPUImageSphereRefractionFilter(PointF center, float radius, float refractiveIndex) {\n        super(NO_FILTER_VERTEX_SHADER, SPHERE_FRAGMENT_SHADER);\n        this.center = center;\n        this.radius = radius;\n        this.refractiveIndex = refractiveIndex;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        centerLocation = GLES20.glGetUniformLocation(getProgram(), \"center\");\n        radiusLocation = GLES20.glGetUniformLocation(getProgram(), \"radius\");\n        aspectRatioLocation = GLES20.glGetUniformLocation(getProgram(), \"aspectRatio\");\n        refractiveIndexLocation = GLES20.glGetUniformLocation(getProgram(), \"refractiveIndex\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setAspectRatio(aspectRatio);\n        setRadius(radius);\n        setCenter(center);\n        setRefractiveIndex(refractiveIndex);\n    }\n\n    @Override\n    public void onOutputSizeChanged(int width, int height) {\n        aspectRatio = (float) height / width;\n        setAspectRatio(aspectRatio);\n        super.onOutputSizeChanged(width, height);\n    }\n\n    private void setAspectRatio(float aspectRatio) {\n        this.aspectRatio = aspectRatio;\n        setFloat(aspectRatioLocation, aspectRatio);\n    }\n\n    /**\n     * The index of refraction for the sphere, with a default of 0.71\n     *\n     * @param refractiveIndex default 0.71\n     */\n    public void setRefractiveIndex(float refractiveIndex) {\n        this.refractiveIndex = refractiveIndex;\n        setFloat(refractiveIndexLocation, refractiveIndex);\n    }\n\n    /**\n     * The center about which to apply the distortion, with a default of (0.5, 0.5)\n     *\n     * @param center default (0.5, 0.5)\n     */\n    public void setCenter(PointF center) {\n        this.center = center;\n        setPoint(centerLocation, center);\n    }\n\n    /**\n     * The radius of the distortion, ranging from 0.0 to 1.0, with a default of 0.25\n     *\n     * @param radius from 0.0 to 1.0, default 0.25\n     */\n    public void setRadius(float radius) {\n        this.radius = radius;\n        setFloat(radiusLocation, radius);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageSubtractBlendFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\npublic class GPUImageSubtractBlendFilter extends GPUImageTwoInputFilter {\n    public static final String SUBTRACT_BLEND_FRAGMENT_SHADER = \"varying highp vec2 textureCoordinate;\\n\" +\n            \" varying highp vec2 textureCoordinate2;\\n\" +\n            \"\\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform sampler2D inputImageTexture2;\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"   lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"   lowp vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);\\n\" +\n            \"\\n\" +\n            \"   gl_FragColor = vec4(textureColor.rgb - textureColor2.rgb, textureColor.a);\\n\" +\n            \" }\";\n\n    public GPUImageSubtractBlendFilter() {\n        super(SUBTRACT_BLEND_FRAGMENT_SHADER);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageSwirlFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.graphics.PointF;\nimport android.opengl.GLES20;\n\n/**\n * Creates a swirl distortion on the image.\n */\npublic class GPUImageSwirlFilter extends GPUImageFilter {\n    public static final String SWIRL_FRAGMENT_SHADER = \"\" +\n            \"varying highp vec2 textureCoordinate;\\n\" +\n            \"\\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"\\n\" +\n            \"uniform highp vec2 center;\\n\" +\n            \"uniform highp float radius;\\n\" +\n            \"uniform highp float angle;\\n\" +\n            \"\\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"highp vec2 textureCoordinateToUse = textureCoordinate;\\n\" +\n            \"highp float dist = distance(center, textureCoordinate);\\n\" +\n            \"if (dist < radius)\\n\" +\n            \"{\\n\" +\n            \"textureCoordinateToUse -= center;\\n\" +\n            \"highp float percent = (radius - dist) / radius;\\n\" +\n            \"highp float theta = percent * percent * angle * 8.0;\\n\" +\n            \"highp float s = sin(theta);\\n\" +\n            \"highp float c = cos(theta);\\n\" +\n            \"textureCoordinateToUse = vec2(dot(textureCoordinateToUse, vec2(c, -s)), dot(textureCoordinateToUse, vec2(s, c)));\\n\" +\n            \"textureCoordinateToUse += center;\\n\" +\n            \"}\\n\" +\n            \"\\n\" +\n            \"gl_FragColor = texture2D(inputImageTexture, textureCoordinateToUse );\\n\" +\n            \"\\n\" +\n            \"}\\n\";\n\n    private float angle;\n    private int angleLocation;\n    private float radius;\n    private int radiusLocation;\n    private PointF center;\n    private int centerLocation;\n\n    public GPUImageSwirlFilter() {\n        this(0.5f, 1.0f, new PointF(0.5f, 0.5f));\n    }\n\n    public GPUImageSwirlFilter(float radius, float angle, PointF center) {\n        super(NO_FILTER_VERTEX_SHADER, SWIRL_FRAGMENT_SHADER);\n        this.radius = radius;\n        this.angle = angle;\n        this.center = center;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        angleLocation = GLES20.glGetUniformLocation(getProgram(), \"angle\");\n        radiusLocation = GLES20.glGetUniformLocation(getProgram(), \"radius\");\n        centerLocation = GLES20.glGetUniformLocation(getProgram(), \"center\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setRadius(radius);\n        setAngle(angle);\n        setCenter(center);\n    }\n\n    /**\n     * The radius of the distortion, ranging from 0.0 to 1.0, with a default of 0.5.\n     *\n     * @param radius from 0.0 to 1.0, default 0.5\n     */\n    public void setRadius(float radius) {\n        this.radius = radius;\n        setFloat(radiusLocation, radius);\n    }\n\n    /**\n     * The amount of distortion to apply, with a minimum of 0.0 and a default of 1.0.\n     *\n     * @param angle minimum 0.0, default 1.0\n     */\n    public void setAngle(float angle) {\n        this.angle = angle;\n        setFloat(angleLocation, angle);\n    }\n\n    /**\n     * The center about which to apply the distortion, with a default of (0.5, 0.5).\n     *\n     * @param center default (0.5, 0.5)\n     */\n    public void setCenter(PointF center) {\n        this.center = center;\n        setPoint(centerLocation, center);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageThresholdEdgeDetectionFilter.java",
    "content": "package jp.co.cyberagent.android.gpuimage.filter;\n\n/**\n * Applies sobel edge detection on the image.\n */\npublic class GPUImageThresholdEdgeDetectionFilter extends GPUImageFilterGroup {\n    public GPUImageThresholdEdgeDetectionFilter() {\n        super();\n        addFilter(new GPUImageGrayscaleFilter());\n        addFilter(new GPUImageSobelThresholdFilter());\n    }\n\n    public void setLineSize(final float size) {\n        ((GPUImage3x3TextureSamplingFilter) getFilters().get(1)).setLineSize(size);\n    }\n\n    public void setThreshold(final float threshold) {\n        ((GPUImageSobelThresholdFilter) getFilters().get(1)).setThreshold(threshold);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageToneCurveFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.graphics.Point;\nimport android.graphics.PointF;\nimport android.opengl.GLES20;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.ByteBuffer;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Comparator;\n\nimport jp.co.cyberagent.android.gpuimage.util.OpenGlUtils;\n\npublic class GPUImageToneCurveFilter extends GPUImageFilter {\n    public static final String TONE_CURVE_FRAGMENT_SHADER = \"\" +\n            \" varying highp vec2 textureCoordinate;\\n\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" uniform sampler2D toneCurveTexture;\\n\" +\n            \"\\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"     lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"     lowp float redCurveValue = texture2D(toneCurveTexture, vec2(textureColor.r, 0.0)).r;\\n\" +\n            \"     lowp float greenCurveValue = texture2D(toneCurveTexture, vec2(textureColor.g, 0.0)).g;\\n\" +\n            \"     lowp float blueCurveValue = texture2D(toneCurveTexture, vec2(textureColor.b, 0.0)).b;\\n\" +\n            \"\\n\" +\n            \"     gl_FragColor = vec4(redCurveValue, greenCurveValue, blueCurveValue, textureColor.a);\\n\" +\n            \" }\";\n\n    private int[] toneCurveTexture = new int[]{OpenGlUtils.NO_TEXTURE};\n    private int toneCurveTextureUniformLocation;\n\n    private PointF[] rgbCompositeControlPoints;\n    private PointF[] redControlPoints;\n    private PointF[] greenControlPoints;\n    private PointF[] blueControlPoints;\n\n    private ArrayList<Float> rgbCompositeCurve;\n    private ArrayList<Float> redCurve;\n    private ArrayList<Float> greenCurve;\n    private ArrayList<Float> blueCurve;\n\n\n    public GPUImageToneCurveFilter() {\n        super(NO_FILTER_VERTEX_SHADER, TONE_CURVE_FRAGMENT_SHADER);\n\n        PointF[] defaultCurvePoints = new PointF[]{new PointF(0.0f, 0.0f), new PointF(0.5f, 0.5f), new PointF(1.0f, 1.0f)};\n        rgbCompositeControlPoints = defaultCurvePoints;\n        redControlPoints = defaultCurvePoints;\n        greenControlPoints = defaultCurvePoints;\n        blueControlPoints = defaultCurvePoints;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        toneCurveTextureUniformLocation = GLES20.glGetUniformLocation(getProgram(), \"toneCurveTexture\");\n        GLES20.glActiveTexture(GLES20.GL_TEXTURE3);\n        GLES20.glGenTextures(1, toneCurveTexture, 0);\n        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, toneCurveTexture[0]);\n        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);\n        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);\n        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);\n        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setRgbCompositeControlPoints(rgbCompositeControlPoints);\n        setRedControlPoints(redControlPoints);\n        setGreenControlPoints(greenControlPoints);\n        setBlueControlPoints(blueControlPoints);\n    }\n\n    @Override\n    protected void onDrawArraysPre() {\n        if (toneCurveTexture[0] != OpenGlUtils.NO_TEXTURE) {\n            GLES20.glActiveTexture(GLES20.GL_TEXTURE3);\n            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, toneCurveTexture[0]);\n            GLES20.glUniform1i(toneCurveTextureUniformLocation, 3);\n        }\n    }\n\n    public void setFromCurveFileInputStream(InputStream input) {\n        try {\n            int version = readShort(input);\n            int totalCurves = readShort(input);\n\n            ArrayList<PointF[]> curves = new ArrayList<>(totalCurves);\n            float pointRate = 1.0f / 255;\n\n            for (int i = 0; i < totalCurves; i++) {\n                // 2 bytes, Count of points in the curve (short integer from 2...19)\n                short pointCount = readShort(input);\n\n                PointF[] points = new PointF[pointCount];\n\n                // point count * 4\n                // Curve points. Each curve point is a pair of short integers where\n                // the first number is the output value (vertical coordinate on the\n                // Curves dialog graph) and the second is the input value. All coordinates have range 0 to 255.\n                for (int j = 0; j < pointCount; j++) {\n                    short y = readShort(input);\n                    short x = readShort(input);\n\n                    points[j] = new PointF(x * pointRate, y * pointRate);\n                }\n\n                curves.add(points);\n            }\n            input.close();\n\n            rgbCompositeControlPoints = curves.get(0);\n            redControlPoints = curves.get(1);\n            greenControlPoints = curves.get(2);\n            blueControlPoints = curves.get(3);\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n    private short readShort(InputStream input) throws IOException {\n        return (short) (input.read() << 8 | input.read());\n    }\n\n    public void setRgbCompositeControlPoints(PointF[] points) {\n        rgbCompositeControlPoints = points;\n        rgbCompositeCurve = createSplineCurve(rgbCompositeControlPoints);\n        updateToneCurveTexture();\n    }\n\n    public void setRedControlPoints(PointF[] points) {\n        redControlPoints = points;\n        redCurve = createSplineCurve(redControlPoints);\n        updateToneCurveTexture();\n    }\n\n    public void setGreenControlPoints(PointF[] points) {\n        greenControlPoints = points;\n        greenCurve = createSplineCurve(greenControlPoints);\n        updateToneCurveTexture();\n    }\n\n    public void setBlueControlPoints(PointF[] points) {\n        blueControlPoints = points;\n        blueCurve = createSplineCurve(blueControlPoints);\n        updateToneCurveTexture();\n    }\n\n    private void updateToneCurveTexture() {\n        runOnDraw(new Runnable() {\n            @Override\n            public void run() {\n                GLES20.glActiveTexture(GLES20.GL_TEXTURE3);\n                GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, toneCurveTexture[0]);\n\n                if ((redCurve.size() >= 256) && (greenCurve.size() >= 256) && (blueCurve.size() >= 256) && (rgbCompositeCurve.size() >= 256)) {\n                    byte[] toneCurveByteArray = new byte[256 * 4];\n                    for (int currentCurveIndex = 0; currentCurveIndex < 256; currentCurveIndex++) {\n                        // BGRA for upload to texture\n                        toneCurveByteArray[currentCurveIndex * 4 + 2] = (byte) ((int) Math.min(Math.max(currentCurveIndex + blueCurve.get(currentCurveIndex) + rgbCompositeCurve.get(currentCurveIndex), 0), 255) & 0xff);\n                        toneCurveByteArray[currentCurveIndex * 4 + 1] = (byte) ((int) Math.min(Math.max(currentCurveIndex + greenCurve.get(currentCurveIndex) + rgbCompositeCurve.get(currentCurveIndex), 0), 255) & 0xff);\n                        toneCurveByteArray[currentCurveIndex * 4] = (byte) ((int) Math.min(Math.max(currentCurveIndex + redCurve.get(currentCurveIndex) + rgbCompositeCurve.get(currentCurveIndex), 0), 255) & 0xff);\n                        toneCurveByteArray[currentCurveIndex * 4 + 3] = (byte) (0xff);\n                    }\n\n                    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));\n                }\n//        Buffer pixels!\n//        GLES20.glTexImage2D(int target,\n//            int level,\n//            int internalformat,\n//            int width,\n//            int height,\n//            int border,\n//            int format,\n//            int type,\n//            java.nio.Buffer pixels);\n            }\n        });\n    }\n\n    private ArrayList<Float> createSplineCurve(PointF[] points) {\n        if (points == null || points.length <= 0) {\n            return null;\n        }\n\n        // Sort the array\n        PointF[] pointsSorted = points.clone();\n        Arrays.sort(pointsSorted, new Comparator<PointF>() {\n            @Override\n            public int compare(PointF point1, PointF point2) {\n                if (point1.x < point2.x) {\n                    return -1;\n                } else if (point1.x > point2.x) {\n                    return 1;\n                } else {\n                    return 0;\n                }\n            }\n        });\n\n        // Convert from (0, 1) to (0, 255).\n        Point[] convertedPoints = new Point[pointsSorted.length];\n        for (int i = 0; i < points.length; i++) {\n            PointF point = pointsSorted[i];\n            convertedPoints[i] = new Point((int) (point.x * 255), (int) (point.y * 255));\n        }\n\n        ArrayList<Point> splinePoints = createSplineCurve2(convertedPoints);\n\n        // If we have a first point like (0.3, 0) we'll be missing some points at the beginning\n        // that should be 0.\n        Point firstSplinePoint = splinePoints.get(0);\n        if (firstSplinePoint.x > 0) {\n            for (int i = firstSplinePoint.x; i >= 0; i--) {\n                splinePoints.add(0, new Point(i, 0));\n            }\n        }\n\n        // Insert points similarly at the end, if necessary.\n        Point lastSplinePoint = splinePoints.get(splinePoints.size() - 1);\n        if (lastSplinePoint.x < 255) {\n            for (int i = lastSplinePoint.x + 1; i <= 255; i++) {\n                splinePoints.add(new Point(i, 255));\n            }\n        }\n\n        // Prepare the spline points.\n        ArrayList<Float> preparedSplinePoints = new ArrayList<>(splinePoints.size());\n        for (Point newPoint : splinePoints) {\n            Point origPoint = new Point(newPoint.x, newPoint.x);\n\n            float distance = (float) Math.sqrt(Math.pow((origPoint.x - newPoint.x), 2.0) + Math.pow((origPoint.y - newPoint.y), 2.0));\n\n            if (origPoint.y > newPoint.y) {\n                distance = -distance;\n            }\n\n            preparedSplinePoints.add(distance);\n        }\n\n        return preparedSplinePoints;\n    }\n\n    private ArrayList<Point> createSplineCurve2(Point[] points) {\n        ArrayList<Double> sdA = createSecondDerivative(points);\n\n        // Is [points count] equal to [sdA count]?\n//    int n = [points count];\n        int n = sdA.size();\n        if (n < 1) {\n            return null;\n        }\n        double sd[] = new double[n];\n\n        // From NSMutableArray to sd[n];\n        for (int i = 0; i < n; i++) {\n            sd[i] = sdA.get(i);\n        }\n\n\n        ArrayList<Point> output = new ArrayList<>(n + 1);\n\n        for (int i = 0; i < n - 1; i++) {\n            Point cur = points[i];\n            Point next = points[i + 1];\n\n            for (int x = cur.x; x < next.x; x++) {\n                double t = (double) (x - cur.x) / (next.x - cur.x);\n\n                double a = 1 - t;\n                double b = t;\n                double h = next.x - cur.x;\n\n                double y = a * cur.y + b * next.y + (h * h / 6) * ((a * a * a - a) * sd[i] + (b * b * b - b) * sd[i + 1]);\n\n                if (y > 255.0) {\n                    y = 255.0;\n                } else if (y < 0.0) {\n                    y = 0.0;\n                }\n\n                output.add(new Point(x, (int) Math.round(y)));\n            }\n        }\n\n        // If the last point is (255, 255) it doesn't get added.\n        if (output.size() == 255) {\n            output.add(points[points.length - 1]);\n        }\n        return output;\n    }\n\n    private ArrayList<Double> createSecondDerivative(Point[] points) {\n        int n = points.length;\n        if (n <= 1) {\n            return null;\n        }\n\n        double matrix[][] = new double[n][3];\n        double result[] = new double[n];\n        matrix[0][1] = 1;\n        // What about matrix[0][1] and matrix[0][0]? Assuming 0 for now (Brad L.)\n        matrix[0][0] = 0;\n        matrix[0][2] = 0;\n\n        for (int i = 1; i < n - 1; i++) {\n            Point P1 = points[i - 1];\n            Point P2 = points[i];\n            Point P3 = points[i + 1];\n\n            matrix[i][0] = (double) (P2.x - P1.x) / 6;\n            matrix[i][1] = (double) (P3.x - P1.x) / 3;\n            matrix[i][2] = (double) (P3.x - P2.x) / 6;\n            result[i] = (double) (P3.y - P2.y) / (P3.x - P2.x) - (double) (P2.y - P1.y) / (P2.x - P1.x);\n        }\n\n        // What about result[0] and result[n-1]? Assuming 0 for now (Brad L.)\n        result[0] = 0;\n        result[n - 1] = 0;\n\n        matrix[n - 1][1] = 1;\n        // What about matrix[n-1][0] and matrix[n-1][2]? For now, assuming they are 0 (Brad L.)\n        matrix[n - 1][0] = 0;\n        matrix[n - 1][2] = 0;\n\n        // solving pass1 (up->down)\n        for (int i = 1; i < n; i++) {\n            double k = matrix[i][0] / matrix[i - 1][1];\n            matrix[i][1] -= k * matrix[i - 1][2];\n            matrix[i][0] = 0;\n            result[i] -= k * result[i - 1];\n        }\n        // solving pass2 (down->up)\n        for (int i = n - 2; i >= 0; i--) {\n            double k = matrix[i][2] / matrix[i + 1][1];\n            matrix[i][1] -= k * matrix[i + 1][0];\n            matrix[i][2] = 0;\n            result[i] -= k * result[i + 1];\n        }\n\n        ArrayList<Double> output = new ArrayList<>(n);\n        for (int i = 0; i < n; i++) output.add(result[i] / matrix[i][1]);\n\n        return output;\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageToonFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\n/**\n * This uses Sobel edge detection to place a black border around objects,\n * and then it quantizes the colors present in the image to give a cartoon-like quality to the image.\n */\npublic class GPUImageToonFilter extends GPUImage3x3TextureSamplingFilter {\n    public static final String TOON_FRAGMENT_SHADER = \"\" +\n            \"precision highp float;\\n\" +\n            \"\\n\" +\n            \"varying vec2 textureCoordinate;\\n\" +\n            \"varying vec2 leftTextureCoordinate;\\n\" +\n            \"varying vec2 rightTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"varying vec2 topTextureCoordinate;\\n\" +\n            \"varying vec2 topLeftTextureCoordinate;\\n\" +\n            \"varying vec2 topRightTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"varying vec2 bottomTextureCoordinate;\\n\" +\n            \"varying vec2 bottomLeftTextureCoordinate;\\n\" +\n            \"varying vec2 bottomRightTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"\\n\" +\n            \"uniform highp float intensity;\\n\" +\n            \"uniform highp float threshold;\\n\" +\n            \"uniform highp float quantizationLevels;\\n\" +\n            \"\\n\" +\n            \"const highp vec3 W = vec3(0.2125, 0.7154, 0.0721);\\n\" +\n            \"\\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"\\n\" +\n            \"float bottomLeftIntensity = texture2D(inputImageTexture, bottomLeftTextureCoordinate).r;\\n\" +\n            \"float topRightIntensity = texture2D(inputImageTexture, topRightTextureCoordinate).r;\\n\" +\n            \"float topLeftIntensity = texture2D(inputImageTexture, topLeftTextureCoordinate).r;\\n\" +\n            \"float bottomRightIntensity = texture2D(inputImageTexture, bottomRightTextureCoordinate).r;\\n\" +\n            \"float leftIntensity = texture2D(inputImageTexture, leftTextureCoordinate).r;\\n\" +\n            \"float rightIntensity = texture2D(inputImageTexture, rightTextureCoordinate).r;\\n\" +\n            \"float bottomIntensity = texture2D(inputImageTexture, bottomTextureCoordinate).r;\\n\" +\n            \"float topIntensity = texture2D(inputImageTexture, topTextureCoordinate).r;\\n\" +\n            \"float h = -topLeftIntensity - 2.0 * topIntensity - topRightIntensity + bottomLeftIntensity + 2.0 * bottomIntensity + bottomRightIntensity;\\n\" +\n            \"float v = -bottomLeftIntensity - 2.0 * leftIntensity - topLeftIntensity + bottomRightIntensity + 2.0 * rightIntensity + topRightIntensity;\\n\" +\n            \"\\n\" +\n            \"float mag = length(vec2(h, v));\\n\" +\n            \"\\n\" +\n            \"vec3 posterizedImageColor = floor((textureColor.rgb * quantizationLevels) + 0.5) / quantizationLevels;\\n\" +\n            \"\\n\" +\n            \"float thresholdTest = 1.0 - step(threshold, mag);\\n\" +\n            \"\\n\" +\n            \"gl_FragColor = vec4(posterizedImageColor * thresholdTest, textureColor.a);\\n\" +\n            \"}\\n\";\n\n    private float threshold;\n    private int thresholdLocation;\n    private float quantizationLevels;\n    private int quantizationLevelsLocation;\n\n    public GPUImageToonFilter() {\n        this(0.2f, 10.0f);\n    }\n\n    public GPUImageToonFilter(float threshold, float quantizationLevels) {\n        super(TOON_FRAGMENT_SHADER);\n        this.threshold = threshold;\n        this.quantizationLevels = quantizationLevels;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        thresholdLocation = GLES20.glGetUniformLocation(getProgram(), \"threshold\");\n        quantizationLevelsLocation = GLES20.glGetUniformLocation(getProgram(), \"quantizationLevels\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setThreshold(threshold);\n        setQuantizationLevels(quantizationLevels);\n    }\n\n    /**\n     * The threshold at which to apply the edges, default of 0.2.\n     *\n     * @param threshold default 0.2\n     */\n    public void setThreshold(final float threshold) {\n        this.threshold = threshold;\n        setFloat(thresholdLocation, threshold);\n    }\n\n    /**\n     * The levels of quantization for the posterization of colors within the scene, with a default of 10.0.\n     *\n     * @param quantizationLevels default 10.0\n     */\n    public void setQuantizationLevels(final float quantizationLevels) {\n        this.quantizationLevels = quantizationLevels;\n        setFloat(quantizationLevelsLocation, quantizationLevels);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageTransformFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\nimport android.opengl.Matrix;\n\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.FloatBuffer;\n\npublic class GPUImageTransformFilter extends GPUImageFilter {\n    public static final String TRANSFORM_VERTEX_SHADER = \"\" +\n            \"attribute vec4 position;\\n\" +\n            \" attribute vec4 inputTextureCoordinate;\\n\" +\n            \" \\n\" +\n            \" uniform mat4 transformMatrix;\\n\" +\n            \" uniform mat4 orthographicMatrix;\\n\" +\n            \" \\n\" +\n            \" varying vec2 textureCoordinate;\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"     gl_Position = transformMatrix * vec4(position.xyz, 1.0) * orthographicMatrix;\\n\" +\n            \"     textureCoordinate = inputTextureCoordinate.xy;\\n\" +\n            \" }\";\n\n    private int transformMatrixUniform;\n    private int orthographicMatrixUniform;\n    private float[] orthographicMatrix;\n\n    private float[] transform3D;\n\n    // This applies the transform to the raw frame data if set to YES, the default of NO takes the aspect ratio of the image input into account when rotating\n    private boolean ignoreAspectRatio;\n\n    // sets the anchor point to top left corner\n    private boolean anchorTopLeft;\n\n    public GPUImageTransformFilter() {\n        super(TRANSFORM_VERTEX_SHADER, NO_FILTER_FRAGMENT_SHADER);\n\n        orthographicMatrix = new float[16];\n        Matrix.orthoM(orthographicMatrix, 0, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);\n\n        transform3D = new float[16];\n        Matrix.setIdentityM(transform3D, 0);\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        transformMatrixUniform = GLES20.glGetUniformLocation(getProgram(), \"transformMatrix\");\n        orthographicMatrixUniform = GLES20.glGetUniformLocation(getProgram(), \"orthographicMatrix\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setUniformMatrix4f(transformMatrixUniform, transform3D);\n        setUniformMatrix4f(orthographicMatrixUniform, orthographicMatrix);\n    }\n\n    @Override\n    public void onOutputSizeChanged(final int width, final int height) {\n        super.onOutputSizeChanged(width, height);\n\n        if (!ignoreAspectRatio) {\n            Matrix.orthoM(orthographicMatrix, 0, -1.0f, 1.0f, -1.0f * (float) height / (float) width, 1.0f * (float) height / (float) width, -1.0f, 1.0f);\n            setUniformMatrix4f(orthographicMatrixUniform, orthographicMatrix);\n        }\n    }\n\n    @Override\n    public void onDraw(final int textureId, final FloatBuffer cubeBuffer,\n                       final FloatBuffer textureBuffer) {\n\n        FloatBuffer vertBuffer = cubeBuffer;\n\n        if (!ignoreAspectRatio) {\n\n            float[] adjustedVertices = new float[8];\n\n            cubeBuffer.position(0);\n            cubeBuffer.get(adjustedVertices);\n\n            float normalizedHeight = (float) getOutputHeight() / (float) getOutputWidth();\n            adjustedVertices[1] *= normalizedHeight;\n            adjustedVertices[3] *= normalizedHeight;\n            adjustedVertices[5] *= normalizedHeight;\n            adjustedVertices[7] *= normalizedHeight;\n\n            vertBuffer = ByteBuffer.allocateDirect(adjustedVertices.length * 4)\n                    .order(ByteOrder.nativeOrder())\n                    .asFloatBuffer();\n\n            vertBuffer.put(adjustedVertices).position(0);\n        }\n\n        super.onDraw(textureId, vertBuffer, textureBuffer);\n    }\n\n    public void setTransform3D(float[] transform3D) {\n        this.transform3D = transform3D;\n        setUniformMatrix4f(transformMatrixUniform, transform3D);\n    }\n\n    public float[] getTransform3D() {\n        return transform3D;\n    }\n\n    public void setIgnoreAspectRatio(boolean ignoreAspectRatio) {\n        this.ignoreAspectRatio = ignoreAspectRatio;\n\n        if (ignoreAspectRatio) {\n            Matrix.orthoM(orthographicMatrix, 0, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);\n            setUniformMatrix4f(orthographicMatrixUniform, orthographicMatrix);\n        } else {\n            onOutputSizeChanged(getOutputWidth(), getOutputHeight());\n        }\n    }\n\n    public boolean ignoreAspectRatio() {\n        return ignoreAspectRatio;\n    }\n\n    public void setAnchorTopLeft(boolean anchorTopLeft) {\n        this.anchorTopLeft = anchorTopLeft;\n        setIgnoreAspectRatio(ignoreAspectRatio);\n    }\n\n    public boolean anchorTopLeft() {\n        return anchorTopLeft;\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageTwoInputFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.graphics.Bitmap;\nimport android.opengl.GLES20;\n\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.FloatBuffer;\n\nimport jp.co.cyberagent.android.gpuimage.util.OpenGlUtils;\nimport jp.co.cyberagent.android.gpuimage.util.Rotation;\nimport jp.co.cyberagent.android.gpuimage.util.TextureRotationUtil;\n\npublic class GPUImageTwoInputFilter extends GPUImageFilter {\n    private static final String VERTEX_SHADER = \"attribute vec4 position;\\n\" +\n            \"attribute vec4 inputTextureCoordinate;\\n\" +\n            \"attribute vec4 inputTextureCoordinate2;\\n\" +\n            \" \\n\" +\n            \"varying vec2 textureCoordinate;\\n\" +\n            \"varying vec2 textureCoordinate2;\\n\" +\n            \" \\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"    gl_Position = position;\\n\" +\n            \"    textureCoordinate = inputTextureCoordinate.xy;\\n\" +\n            \"    textureCoordinate2 = inputTextureCoordinate2.xy;\\n\" +\n            \"}\";\n\n    private int filterSecondTextureCoordinateAttribute;\n    private int filterInputTextureUniform2;\n    private int filterSourceTexture2 = OpenGlUtils.NO_TEXTURE;\n    private ByteBuffer texture2CoordinatesBuffer;\n    private Bitmap bitmap;\n\n    public GPUImageTwoInputFilter(String fragmentShader) {\n        this(VERTEX_SHADER, fragmentShader);\n    }\n\n    public GPUImageTwoInputFilter(String vertexShader, String fragmentShader) {\n        super(vertexShader, fragmentShader);\n        setRotation(Rotation.NORMAL, false, false);\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n\n        filterSecondTextureCoordinateAttribute = GLES20.glGetAttribLocation(getProgram(), \"inputTextureCoordinate2\");\n        filterInputTextureUniform2 = GLES20.glGetUniformLocation(getProgram(), \"inputImageTexture2\"); // This does assume a name of \"inputImageTexture2\" for second input texture in the fragment shader\n        GLES20.glEnableVertexAttribArray(filterSecondTextureCoordinateAttribute);\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        if (bitmap != null && !bitmap.isRecycled()) {\n            setBitmap(bitmap);\n        }\n    }\n\n    public void setBitmap(final Bitmap bitmap) {\n        if (bitmap != null && bitmap.isRecycled()) {\n            return;\n        }\n        this.bitmap = bitmap;\n        if (this.bitmap == null) {\n            return;\n        }\n        runOnDraw(new Runnable() {\n            public void run() {\n                if (filterSourceTexture2 == OpenGlUtils.NO_TEXTURE) {\n                    if (bitmap == null || bitmap.isRecycled()) {\n                        return;\n                    }\n                    GLES20.glActiveTexture(GLES20.GL_TEXTURE3);\n                    filterSourceTexture2 = OpenGlUtils.loadTexture(bitmap, OpenGlUtils.NO_TEXTURE, false);\n                }\n            }\n        });\n    }\n\n    public Bitmap getBitmap() {\n        return bitmap;\n    }\n\n    public void recycleBitmap() {\n        if (bitmap != null && !bitmap.isRecycled()) {\n            bitmap.recycle();\n            bitmap = null;\n        }\n    }\n\n    public void onDestroy() {\n        super.onDestroy();\n        GLES20.glDeleteTextures(1, new int[]{\n                filterSourceTexture2\n        }, 0);\n        filterSourceTexture2 = OpenGlUtils.NO_TEXTURE;\n    }\n\n    @Override\n    protected void onDrawArraysPre() {\n        GLES20.glEnableVertexAttribArray(filterSecondTextureCoordinateAttribute);\n        GLES20.glActiveTexture(GLES20.GL_TEXTURE3);\n        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, filterSourceTexture2);\n        GLES20.glUniform1i(filterInputTextureUniform2, 3);\n\n        texture2CoordinatesBuffer.position(0);\n        GLES20.glVertexAttribPointer(filterSecondTextureCoordinateAttribute, 2, GLES20.GL_FLOAT, false, 0, texture2CoordinatesBuffer);\n    }\n\n    public void setRotation(final Rotation rotation, final boolean flipHorizontal, final boolean flipVertical) {\n        float[] buffer = TextureRotationUtil.getRotation(rotation, flipHorizontal, flipVertical);\n\n        ByteBuffer bBuffer = ByteBuffer.allocateDirect(32).order(ByteOrder.nativeOrder());\n        FloatBuffer fBuffer = bBuffer.asFloatBuffer();\n        fBuffer.put(buffer);\n        fBuffer.flip();\n\n        texture2CoordinatesBuffer = bBuffer;\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageTwoPassFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\npublic class GPUImageTwoPassFilter extends GPUImageFilterGroup {\n    public GPUImageTwoPassFilter(String firstVertexShader, String firstFragmentShader,\n                                 String secondVertexShader, String secondFragmentShader) {\n        super(null);\n        addFilter(new GPUImageFilter(firstVertexShader, firstFragmentShader));\n        addFilter(new GPUImageFilter(secondVertexShader, secondFragmentShader));\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageTwoPassTextureSamplingFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\npublic class GPUImageTwoPassTextureSamplingFilter extends GPUImageTwoPassFilter {\n    public GPUImageTwoPassTextureSamplingFilter(String firstVertexShader, String firstFragmentShader,\n                                                String secondVertexShader, String secondFragmentShader) {\n        super(firstVertexShader, firstFragmentShader,\n                secondVertexShader, secondFragmentShader);\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        initTexelOffsets();\n    }\n\n    protected void initTexelOffsets() {\n        float ratio = getHorizontalTexelOffsetRatio();\n        GPUImageFilter filter = getFilters().get(0);\n        int texelWidthOffsetLocation = GLES20.glGetUniformLocation(filter.getProgram(), \"texelWidthOffset\");\n        int texelHeightOffsetLocation = GLES20.glGetUniformLocation(filter.getProgram(), \"texelHeightOffset\");\n        filter.setFloat(texelWidthOffsetLocation, ratio / getOutputWidth());\n        filter.setFloat(texelHeightOffsetLocation, 0);\n\n        ratio = getVerticalTexelOffsetRatio();\n        filter = getFilters().get(1);\n        texelWidthOffsetLocation = GLES20.glGetUniformLocation(filter.getProgram(), \"texelWidthOffset\");\n        texelHeightOffsetLocation = GLES20.glGetUniformLocation(filter.getProgram(), \"texelHeightOffset\");\n        filter.setFloat(texelWidthOffsetLocation, 0);\n        filter.setFloat(texelHeightOffsetLocation, ratio / getOutputHeight());\n    }\n\n    @Override\n    public void onOutputSizeChanged(int width, int height) {\n        super.onOutputSizeChanged(width, height);\n        initTexelOffsets();\n    }\n\n    public float getVerticalTexelOffsetRatio() {\n        return 1f;\n    }\n\n    public float getHorizontalTexelOffsetRatio() {\n        return 1f;\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageVibranceFilter.java",
    "content": "package jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\npublic class GPUImageVibranceFilter extends GPUImageFilter {\n    public static final String VIBRANCE_FRAGMENT_SHADER = \"\" +\n            \"varying highp vec2 textureCoordinate;\\n\" +\n            \"\\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"uniform lowp float vibrance;\\n\" +\n            \"\\n\" +\n            \"void main() {\\n\" +\n            \"    lowp vec4 color = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"    lowp float average = (color.r + color.g + color.b) / 3.0;\\n\" +\n            \"    lowp float mx = max(color.r, max(color.g, color.b));\\n\" +\n            \"    lowp float amt = (mx - average) * (-vibrance * 3.0);\\n\" +\n            \"    color.rgb = mix(color.rgb, vec3(mx), amt);\\n\" +\n            \"    gl_FragColor = color;\\n\" +\n            \"}\";\n\n    private int vibranceLocation;\n    private float vibrance;\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        vibranceLocation = GLES20.glGetUniformLocation(getProgram(), \"vibrance\");\n    }\n\n    public GPUImageVibranceFilter() {\n        this(0f);\n    }\n\n    public GPUImageVibranceFilter(float vibrance) {\n        super(NO_FILTER_VERTEX_SHADER, VIBRANCE_FRAGMENT_SHADER);\n        this.vibrance = vibrance;\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setVibrance(vibrance);\n    }\n\n    public void setVibrance(final float vibrance) {\n        this.vibrance = vibrance;\n        if (isInitialized()) {\n            setFloat(vibranceLocation, vibrance);\n        }\n    }\n}\n\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageVignetteFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.graphics.PointF;\nimport android.opengl.GLES20;\n\n/**\n * Performs a vignetting effect, fading out the image at the edges\n * x:\n * y: The directional intensity of the vignetting, with a default of x = 0.75, y = 0.5\n */\npublic class GPUImageVignetteFilter extends GPUImageFilter {\n    public static final String VIGNETTING_FRAGMENT_SHADER = \"\" +\n            \" uniform sampler2D inputImageTexture;\\n\" +\n            \" varying highp vec2 textureCoordinate;\\n\" +\n            \" \\n\" +\n            \" uniform lowp vec2 vignetteCenter;\\n\" +\n            \" uniform lowp vec3 vignetteColor;\\n\" +\n            \" uniform highp float vignetteStart;\\n\" +\n            \" uniform highp float vignetteEnd;\\n\" +\n            \" \\n\" +\n            \" void main()\\n\" +\n            \" {\\n\" +\n            \"     /*\\n\" +\n            \"     lowp vec3 rgb = texture2D(inputImageTexture, textureCoordinate).rgb;\\n\" +\n            \"     lowp float d = distance(textureCoordinate, vec2(0.5,0.5));\\n\" +\n            \"     rgb *= (1.0 - smoothstep(vignetteStart, vignetteEnd, d));\\n\" +\n            \"     gl_FragColor = vec4(vec3(rgb),1.0);\\n\" +\n            \"      */\\n\" +\n            \"     \\n\" +\n            \"     lowp vec3 rgb = texture2D(inputImageTexture, textureCoordinate).rgb;\\n\" +\n            \"     lowp float d = distance(textureCoordinate, vec2(vignetteCenter.x, vignetteCenter.y));\\n\" +\n            \"     lowp float percent = smoothstep(vignetteStart, vignetteEnd, d);\\n\" +\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\" +\n            \" }\";\n\n    private int vignetteCenterLocation;\n    private PointF vignetteCenter;\n    private int vignetteColorLocation;\n    private float[] vignetteColor;\n    private int vignetteStartLocation;\n    private float vignetteStart;\n    private int vignetteEndLocation;\n    private float vignetteEnd;\n\n    public GPUImageVignetteFilter() {\n        this(new PointF(), new float[]{0.0f, 0.0f, 0.0f}, 0.3f, 0.75f);\n    }\n\n    public GPUImageVignetteFilter(final PointF vignetteCenter, final float[] vignetteColor, final float vignetteStart, final float vignetteEnd) {\n        super(NO_FILTER_VERTEX_SHADER, VIGNETTING_FRAGMENT_SHADER);\n        this.vignetteCenter = vignetteCenter;\n        this.vignetteColor = vignetteColor;\n        this.vignetteStart = vignetteStart;\n        this.vignetteEnd = vignetteEnd;\n\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        vignetteCenterLocation = GLES20.glGetUniformLocation(getProgram(), \"vignetteCenter\");\n        vignetteColorLocation = GLES20.glGetUniformLocation(getProgram(), \"vignetteColor\");\n        vignetteStartLocation = GLES20.glGetUniformLocation(getProgram(), \"vignetteStart\");\n        vignetteEndLocation = GLES20.glGetUniformLocation(getProgram(), \"vignetteEnd\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setVignetteCenter(vignetteCenter);\n        setVignetteColor(vignetteColor);\n        setVignetteStart(vignetteStart);\n        setVignetteEnd(vignetteEnd);\n    }\n\n    public void setVignetteCenter(final PointF vignetteCenter) {\n        this.vignetteCenter = vignetteCenter;\n        setPoint(vignetteCenterLocation, this.vignetteCenter);\n    }\n\n    public void setVignetteColor(final float[] vignetteColor) {\n        this.vignetteColor = vignetteColor;\n        setFloatVec3(vignetteColorLocation, this.vignetteColor);\n    }\n\n    public void setVignetteStart(final float vignetteStart) {\n        this.vignetteStart = vignetteStart;\n        setFloat(vignetteStartLocation, this.vignetteStart);\n    }\n\n    public void setVignetteEnd(final float vignetteEnd) {\n        this.vignetteEnd = vignetteEnd;\n        setFloat(vignetteEndLocation, this.vignetteEnd);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageWeakPixelInclusionFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\npublic class GPUImageWeakPixelInclusionFilter extends GPUImage3x3TextureSamplingFilter {\n    public static final String WEAKPIXEL_FRAGMENT_SHADER = \"\" +\n            \"precision lowp float;\\n\" +\n            \"\\n\" +\n            \"varying vec2 textureCoordinate;\\n\" +\n            \"varying vec2 leftTextureCoordinate;\\n\" +\n            \"varying vec2 rightTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"varying vec2 topTextureCoordinate;\\n\" +\n            \"varying vec2 topLeftTextureCoordinate;\\n\" +\n            \"varying vec2 topRightTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"varying vec2 bottomTextureCoordinate;\\n\" +\n            \"varying vec2 bottomLeftTextureCoordinate;\\n\" +\n            \"varying vec2 bottomRightTextureCoordinate;\\n\" +\n            \"\\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"\\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"float bottomLeftIntensity = texture2D(inputImageTexture, bottomLeftTextureCoordinate).r;\\n\" +\n            \"float topRightIntensity = texture2D(inputImageTexture, topRightTextureCoordinate).r;\\n\" +\n            \"float topLeftIntensity = texture2D(inputImageTexture, topLeftTextureCoordinate).r;\\n\" +\n            \"float bottomRightIntensity = texture2D(inputImageTexture, bottomRightTextureCoordinate).r;\\n\" +\n            \"float leftIntensity = texture2D(inputImageTexture, leftTextureCoordinate).r;\\n\" +\n            \"float rightIntensity = texture2D(inputImageTexture, rightTextureCoordinate).r;\\n\" +\n            \"float bottomIntensity = texture2D(inputImageTexture, bottomTextureCoordinate).r;\\n\" +\n            \"float topIntensity = texture2D(inputImageTexture, topTextureCoordinate).r;\\n\" +\n            \"float centerIntensity = texture2D(inputImageTexture, textureCoordinate).r;\\n\" +\n            \"\\n\" +\n            \"float pixelIntensitySum = bottomLeftIntensity + topRightIntensity + topLeftIntensity + bottomRightIntensity + leftIntensity + rightIntensity + bottomIntensity + topIntensity + centerIntensity;\\n\" +\n            \"float sumTest = step(1.5, pixelIntensitySum);\\n\" +\n            \"float pixelTest = step(0.01, centerIntensity);\\n\" +\n            \"\\n\" +\n            \"gl_FragColor = vec4(vec3(sumTest * pixelTest), 1.0);\\n\" +\n            \"}\\n\";\n\n    public GPUImageWeakPixelInclusionFilter() {\n        super(WEAKPIXEL_FRAGMENT_SHADER);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageWhiteBalanceFilter.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.opengl.GLES20;\n\n/**\n * Adjusts the white balance of incoming image. <br>\n * <br>\n * temperature:\n * tint:\n */\npublic class GPUImageWhiteBalanceFilter extends GPUImageFilter {\n    public static final String WHITE_BALANCE_FRAGMENT_SHADER = \"\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"varying highp vec2 textureCoordinate;\\n\" +\n            \" \\n\" +\n            \"uniform lowp float temperature;\\n\" +\n            \"uniform lowp float tint;\\n\" +\n            \"\\n\" +\n            \"const lowp vec3 warmFilter = vec3(0.93, 0.54, 0.0);\\n\" +\n            \"\\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\" +\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            \"\\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"\tlowp vec4 source = texture2D(inputImageTexture, textureCoordinate);\\n\" +\n            \"\t\\n\" +\n            \"\tmediump vec3 yiq = RGBtoYIQ * source.rgb; //adjusting tint\\n\" +\n            \"\tyiq.b = clamp(yiq.b + tint*0.5226*0.1, -0.5226, 0.5226);\\n\" +\n            \"\tlowp vec3 rgb = YIQtoRGB * yiq;\\n\" +\n            \"\\n\" +\n            \"\tlowp vec3 processed = vec3(\\n\" +\n            \"\t\t(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\" +\n            \"\t\t(rgb.g < 0.5 ? (2.0 * rgb.g * warmFilter.g) : (1.0 - 2.0 * (1.0 - rgb.g) * (1.0 - warmFilter.g))), \\n\" +\n            \"\t\t(rgb.b < 0.5 ? (2.0 * rgb.b * warmFilter.b) : (1.0 - 2.0 * (1.0 - rgb.b) * (1.0 - warmFilter.b))));\\n\" +\n            \"\\n\" +\n            \"\tgl_FragColor = vec4(mix(rgb, processed, temperature), source.a);\\n\" +\n            \"}\";\n\n    private int temperatureLocation;\n    private float temperature;\n    private int tintLocation;\n    private float tint;\n\n    public GPUImageWhiteBalanceFilter() {\n        this(5000.0f, 0.0f);\n    }\n\n    public GPUImageWhiteBalanceFilter(final float temperature, final float tint) {\n        super(NO_FILTER_VERTEX_SHADER, WHITE_BALANCE_FRAGMENT_SHADER);\n        this.temperature = temperature;\n        this.tint = tint;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        temperatureLocation = GLES20.glGetUniformLocation(getProgram(), \"temperature\");\n        tintLocation = GLES20.glGetUniformLocation(getProgram(), \"tint\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setTemperature(temperature);\n        setTint(tint);\n    }\n\n    public void setTemperature(final float temperature) {\n        this.temperature = temperature;\n        setFloat(temperatureLocation, this.temperature < 5000 ? (float) (0.0004 * (this.temperature - 5000.0)) : (float) (0.00006 * (this.temperature - 5000.0)));\n    }\n\n    public void setTint(final float tint) {\n        this.tint = tint;\n        setFloat(tintLocation, (float) (this.tint / 100.0));\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/filter/GPUImageZoomBlurFilter.java",
    "content": "package jp.co.cyberagent.android.gpuimage.filter;\n\nimport android.graphics.PointF;\nimport android.opengl.GLES20;\n\npublic class GPUImageZoomBlurFilter extends GPUImageFilter {\n    public static final String ZOOM_BLUR_FRAGMENT_SHADER = \"\" +\n            \"varying highp vec2 textureCoordinate;\\n\" +\n            \"\\n\" +\n            \"uniform sampler2D inputImageTexture;\\n\" +\n            \"\\n\" +\n            \"uniform highp vec2 blurCenter;\\n\" +\n            \"uniform highp float blurSize;\\n\" +\n            \"\\n\" +\n            \"void main()\\n\" +\n            \"{\\n\" +\n            \"    // TODO: Do a more intelligent scaling based on resolution here\\n\" +\n            \"    highp vec2 samplingOffset = 1.0/100.0 * (blurCenter - textureCoordinate) * blurSize;\\n\" +\n            \"    \\n\" +\n            \"    lowp vec4 fragmentColor = texture2D(inputImageTexture, textureCoordinate) * 0.18;\\n\" +\n            \"    fragmentColor += texture2D(inputImageTexture, textureCoordinate + samplingOffset) * 0.15;\\n\" +\n            \"    fragmentColor += texture2D(inputImageTexture, textureCoordinate + (2.0 * samplingOffset)) *  0.12;\\n\" +\n            \"    fragmentColor += texture2D(inputImageTexture, textureCoordinate + (3.0 * samplingOffset)) * 0.09;\\n\" +\n            \"    fragmentColor += texture2D(inputImageTexture, textureCoordinate + (4.0 * samplingOffset)) * 0.05;\\n\" +\n            \"    fragmentColor += texture2D(inputImageTexture, textureCoordinate - samplingOffset) * 0.15;\\n\" +\n            \"    fragmentColor += texture2D(inputImageTexture, textureCoordinate - (2.0 * samplingOffset)) *  0.12;\\n\" +\n            \"    fragmentColor += texture2D(inputImageTexture, textureCoordinate - (3.0 * samplingOffset)) * 0.09;\\n\" +\n            \"    fragmentColor += texture2D(inputImageTexture, textureCoordinate - (4.0 * samplingOffset)) * 0.05;\\n\" +\n            \"    \\n\" +\n            \"    gl_FragColor = fragmentColor;\\n\" +\n            \"}\\n\";\n\n    private PointF blurCenter;\n    private int blurCenterLocation;\n    private float blurSize;\n    private int blurSizeLocation;\n\n    public GPUImageZoomBlurFilter() {\n        this(new PointF(0.5f, 0.5f), 1.0f);\n    }\n\n    public GPUImageZoomBlurFilter(PointF blurCenter, float blurSize) {\n        super(NO_FILTER_VERTEX_SHADER, ZOOM_BLUR_FRAGMENT_SHADER);\n        this.blurCenter = blurCenter;\n        this.blurSize = blurSize;\n    }\n\n    @Override\n    public void onInit() {\n        super.onInit();\n        blurCenterLocation = GLES20.glGetUniformLocation(getProgram(), \"blurCenter\");\n        blurSizeLocation = GLES20.glGetUniformLocation(getProgram(), \"blurSize\");\n    }\n\n    @Override\n    public void onInitialized() {\n        super.onInitialized();\n        setBlurCenter(blurCenter);\n        setBlurSize(blurSize);\n    }\n\n    public void setBlurCenter(final PointF blurCenter) {\n        this.blurCenter = blurCenter;\n        setPoint(blurCenterLocation, blurCenter);\n    }\n\n    public void setBlurSize(final float blurSize) {\n        this.blurSize = blurSize;\n        setFloat(blurSizeLocation, blurSize);\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/util/OpenGlUtils.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.util;\n\nimport android.graphics.Bitmap;\nimport android.graphics.Bitmap.Config;\nimport android.hardware.Camera.Size;\nimport android.opengl.GLES20;\nimport android.opengl.GLUtils;\nimport android.util.Log;\n\nimport java.nio.IntBuffer;\n\npublic class OpenGlUtils {\n    public static final int NO_TEXTURE = -1;\n\n    public static int loadTexture(final Bitmap img, final int usedTexId) {\n        return loadTexture(img, usedTexId, true);\n    }\n\n    public static int loadTexture(final Bitmap img, final int usedTexId, final boolean recycle) {\n        int textures[] = new int[1];\n        if (usedTexId == NO_TEXTURE) {\n            GLES20.glGenTextures(1, textures, 0);\n            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);\n            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,\n                    GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);\n            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,\n                    GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);\n            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,\n                    GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);\n            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,\n                    GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);\n\n            GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, img, 0);\n        } else {\n            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, usedTexId);\n            GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, img);\n            textures[0] = usedTexId;\n        }\n        if (recycle) {\n            img.recycle();\n        }\n        return textures[0];\n    }\n\n    public static int loadTexture(final IntBuffer data, final int width, final int height, final int usedTexId) {\n        int textures[] = new int[1];\n        if (usedTexId == NO_TEXTURE) {\n            GLES20.glGenTextures(1, textures, 0);\n            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);\n            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,\n                    GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);\n            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,\n                    GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);\n            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,\n                    GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);\n            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,\n                    GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);\n            GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height,\n                    0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, data);\n        } else {\n            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, usedTexId);\n            GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, width,\n                    height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, data);\n            textures[0] = usedTexId;\n        }\n        return textures[0];\n    }\n\n    public static int loadTextureAsBitmap(final IntBuffer data, final Size size, final int usedTexId) {\n        Bitmap bitmap = Bitmap\n                .createBitmap(data.array(), size.width, size.height, Config.ARGB_8888);\n        return loadTexture(bitmap, usedTexId);\n    }\n\n    public static int loadShader(final String strSource, final int iType) {\n        int[] compiled = new int[1];\n        int iShader = GLES20.glCreateShader(iType);\n        GLES20.glShaderSource(iShader, strSource);\n        GLES20.glCompileShader(iShader);\n        GLES20.glGetShaderiv(iShader, GLES20.GL_COMPILE_STATUS, compiled, 0);\n        if (compiled[0] == 0) {\n            Log.d(\"Load Shader Failed\", \"Compilation\\n\" + GLES20.glGetShaderInfoLog(iShader));\n            return 0;\n        }\n        return iShader;\n    }\n\n    public static int loadProgram(final String strVSource, final String strFSource) {\n        int iVShader;\n        int iFShader;\n        int iProgId;\n        int[] link = new int[1];\n        iVShader = loadShader(strVSource, GLES20.GL_VERTEX_SHADER);\n        if (iVShader == 0) {\n            Log.d(\"Load Program\", \"Vertex Shader Failed\");\n            return 0;\n        }\n        iFShader = loadShader(strFSource, GLES20.GL_FRAGMENT_SHADER);\n        if (iFShader == 0) {\n            Log.d(\"Load Program\", \"Fragment Shader Failed\");\n            return 0;\n        }\n\n        iProgId = GLES20.glCreateProgram();\n\n        GLES20.glAttachShader(iProgId, iVShader);\n        GLES20.glAttachShader(iProgId, iFShader);\n\n        GLES20.glLinkProgram(iProgId);\n\n        GLES20.glGetProgramiv(iProgId, GLES20.GL_LINK_STATUS, link, 0);\n        if (link[0] <= 0) {\n            Log.d(\"Load Program\", \"Linking Failed\");\n            return 0;\n        }\n        GLES20.glDeleteShader(iVShader);\n        GLES20.glDeleteShader(iFShader);\n        return iProgId;\n    }\n\n    public static float rnd(final float min, final float max) {\n        float fRandNum = (float) Math.random();\n        return min + (max - min) * fRandNum;\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/util/Rotation.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.util;\n\npublic enum Rotation {\n    NORMAL, ROTATION_90, ROTATION_180, ROTATION_270;\n\n    /**\n     * Retrieves the int representation of the Rotation.\n     *\n     * @return 0, 90, 180 or 270\n     */\n    public int asInt() {\n        switch (this) {\n            case NORMAL:\n                return 0;\n            case ROTATION_90:\n                return 90;\n            case ROTATION_180:\n                return 180;\n            case ROTATION_270:\n                return 270;\n            default:\n                throw new IllegalStateException(\"Unknown Rotation!\");\n        }\n    }\n\n    /**\n     * Create a Rotation from an integer. Needs to be either 0, 90, 180 or 270.\n     *\n     * @param rotation 0, 90, 180 or 270\n     * @return Rotation object\n     */\n    public static Rotation fromInt(int rotation) {\n        switch (rotation) {\n            case 0:\n                return NORMAL;\n            case 90:\n                return ROTATION_90;\n            case 180:\n                return ROTATION_180;\n            case 270:\n                return ROTATION_270;\n            case 360:\n                return NORMAL;\n            default:\n                throw new IllegalStateException(\n                        rotation + \" is an unknown rotation. Needs to be either 0, 90, 180 or 270!\");\n        }\n    }\n}\n"
  },
  {
    "path": "library/src/main/java/jp/co/cyberagent/android/gpuimage/util/TextureRotationUtil.java",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.util;\n\npublic class TextureRotationUtil {\n\n    public static final float TEXTURE_NO_ROTATION[] = {\n            0.0f, 1.0f,\n            1.0f, 1.0f,\n            0.0f, 0.0f,\n            1.0f, 0.0f,\n    };\n\n    public static final float TEXTURE_ROTATED_90[] = {\n            1.0f, 1.0f,\n            1.0f, 0.0f,\n            0.0f, 1.0f,\n            0.0f, 0.0f,\n    };\n    public static final float TEXTURE_ROTATED_180[] = {\n            1.0f, 0.0f,\n            0.0f, 0.0f,\n            1.0f, 1.0f,\n            0.0f, 1.0f,\n    };\n    public static final float TEXTURE_ROTATED_270[] = {\n            0.0f, 0.0f,\n            0.0f, 1.0f,\n            1.0f, 0.0f,\n            1.0f, 1.0f,\n    };\n\n    private TextureRotationUtil() {\n    }\n\n    public static float[] getRotation(final Rotation rotation, final boolean flipHorizontal,\n                                      final boolean flipVertical) {\n        float[] rotatedTex;\n        switch (rotation) {\n            case ROTATION_90:\n                rotatedTex = TEXTURE_ROTATED_90;\n                break;\n            case ROTATION_180:\n                rotatedTex = TEXTURE_ROTATED_180;\n                break;\n            case ROTATION_270:\n                rotatedTex = TEXTURE_ROTATED_270;\n                break;\n            case NORMAL:\n            default:\n                rotatedTex = TEXTURE_NO_ROTATION;\n                break;\n        }\n        if (flipHorizontal) {\n            rotatedTex = new float[]{\n                    flip(rotatedTex[0]), rotatedTex[1],\n                    flip(rotatedTex[2]), rotatedTex[3],\n                    flip(rotatedTex[4]), rotatedTex[5],\n                    flip(rotatedTex[6]), rotatedTex[7],\n            };\n        }\n        if (flipVertical) {\n            rotatedTex = new float[]{\n                    rotatedTex[0], flip(rotatedTex[1]),\n                    rotatedTex[2], flip(rotatedTex[3]),\n                    rotatedTex[4], flip(rotatedTex[5]),\n                    rotatedTex[6], flip(rotatedTex[7]),\n            };\n        }\n        return rotatedTex;\n    }\n\n\n    private static float flip(final float i) {\n        if (i == 0.0f) {\n            return 1.0f;\n        }\n        return 0.0f;\n    }\n}\n"
  },
  {
    "path": "library/src/main/res/values/attrs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <declare-styleable name=\"GPUImageView\">\n        <attr name=\"gpuimage_surface_type\" format=\"enum\">\n            <enum name=\"surface_view\" value=\"0\" />\n            <enum name=\"texture_view\" value=\"1\" />\n        </attr>\n        <attr name=\"gpuimage_show_loading\" format=\"boolean\"/>\n    </declare-styleable>\n</resources>"
  },
  {
    "path": "sample/build.gradle",
    "content": "apply plugin: 'com.android.application'\napply plugin: 'kotlin-android-extensions'\napply plugin: 'kotlin-android'\n\nandroid {\n    compileSdkVersion COMPILE_SDK_VERSION as int\n\n    defaultConfig {\n        minSdkVersion MIN_SDK_VERSION as int\n        targetSdkVersion TARGET_SDK_VERSION as int\n\n        versionCode = VERSION_CODE as int\n        versionName = VERSION_NAME\n    }\n\n    buildTypes {\n        debug {\n            debuggable true\n        }\n        release {\n            debuggable false\n            zipAlignEnabled true\n            minifyEnabled true\n            shrinkResources true\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\nrepositories {\n//     maven { url = \"https://oss.sonatype.org/content/repositories/snapshots\"}\n}\n\ndependencies {\n    implementation project(':library')\n    implementation 'androidx.appcompat:appcompat:1.2.0'\n    implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version\"\n}"
  },
  {
    "path": "sample/proguard-project.txt",
    "content": "# To enable ProGuard in your project, edit project.properties\n# to define the proguard.config property as described in that file.\n#\n# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in ${sdk.dir}/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the ProGuard\n# include property in project.properties.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "sample/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    package=\"jp.co.cyberagent.android.gpuimage.sample\">\n\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n    <uses-permission android:name=\"android.permission.CAMERA\" />\n\n    <!-- For images from picasa -->\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n\n    <uses-feature android:name=\"android.hardware.camera\" />\n    <uses-feature\n        android:name=\"android.hardware.camera.autofocus\"\n        android:required=\"false\" />\n\n    <application\n        android:allowBackup=\"false\"\n        android:hardwareAccelerated=\"true\"\n        android:icon=\"@drawable/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:largeHeap=\"true\"\n        android:theme=\"@style/AppTheme\"\n        tools:ignore=\"GoogleAppIndexingWarning\">\n        <activity\n            android:name=\".activity.MainActivity\"\n            android:label=\"@string/title_activity_activity_main\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n        <activity android:name=\".activity.GalleryActivity\" />\n        <activity\n            android:name=\".activity.CameraActivity\"\n            android:screenOrientation=\"portrait\"\n            android:theme=\"@style/AppTheme.NoActionBar\" />\n    </application>\n\n</manifest>"
  },
  {
    "path": "sample/src/main/java/jp/co/cyberagent/android/gpuimage/sample/GPUImageFilterTools.kt",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.sample\n\nimport android.app.AlertDialog\nimport android.content.Context\nimport android.graphics.BitmapFactory\nimport android.graphics.PointF\nimport android.opengl.Matrix\nimport jp.co.cyberagent.android.gpuimage.filter.*\nimport java.util.*\n\nobject GPUImageFilterTools {\n    fun showDialog(\n        context: Context,\n        listener: (filter: GPUImageFilter) -> Unit\n    ) {\n        val filters = FilterList().apply {\n            addFilter(\"Contrast\", FilterType.CONTRAST)\n            addFilter(\"Invert\", FilterType.INVERT)\n            addFilter(\"Pixelation\", FilterType.PIXELATION)\n            addFilter(\"Hue\", FilterType.HUE)\n            addFilter(\"Gamma\", FilterType.GAMMA)\n            addFilter(\"Brightness\", FilterType.BRIGHTNESS)\n            addFilter(\"Sepia\", FilterType.SEPIA)\n            addFilter(\"Grayscale\", FilterType.GRAYSCALE)\n            addFilter(\"Sharpness\", FilterType.SHARPEN)\n            addFilter(\"Sobel Edge Detection\", FilterType.SOBEL_EDGE_DETECTION)\n            addFilter(\"Threshold Edge Detection\", FilterType.THRESHOLD_EDGE_DETECTION)\n            addFilter(\"3x3 Convolution\", FilterType.THREE_X_THREE_CONVOLUTION)\n            addFilter(\"Emboss\", FilterType.EMBOSS)\n            addFilter(\"Posterize\", FilterType.POSTERIZE)\n            addFilter(\"Grouped filters\", FilterType.FILTER_GROUP)\n            addFilter(\"Saturation\", FilterType.SATURATION)\n            addFilter(\"Exposure\", FilterType.EXPOSURE)\n            addFilter(\"Highlight Shadow\", FilterType.HIGHLIGHT_SHADOW)\n            addFilter(\"Monochrome\", FilterType.MONOCHROME)\n            addFilter(\"Opacity\", FilterType.OPACITY)\n            addFilter(\"RGB\", FilterType.RGB)\n            addFilter(\"White Balance\", FilterType.WHITE_BALANCE)\n            addFilter(\"Vignette\", FilterType.VIGNETTE)\n            addFilter(\"ToneCurve\", FilterType.TONE_CURVE)\n\n            addFilter(\"Luminance\", FilterType.LUMINANCE)\n            addFilter(\"Luminance Threshold\", FilterType.LUMINANCE_THRESHSOLD)\n\n            addFilter(\"Blend (Difference)\", FilterType.BLEND_DIFFERENCE)\n            addFilter(\"Blend (Source Over)\", FilterType.BLEND_SOURCE_OVER)\n            addFilter(\"Blend (Color Burn)\", FilterType.BLEND_COLOR_BURN)\n            addFilter(\"Blend (Color Dodge)\", FilterType.BLEND_COLOR_DODGE)\n            addFilter(\"Blend (Darken)\", FilterType.BLEND_DARKEN)\n            addFilter(\"Blend (Dissolve)\", FilterType.BLEND_DISSOLVE)\n            addFilter(\"Blend (Exclusion)\", FilterType.BLEND_EXCLUSION)\n            addFilter(\"Blend (Hard Light)\", FilterType.BLEND_HARD_LIGHT)\n            addFilter(\"Blend (Lighten)\", FilterType.BLEND_LIGHTEN)\n            addFilter(\"Blend (Add)\", FilterType.BLEND_ADD)\n            addFilter(\"Blend (Divide)\", FilterType.BLEND_DIVIDE)\n            addFilter(\"Blend (Multiply)\", FilterType.BLEND_MULTIPLY)\n            addFilter(\"Blend (Overlay)\", FilterType.BLEND_OVERLAY)\n            addFilter(\"Blend (Screen)\", FilterType.BLEND_SCREEN)\n            addFilter(\"Blend (Alpha)\", FilterType.BLEND_ALPHA)\n            addFilter(\"Blend (Color)\", FilterType.BLEND_COLOR)\n            addFilter(\"Blend (Hue)\", FilterType.BLEND_HUE)\n            addFilter(\"Blend (Saturation)\", FilterType.BLEND_SATURATION)\n            addFilter(\"Blend (Luminosity)\", FilterType.BLEND_LUMINOSITY)\n            addFilter(\"Blend (Linear Burn)\", FilterType.BLEND_LINEAR_BURN)\n            addFilter(\"Blend (Soft Light)\", FilterType.BLEND_SOFT_LIGHT)\n            addFilter(\"Blend (Subtract)\", FilterType.BLEND_SUBTRACT)\n            addFilter(\"Blend (Chroma Key)\", FilterType.BLEND_CHROMA_KEY)\n            addFilter(\"Blend (Normal)\", FilterType.BLEND_NORMAL)\n\n            addFilter(\"Lookup (Amatorka)\", FilterType.LOOKUP_AMATORKA)\n            addFilter(\"Gaussian Blur\", FilterType.GAUSSIAN_BLUR)\n            addFilter(\"Crosshatch\", FilterType.CROSSHATCH)\n\n            addFilter(\"Box Blur\", FilterType.BOX_BLUR)\n            addFilter(\"CGA Color Space\", FilterType.CGA_COLORSPACE)\n            addFilter(\"Dilation\", FilterType.DILATION)\n            addFilter(\"Kuwahara\", FilterType.KUWAHARA)\n            addFilter(\"RGB Dilation\", FilterType.RGB_DILATION)\n            addFilter(\"Sketch\", FilterType.SKETCH)\n            addFilter(\"Toon\", FilterType.TOON)\n            addFilter(\"Smooth Toon\", FilterType.SMOOTH_TOON)\n            addFilter(\"Halftone\", FilterType.HALFTONE)\n\n            addFilter(\"Bulge Distortion\", FilterType.BULGE_DISTORTION)\n            addFilter(\"Glass Sphere\", FilterType.GLASS_SPHERE)\n            addFilter(\"Haze\", FilterType.HAZE)\n            addFilter(\"Laplacian\", FilterType.LAPLACIAN)\n            addFilter(\"Non Maximum Suppression\", FilterType.NON_MAXIMUM_SUPPRESSION)\n            addFilter(\"Sphere Refraction\", FilterType.SPHERE_REFRACTION)\n            addFilter(\"Swirl\", FilterType.SWIRL)\n            addFilter(\"Weak Pixel Inclusion\", FilterType.WEAK_PIXEL_INCLUSION)\n            addFilter(\"False Color\", FilterType.FALSE_COLOR)\n\n            addFilter(\"Color Balance\", FilterType.COLOR_BALANCE)\n\n            addFilter(\"Levels Min (Mid Adjust)\", FilterType.LEVELS_FILTER_MIN)\n\n            addFilter(\"Bilateral Blur\", FilterType.BILATERAL_BLUR)\n\n            addFilter(\"Zoom Blur\", FilterType.ZOOM_BLUR)\n\n            addFilter(\"Transform (2-D)\", FilterType.TRANSFORM2D)\n\n            addFilter(\"Solarize\", FilterType.SOLARIZE)\n\n            addFilter(\"Vibrance\", FilterType.VIBRANCE)\n        }\n\n        val builder = AlertDialog.Builder(context)\n        builder.setTitle(\"Choose a filter\")\n        builder.setItems(filters.names.toTypedArray()) { _, item ->\n            listener(createFilterForType(context, filters.filters[item]))\n        }\n        builder.create().show()\n    }\n\n    private fun createFilterForType(context: Context, type: FilterType): GPUImageFilter {\n        return when (type) {\n            FilterType.CONTRAST -> GPUImageContrastFilter(2.0f)\n            FilterType.GAMMA -> GPUImageGammaFilter(2.0f)\n            FilterType.INVERT -> GPUImageColorInvertFilter()\n            FilterType.PIXELATION -> GPUImagePixelationFilter()\n            FilterType.HUE -> GPUImageHueFilter(90.0f)\n            FilterType.BRIGHTNESS -> GPUImageBrightnessFilter(1.5f)\n            FilterType.GRAYSCALE -> GPUImageGrayscaleFilter()\n            FilterType.SEPIA -> GPUImageSepiaToneFilter()\n            FilterType.SHARPEN -> GPUImageSharpenFilter()\n            FilterType.SOBEL_EDGE_DETECTION -> GPUImageSobelEdgeDetectionFilter()\n            FilterType.THRESHOLD_EDGE_DETECTION -> GPUImageThresholdEdgeDetectionFilter()\n            FilterType.THREE_X_THREE_CONVOLUTION -> GPUImage3x3ConvolutionFilter()\n            FilterType.EMBOSS -> GPUImageEmbossFilter()\n            FilterType.POSTERIZE -> GPUImagePosterizeFilter()\n            FilterType.FILTER_GROUP -> GPUImageFilterGroup(\n                listOf(\n                    GPUImageContrastFilter(),\n                    GPUImageDirectionalSobelEdgeDetectionFilter(),\n                    GPUImageGrayscaleFilter()\n                )\n            )\n            FilterType.SATURATION -> GPUImageSaturationFilter(1.0f)\n            FilterType.EXPOSURE -> GPUImageExposureFilter(0.0f)\n            FilterType.HIGHLIGHT_SHADOW -> GPUImageHighlightShadowFilter(\n                0.0f,\n                1.0f\n            )\n            FilterType.MONOCHROME -> GPUImageMonochromeFilter(\n                1.0f, floatArrayOf(0.6f, 0.45f, 0.3f, 1.0f)\n            )\n            FilterType.OPACITY -> GPUImageOpacityFilter(1.0f)\n            FilterType.RGB -> GPUImageRGBFilter(1.0f, 1.0f, 1.0f)\n            FilterType.WHITE_BALANCE -> GPUImageWhiteBalanceFilter(\n                5000.0f,\n                0.0f\n            )\n            FilterType.VIGNETTE -> GPUImageVignetteFilter(\n                PointF(0.5f, 0.5f),\n                floatArrayOf(0.0f, 0.0f, 0.0f),\n                0.3f,\n                0.75f\n            )\n            FilterType.TONE_CURVE -> GPUImageToneCurveFilter().apply {\n                setFromCurveFileInputStream(context.resources.openRawResource(R.raw.tone_cuver_sample))\n            }\n            FilterType.LUMINANCE -> GPUImageLuminanceFilter()\n            FilterType.LUMINANCE_THRESHSOLD -> GPUImageLuminanceThresholdFilter(0.5f)\n            FilterType.BLEND_DIFFERENCE -> createBlendFilter(\n                context,\n                GPUImageDifferenceBlendFilter::class.java\n            )\n            FilterType.BLEND_SOURCE_OVER -> createBlendFilter(\n                context,\n                GPUImageSourceOverBlendFilter::class.java\n            )\n            FilterType.BLEND_COLOR_BURN -> createBlendFilter(\n                context,\n                GPUImageColorBurnBlendFilter::class.java\n            )\n            FilterType.BLEND_COLOR_DODGE -> createBlendFilter(\n                context,\n                GPUImageColorDodgeBlendFilter::class.java\n            )\n            FilterType.BLEND_DARKEN -> createBlendFilter(\n                context,\n                GPUImageDarkenBlendFilter::class.java\n            )\n            FilterType.BLEND_DISSOLVE -> createBlendFilter(\n                context,\n                GPUImageDissolveBlendFilter::class.java\n            )\n            FilterType.BLEND_EXCLUSION -> createBlendFilter(\n                context,\n                GPUImageExclusionBlendFilter::class.java\n            )\n\n            FilterType.BLEND_HARD_LIGHT -> createBlendFilter(\n                context,\n                GPUImageHardLightBlendFilter::class.java\n            )\n            FilterType.BLEND_LIGHTEN -> createBlendFilter(\n                context,\n                GPUImageLightenBlendFilter::class.java\n            )\n            FilterType.BLEND_ADD -> createBlendFilter(\n                context,\n                GPUImageAddBlendFilter::class.java\n            )\n            FilterType.BLEND_DIVIDE -> createBlendFilter(\n                context,\n                GPUImageDivideBlendFilter::class.java\n            )\n            FilterType.BLEND_MULTIPLY -> createBlendFilter(\n                context,\n                GPUImageMultiplyBlendFilter::class.java\n            )\n            FilterType.BLEND_OVERLAY -> createBlendFilter(\n                context,\n                GPUImageOverlayBlendFilter::class.java\n            )\n            FilterType.BLEND_SCREEN -> createBlendFilter(\n                context,\n                GPUImageScreenBlendFilter::class.java\n            )\n            FilterType.BLEND_ALPHA -> createBlendFilter(\n                context,\n                GPUImageAlphaBlendFilter::class.java\n            )\n            FilterType.BLEND_COLOR -> createBlendFilter(\n                context,\n                GPUImageColorBlendFilter::class.java\n            )\n            FilterType.BLEND_HUE -> createBlendFilter(\n                context,\n                GPUImageHueBlendFilter::class.java\n            )\n            FilterType.BLEND_SATURATION -> createBlendFilter(\n                context,\n                GPUImageSaturationBlendFilter::class.java\n            )\n            FilterType.BLEND_LUMINOSITY -> createBlendFilter(\n                context,\n                GPUImageLuminosityBlendFilter::class.java\n            )\n            FilterType.BLEND_LINEAR_BURN -> createBlendFilter(\n                context,\n                GPUImageLinearBurnBlendFilter::class.java\n            )\n            FilterType.BLEND_SOFT_LIGHT -> createBlendFilter(\n                context,\n                GPUImageSoftLightBlendFilter::class.java\n            )\n            FilterType.BLEND_SUBTRACT -> createBlendFilter(\n                context,\n                GPUImageSubtractBlendFilter::class.java\n            )\n            FilterType.BLEND_CHROMA_KEY -> createBlendFilter(\n                context,\n                GPUImageChromaKeyBlendFilter::class.java\n            )\n            FilterType.BLEND_NORMAL -> createBlendFilter(\n                context,\n                GPUImageNormalBlendFilter::class.java\n            )\n\n            FilterType.LOOKUP_AMATORKA -> GPUImageLookupFilter().apply {\n                bitmap = BitmapFactory.decodeResource(context.resources, R.drawable.lookup_amatorka)\n            }\n            FilterType.GAUSSIAN_BLUR -> GPUImageGaussianBlurFilter()\n            FilterType.CROSSHATCH -> GPUImageCrosshatchFilter()\n            FilterType.BOX_BLUR -> GPUImageBoxBlurFilter()\n            FilterType.CGA_COLORSPACE -> GPUImageCGAColorspaceFilter()\n            FilterType.DILATION -> GPUImageDilationFilter()\n            FilterType.KUWAHARA -> GPUImageKuwaharaFilter()\n            FilterType.RGB_DILATION -> GPUImageRGBDilationFilter()\n            FilterType.SKETCH -> GPUImageSketchFilter()\n            FilterType.TOON -> GPUImageToonFilter()\n            FilterType.SMOOTH_TOON -> GPUImageSmoothToonFilter()\n            FilterType.BULGE_DISTORTION -> GPUImageBulgeDistortionFilter()\n            FilterType.GLASS_SPHERE -> GPUImageGlassSphereFilter()\n            FilterType.HAZE -> GPUImageHazeFilter()\n            FilterType.LAPLACIAN -> GPUImageLaplacianFilter()\n            FilterType.NON_MAXIMUM_SUPPRESSION -> GPUImageNonMaximumSuppressionFilter()\n            FilterType.SPHERE_REFRACTION -> GPUImageSphereRefractionFilter()\n            FilterType.SWIRL -> GPUImageSwirlFilter()\n            FilterType.WEAK_PIXEL_INCLUSION -> GPUImageWeakPixelInclusionFilter()\n            FilterType.FALSE_COLOR -> GPUImageFalseColorFilter()\n            FilterType.COLOR_BALANCE -> GPUImageColorBalanceFilter()\n            FilterType.LEVELS_FILTER_MIN -> GPUImageLevelsFilter()\n            FilterType.HALFTONE -> GPUImageHalftoneFilter()\n            FilterType.BILATERAL_BLUR -> GPUImageBilateralBlurFilter()\n            FilterType.ZOOM_BLUR -> GPUImageZoomBlurFilter()\n            FilterType.TRANSFORM2D -> GPUImageTransformFilter()\n            FilterType.SOLARIZE -> GPUImageSolarizeFilter()\n            FilterType.VIBRANCE -> GPUImageVibranceFilter()\n        }\n    }\n\n    private fun createBlendFilter(\n        context: Context,\n        filterClass: Class<out GPUImageTwoInputFilter>\n    ): GPUImageFilter {\n        return try {\n            filterClass.newInstance().apply {\n                bitmap = BitmapFactory.decodeResource(context.resources, R.drawable.ic_launcher)\n            }\n        } catch (e: Exception) {\n            e.printStackTrace()\n            GPUImageFilter()\n        }\n    }\n\n    private enum class FilterType {\n        CONTRAST, GRAYSCALE, SHARPEN, SEPIA, SOBEL_EDGE_DETECTION, THRESHOLD_EDGE_DETECTION, THREE_X_THREE_CONVOLUTION, FILTER_GROUP, EMBOSS, POSTERIZE, GAMMA, BRIGHTNESS, INVERT, HUE, PIXELATION,\n        SATURATION, EXPOSURE, HIGHLIGHT_SHADOW, MONOCHROME, OPACITY, RGB, WHITE_BALANCE, VIGNETTE, TONE_CURVE, LUMINANCE, LUMINANCE_THRESHSOLD, BLEND_COLOR_BURN, BLEND_COLOR_DODGE, BLEND_DARKEN,\n        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,\n        BLEND_COLOR, BLEND_HUE, BLEND_SATURATION, BLEND_LUMINOSITY, BLEND_LINEAR_BURN, BLEND_SOFT_LIGHT, BLEND_SUBTRACT, BLEND_CHROMA_KEY, BLEND_NORMAL, LOOKUP_AMATORKA,\n        GAUSSIAN_BLUR, CROSSHATCH, BOX_BLUR, CGA_COLORSPACE, DILATION, KUWAHARA, RGB_DILATION, SKETCH, TOON, SMOOTH_TOON, BULGE_DISTORTION, GLASS_SPHERE, HAZE, LAPLACIAN, NON_MAXIMUM_SUPPRESSION,\n        SPHERE_REFRACTION, SWIRL, WEAK_PIXEL_INCLUSION, FALSE_COLOR, COLOR_BALANCE, LEVELS_FILTER_MIN, BILATERAL_BLUR, ZOOM_BLUR, HALFTONE, TRANSFORM2D, SOLARIZE, VIBRANCE\n    }\n\n    private class FilterList {\n        val names: MutableList<String> = LinkedList()\n        val filters: MutableList<FilterType> = LinkedList()\n\n        fun addFilter(name: String, filter: FilterType) {\n            names.add(name)\n            filters.add(filter)\n        }\n    }\n\n    class FilterAdjuster(filter: GPUImageFilter) {\n        private val adjuster: Adjuster<out GPUImageFilter>?\n\n        init {\n            adjuster = when (filter) {\n                is GPUImageSharpenFilter -> SharpnessAdjuster(filter)\n                is GPUImageSepiaToneFilter -> SepiaAdjuster(filter)\n                is GPUImageContrastFilter -> ContrastAdjuster(filter)\n                is GPUImageGammaFilter -> GammaAdjuster(filter)\n                is GPUImageBrightnessFilter -> BrightnessAdjuster(filter)\n                is GPUImageSobelEdgeDetectionFilter -> SobelAdjuster(filter)\n                is GPUImageThresholdEdgeDetectionFilter -> ThresholdAdjuster(filter)\n                is GPUImage3x3ConvolutionFilter -> ThreeXThreeConvolutionAjuster(filter)\n                is GPUImageEmbossFilter -> EmbossAdjuster(filter)\n                is GPUImage3x3TextureSamplingFilter -> GPU3x3TextureAdjuster(filter)\n                is GPUImageHueFilter -> HueAdjuster(filter)\n                is GPUImagePosterizeFilter -> PosterizeAdjuster(filter)\n                is GPUImagePixelationFilter -> PixelationAdjuster(filter)\n                is GPUImageSaturationFilter -> SaturationAdjuster(filter)\n                is GPUImageExposureFilter -> ExposureAdjuster(filter)\n                is GPUImageHighlightShadowFilter -> HighlightShadowAdjuster(filter)\n                is GPUImageMonochromeFilter -> MonochromeAdjuster(filter)\n                is GPUImageOpacityFilter -> OpacityAdjuster(filter)\n                is GPUImageRGBFilter -> RGBAdjuster(filter)\n                is GPUImageWhiteBalanceFilter -> WhiteBalanceAdjuster(filter)\n                is GPUImageVignetteFilter -> VignetteAdjuster(filter)\n                is GPUImageLuminanceThresholdFilter -> LuminanceThresholdAdjuster(filter)\n                is GPUImageDissolveBlendFilter -> DissolveBlendAdjuster(filter)\n                is GPUImageGaussianBlurFilter -> GaussianBlurAdjuster(filter)\n                is GPUImageCrosshatchFilter -> CrosshatchBlurAdjuster(filter)\n                is GPUImageBulgeDistortionFilter -> BulgeDistortionAdjuster(filter)\n                is GPUImageGlassSphereFilter -> GlassSphereAdjuster(filter)\n                is GPUImageHazeFilter -> HazeAdjuster(filter)\n                is GPUImageSphereRefractionFilter -> SphereRefractionAdjuster(filter)\n                is GPUImageSwirlFilter -> SwirlAdjuster(filter)\n                is GPUImageColorBalanceFilter -> ColorBalanceAdjuster(filter)\n                is GPUImageLevelsFilter -> LevelsMinMidAdjuster(filter)\n                is GPUImageBilateralBlurFilter -> BilateralAdjuster(filter)\n                is GPUImageTransformFilter -> RotateAdjuster(filter)\n                is GPUImageSolarizeFilter -> SolarizeAdjuster(filter)\n                is GPUImageVibranceFilter -> VibranceAdjuster(filter)\n                else -> null\n            }\n        }\n\n        fun canAdjust(): Boolean {\n            return adjuster != null\n        }\n\n        fun adjust(percentage: Int) {\n            adjuster?.adjust(percentage)\n        }\n\n        private abstract inner class Adjuster<T : GPUImageFilter>(protected val filter: T) {\n\n            abstract fun adjust(percentage: Int)\n\n            protected fun range(percentage: Int, start: Float, end: Float): Float {\n                return (end - start) * percentage / 100.0f + start\n            }\n\n            protected fun range(percentage: Int, start: Int, end: Int): Int {\n                return (end - start) * percentage / 100 + start\n            }\n        }\n\n        private inner class SharpnessAdjuster(filter: GPUImageSharpenFilter) :\n            Adjuster<GPUImageSharpenFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setSharpness(range(percentage, -4.0f, 4.0f))\n            }\n        }\n\n        private inner class PixelationAdjuster(filter: GPUImagePixelationFilter) :\n            Adjuster<GPUImagePixelationFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setPixel(range(percentage, 1.0f, 100.0f))\n            }\n        }\n\n        private inner class HueAdjuster(filter: GPUImageHueFilter) :\n            Adjuster<GPUImageHueFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setHue(range(percentage, 0.0f, 360.0f))\n            }\n        }\n\n        private inner class ContrastAdjuster(filter: GPUImageContrastFilter) :\n            Adjuster<GPUImageContrastFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setContrast(range(percentage, 0.0f, 2.0f))\n            }\n        }\n\n        private inner class GammaAdjuster(filter: GPUImageGammaFilter) :\n            Adjuster<GPUImageGammaFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setGamma(range(percentage, 0.0f, 3.0f))\n            }\n        }\n\n        private inner class BrightnessAdjuster(filter: GPUImageBrightnessFilter) :\n            Adjuster<GPUImageBrightnessFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setBrightness(range(percentage, -1.0f, 1.0f))\n            }\n        }\n\n        private inner class SepiaAdjuster(filter: GPUImageSepiaToneFilter) :\n            Adjuster<GPUImageSepiaToneFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setIntensity(range(percentage, 0.0f, 2.0f))\n            }\n        }\n\n        private inner class SobelAdjuster(filter: GPUImageSobelEdgeDetectionFilter) :\n            Adjuster<GPUImageSobelEdgeDetectionFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setLineSize(range(percentage, 0.0f, 5.0f))\n            }\n        }\n\n        private inner class ThresholdAdjuster(filter: GPUImageThresholdEdgeDetectionFilter) :\n            Adjuster<GPUImageThresholdEdgeDetectionFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setLineSize(range(percentage, 0.0f, 5.0f))\n                filter.setThreshold(0.9f)\n            }\n        }\n\n        private inner class ThreeXThreeConvolutionAjuster(filter: GPUImage3x3ConvolutionFilter) :\n            Adjuster<GPUImage3x3ConvolutionFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setConvolutionKernel(\n                    floatArrayOf(-1.0f, 0.0f, 1.0f, -2.0f, 0.0f, 2.0f, -1.0f, 0.0f, 1.0f)\n                )\n            }\n        }\n\n        private inner class EmbossAdjuster(filter: GPUImageEmbossFilter) :\n            Adjuster<GPUImageEmbossFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.intensity = range(percentage, 0.0f, 4.0f)\n            }\n        }\n\n        private inner class PosterizeAdjuster(filter: GPUImagePosterizeFilter) :\n            Adjuster<GPUImagePosterizeFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                // In theorie to 256, but only first 50 are interesting\n                filter.setColorLevels(range(percentage, 1, 50))\n            }\n        }\n\n        private inner class GPU3x3TextureAdjuster(filter: GPUImage3x3TextureSamplingFilter) :\n            Adjuster<GPUImage3x3TextureSamplingFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setLineSize(range(percentage, 0.0f, 5.0f))\n            }\n        }\n\n        private inner class SaturationAdjuster(filter: GPUImageSaturationFilter) :\n            Adjuster<GPUImageSaturationFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setSaturation(range(percentage, 0.0f, 2.0f))\n            }\n        }\n\n        private inner class ExposureAdjuster(filter: GPUImageExposureFilter) :\n            Adjuster<GPUImageExposureFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setExposure(range(percentage, -10.0f, 10.0f))\n            }\n        }\n\n        private inner class HighlightShadowAdjuster(filter: GPUImageHighlightShadowFilter) :\n            Adjuster<GPUImageHighlightShadowFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setShadows(range(percentage, 0.0f, 1.0f))\n                filter.setHighlights(range(percentage, 0.0f, 1.0f))\n            }\n        }\n\n        private inner class MonochromeAdjuster(filter: GPUImageMonochromeFilter) :\n            Adjuster<GPUImageMonochromeFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setIntensity(range(percentage, 0.0f, 1.0f))\n            }\n        }\n\n        private inner class OpacityAdjuster(filter: GPUImageOpacityFilter) :\n            Adjuster<GPUImageOpacityFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setOpacity(range(percentage, 0.0f, 1.0f))\n            }\n        }\n\n        private inner class RGBAdjuster(filter: GPUImageRGBFilter) :\n            Adjuster<GPUImageRGBFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setRed(range(percentage, 0.0f, 1.0f))\n            }\n        }\n\n        private inner class WhiteBalanceAdjuster(filter: GPUImageWhiteBalanceFilter) :\n            Adjuster<GPUImageWhiteBalanceFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setTemperature(range(percentage, 2000.0f, 8000.0f))\n            }\n        }\n\n        private inner class VignetteAdjuster(filter: GPUImageVignetteFilter) :\n            Adjuster<GPUImageVignetteFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setVignetteStart(range(percentage, 0.0f, 1.0f))\n            }\n        }\n\n        private inner class LuminanceThresholdAdjuster(filter: GPUImageLuminanceThresholdFilter) :\n            Adjuster<GPUImageLuminanceThresholdFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setThreshold(range(percentage, 0.0f, 1.0f))\n            }\n        }\n\n        private inner class DissolveBlendAdjuster(filter: GPUImageDissolveBlendFilter) :\n            Adjuster<GPUImageDissolveBlendFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setMix(range(percentage, 0.0f, 1.0f))\n            }\n        }\n\n        private inner class GaussianBlurAdjuster(filter: GPUImageGaussianBlurFilter) :\n            Adjuster<GPUImageGaussianBlurFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setBlurSize(range(percentage, 0.0f, 1.0f))\n            }\n        }\n\n        private inner class CrosshatchBlurAdjuster(filter: GPUImageCrosshatchFilter) :\n            Adjuster<GPUImageCrosshatchFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setCrossHatchSpacing(range(percentage, 0.0f, 0.06f))\n                filter.setLineWidth(range(percentage, 0.0f, 0.006f))\n            }\n        }\n\n        private inner class BulgeDistortionAdjuster(filter: GPUImageBulgeDistortionFilter) :\n            Adjuster<GPUImageBulgeDistortionFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setRadius(range(percentage, 0.0f, 1.0f))\n                filter.setScale(range(percentage, -1.0f, 1.0f))\n            }\n        }\n\n        private inner class GlassSphereAdjuster(filter: GPUImageGlassSphereFilter) :\n            Adjuster<GPUImageGlassSphereFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setRadius(range(percentage, 0.0f, 1.0f))\n            }\n        }\n\n        private inner class HazeAdjuster(filter: GPUImageHazeFilter) :\n            Adjuster<GPUImageHazeFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setDistance(range(percentage, -0.3f, 0.3f))\n                filter.setSlope(range(percentage, -0.3f, 0.3f))\n            }\n        }\n\n        private inner class SphereRefractionAdjuster(filter: GPUImageSphereRefractionFilter) :\n            Adjuster<GPUImageSphereRefractionFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setRadius(range(percentage, 0.0f, 1.0f))\n            }\n        }\n\n        private inner class SwirlAdjuster(filter: GPUImageSwirlFilter) :\n            Adjuster<GPUImageSwirlFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setAngle(range(percentage, 0.0f, 2.0f))\n            }\n        }\n\n        private inner class ColorBalanceAdjuster(filter: GPUImageColorBalanceFilter) :\n            Adjuster<GPUImageColorBalanceFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setMidtones(\n                    floatArrayOf(\n                        range(percentage, 0.0f, 1.0f),\n                        range(percentage / 2, 0.0f, 1.0f),\n                        range(percentage / 3, 0.0f, 1.0f)\n                    )\n                )\n            }\n        }\n\n        private inner class LevelsMinMidAdjuster(filter: GPUImageLevelsFilter) :\n            Adjuster<GPUImageLevelsFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setMin(0.0f, range(percentage, 0.0f, 1.0f), 1.0f)\n            }\n        }\n\n        private inner class BilateralAdjuster(filter: GPUImageBilateralBlurFilter) :\n            Adjuster<GPUImageBilateralBlurFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setDistanceNormalizationFactor(range(percentage, 0.0f, 15.0f))\n            }\n        }\n\n        private inner class RotateAdjuster(filter: GPUImageTransformFilter) :\n            Adjuster<GPUImageTransformFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                val transform = FloatArray(16)\n                Matrix.setRotateM(transform, 0, (360 * percentage / 100).toFloat(), 0f, 0f, 1.0f)\n                filter.transform3D = transform\n            }\n        }\n\n        private inner class SolarizeAdjuster(filter: GPUImageSolarizeFilter) :\n            Adjuster<GPUImageSolarizeFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setThreshold(range(percentage, 0.0f, 1.0f))\n            }\n        }\n\n        private inner class VibranceAdjuster(filter: GPUImageVibranceFilter) :\n            Adjuster<GPUImageVibranceFilter>(filter) {\n            override fun adjust(percentage: Int) {\n                filter.setVibrance(range(percentage, -1.2f, 1.2f))\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/jp/co/cyberagent/android/gpuimage/sample/activity/CameraActivity.kt",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.sample.activity\n\nimport android.os.Build\nimport android.os.Bundle\nimport android.view.View\nimport android.widget.SeekBar\nimport android.widget.SeekBar.OnSeekBarChangeListener\nimport android.widget.Toast\nimport androidx.appcompat.app.AppCompatActivity\nimport jp.co.cyberagent.android.gpuimage.GPUImageView\nimport jp.co.cyberagent.android.gpuimage.filter.GPUImageFilter\nimport jp.co.cyberagent.android.gpuimage.sample.GPUImageFilterTools\nimport jp.co.cyberagent.android.gpuimage.sample.GPUImageFilterTools.FilterAdjuster\nimport jp.co.cyberagent.android.gpuimage.sample.R\nimport jp.co.cyberagent.android.gpuimage.sample.utils.Camera1Loader\nimport jp.co.cyberagent.android.gpuimage.sample.utils.Camera2Loader\nimport jp.co.cyberagent.android.gpuimage.sample.utils.CameraLoader\nimport jp.co.cyberagent.android.gpuimage.sample.utils.doOnLayout\nimport jp.co.cyberagent.android.gpuimage.util.Rotation\n\nclass CameraActivity : AppCompatActivity() {\n\n    private val gpuImageView: GPUImageView by lazy { findViewById<GPUImageView>(R.id.surfaceView) }\n    private val seekBar: SeekBar by lazy { findViewById<SeekBar>(R.id.seekBar) }\n    private val cameraLoader: CameraLoader by lazy {\n        if (Build.VERSION.SDK_INT < 21) {\n            Camera1Loader(this)\n        } else {\n            Camera2Loader(this)\n        }\n    }\n    private var filterAdjuster: FilterAdjuster? = null\n\n    public override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.activity_camera)\n\n        seekBar.setOnSeekBarChangeListener(object : OnSeekBarChangeListener {\n            override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {\n                filterAdjuster?.adjust(progress)\n            }\n\n            override fun onStartTrackingTouch(seekBar: SeekBar) {}\n            override fun onStopTrackingTouch(seekBar: SeekBar) {}\n        })\n        findViewById<View>(R.id.button_choose_filter).setOnClickListener {\n            GPUImageFilterTools.showDialog(this) { filter -> switchFilterTo(filter) }\n        }\n        findViewById<View>(R.id.button_capture).setOnClickListener {\n            saveSnapshot()\n        }\n        findViewById<View>(R.id.img_switch_camera).run {\n            if (!cameraLoader.hasMultipleCamera()) {\n                visibility = View.GONE\n            }\n            setOnClickListener {\n                cameraLoader.switchCamera()\n                gpuImageView.setRotation(getRotation(cameraLoader.getCameraOrientation()))\n            }\n        }\n        cameraLoader.setOnPreviewFrameListener { data, width, height ->\n            gpuImageView.updatePreviewFrame(data, width, height)\n        }\n        gpuImageView.setRotation(getRotation(cameraLoader.getCameraOrientation()))\n        gpuImageView.setRenderMode(GPUImageView.RENDERMODE_CONTINUOUSLY)\n    }\n\n    override fun onResume() {\n        super.onResume()\n        gpuImageView.doOnLayout {\n            cameraLoader.onResume(it.width, it.height)\n        }\n    }\n\n    override fun onPause() {\n        cameraLoader.onPause()\n        super.onPause()\n    }\n\n    private fun saveSnapshot() {\n        val folderName = \"GPUImage\"\n        val fileName = System.currentTimeMillis().toString() + \".jpg\"\n        gpuImageView.saveToPictures(folderName, fileName) {\n            Toast.makeText(this, \"$folderName/$fileName saved\", Toast.LENGTH_SHORT).show()\n        }\n    }\n\n    private fun getRotation(orientation: Int): Rotation {\n        return when (orientation) {\n            90 -> Rotation.ROTATION_90\n            180 -> Rotation.ROTATION_180\n            270 -> Rotation.ROTATION_270\n            else -> Rotation.NORMAL\n        }\n    }\n\n    private fun switchFilterTo(filter: GPUImageFilter) {\n        if (gpuImageView.filter == null || gpuImageView.filter!!.javaClass != filter.javaClass) {\n            gpuImageView.filter = filter\n            filterAdjuster = FilterAdjuster(filter)\n            filterAdjuster?.adjust(seekBar.progress)\n        }\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/jp/co/cyberagent/android/gpuimage/sample/activity/GalleryActivity.kt",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.sample.activity\n\nimport android.content.Intent\nimport android.os.Bundle\nimport android.view.View\nimport android.widget.SeekBar\nimport android.widget.SeekBar.OnSeekBarChangeListener\nimport android.widget.Toast\nimport androidx.appcompat.app.AppCompatActivity\nimport jp.co.cyberagent.android.gpuimage.GPUImageView\nimport jp.co.cyberagent.android.gpuimage.filter.GPUImageFilter\nimport jp.co.cyberagent.android.gpuimage.sample.GPUImageFilterTools\nimport jp.co.cyberagent.android.gpuimage.sample.GPUImageFilterTools.FilterAdjuster\nimport jp.co.cyberagent.android.gpuimage.sample.R\n\nclass GalleryActivity : AppCompatActivity() {\n\n    private var filterAdjuster: FilterAdjuster? = null\n    private val gpuImageView: GPUImageView by lazy { findViewById<GPUImageView>(R.id.gpuimage) }\n    private val seekBar: SeekBar by lazy { findViewById<SeekBar>(R.id.seekBar) }\n\n    public override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.activity_gallery)\n\n        seekBar.setOnSeekBarChangeListener(object : OnSeekBarChangeListener {\n            override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {\n                filterAdjuster?.adjust(progress)\n                gpuImageView.requestRender()\n            }\n\n            override fun onStartTrackingTouch(seekBar: SeekBar?) {}\n            override fun onStopTrackingTouch(seekBar: SeekBar?) {}\n        })\n\n        findViewById<View>(R.id.button_choose_filter).setOnClickListener {\n            GPUImageFilterTools.showDialog(this) { filter ->\n                switchFilterTo(filter)\n                gpuImageView.requestRender()\n            }\n        }\n        findViewById<View>(R.id.button_save).setOnClickListener { saveImage() }\n\n        startPhotoPicker()\n    }\n\n    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {\n        when (requestCode) {\n            REQUEST_PICK_IMAGE -> if (resultCode == RESULT_OK) {\n                gpuImageView.setImage(data!!.data)\n            } else {\n                finish()\n            }\n\n            else -> super.onActivityResult(requestCode, resultCode, data)\n        }\n    }\n\n    private fun startPhotoPicker() {\n        val photoPickerIntent = Intent(Intent.ACTION_PICK)\n        photoPickerIntent.type = \"image/*\"\n        startActivityForResult(photoPickerIntent, REQUEST_PICK_IMAGE)\n    }\n\n    private fun saveImage() {\n        val fileName = System.currentTimeMillis().toString() + \".jpg\"\n        gpuImageView.saveToPictures(\"GPUImage\", fileName) { uri ->\n            Toast.makeText(this, \"Saved: \" + uri.toString(), Toast.LENGTH_SHORT).show()\n        }\n    }\n\n    private fun switchFilterTo(filter: GPUImageFilter) {\n        if (gpuImageView.filter == null || gpuImageView.filter.javaClass != filter.javaClass) {\n            gpuImageView.filter = filter\n            filterAdjuster = FilterAdjuster(filter)\n            if (filterAdjuster!!.canAdjust()) {\n                seekBar.visibility = View.VISIBLE\n                filterAdjuster!!.adjust(seekBar.progress)\n            } else {\n                seekBar.visibility = View.GONE\n            }\n        }\n    }\n\n    companion object {\n        private const val REQUEST_PICK_IMAGE = 1\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/jp/co/cyberagent/android/gpuimage/sample/activity/MainActivity.kt",
    "content": "/*\n * Copyright (C) 2018 CyberAgent, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage jp.co.cyberagent.android.gpuimage.sample.activity\n\nimport android.Manifest\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.os.Bundle\nimport android.view.View\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.core.app.ActivityCompat\nimport androidx.core.content.ContextCompat\nimport jp.co.cyberagent.android.gpuimage.sample.R\n\nclass MainActivity : AppCompatActivity() {\n\n    public override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.activity_main)\n\n        findViewById<View>(R.id.button_gallery).setOnClickListener {\n            startActivity(Intent(this, GalleryActivity::class.java))\n        }\n        findViewById<View>(R.id.button_camera).setOnClickListener {\n            if (!hasCameraPermission() || !hasStoragePermission()) {\n                ActivityCompat.requestPermissions(\n                    this,\n                    arrayOf(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE),\n                    REQUEST_CAMERA\n                )\n            } else {\n                startActivity(Intent(this, CameraActivity::class.java))\n            }\n        }\n    }\n\n    override fun onRequestPermissionsResult(\n        requestCode: Int,\n        permissions: Array<String>,\n        grantResults: IntArray\n    ) {\n        if (requestCode == REQUEST_CAMERA && grantResults.size == 2\n            && grantResults[0] == PackageManager.PERMISSION_GRANTED\n            && grantResults[1] == PackageManager.PERMISSION_GRANTED\n        ) {\n            startActivity(Intent(this, CameraActivity::class.java))\n        } else {\n            super.onRequestPermissionsResult(requestCode, permissions, grantResults)\n        }\n    }\n\n    private fun hasCameraPermission(): Boolean {\n        return ContextCompat.checkSelfPermission(\n            this,\n            Manifest.permission.CAMERA\n        ) == PackageManager.PERMISSION_GRANTED\n    }\n\n    private fun hasStoragePermission(): Boolean {\n        return ContextCompat.checkSelfPermission(\n            this,\n            Manifest.permission.WRITE_EXTERNAL_STORAGE\n        ) == PackageManager.PERMISSION_GRANTED\n    }\n\n    companion object {\n        private const val REQUEST_CAMERA = 1\n    }\n}\n"
  },
  {
    "path": "sample/src/main/java/jp/co/cyberagent/android/gpuimage/sample/utils/Camera1Loader.kt",
    "content": "@file:Suppress(\"DEPRECATION\")\n\npackage jp.co.cyberagent.android.gpuimage.sample.utils\n\nimport android.app.Activity\nimport android.hardware.Camera\nimport android.util.Log\nimport android.view.Surface\n\nclass Camera1Loader(private val activity: Activity) : CameraLoader() {\n\n    private var cameraInstance: Camera? = null\n    private var cameraFacing: Int = Camera.CameraInfo.CAMERA_FACING_BACK\n\n    override fun onResume(width: Int, height: Int) {\n        setUpCamera()\n    }\n\n    override fun onPause() {\n        releaseCamera()\n    }\n\n    override fun switchCamera() {\n        cameraFacing = when (cameraFacing) {\n            Camera.CameraInfo.CAMERA_FACING_FRONT -> Camera.CameraInfo.CAMERA_FACING_BACK\n            Camera.CameraInfo.CAMERA_FACING_BACK -> Camera.CameraInfo.CAMERA_FACING_FRONT\n            else -> return\n        }\n        releaseCamera()\n        setUpCamera()\n    }\n\n    override fun getCameraOrientation(): Int {\n        val degrees = when (activity.windowManager.defaultDisplay.rotation) {\n            Surface.ROTATION_0 -> 0\n            Surface.ROTATION_90 -> 90\n            Surface.ROTATION_180 -> 180\n            Surface.ROTATION_270 -> 270\n            else -> 0\n        }\n        return if (cameraFacing == Camera.CameraInfo.CAMERA_FACING_FRONT) {\n            (90 + degrees) % 360\n        } else { // back-facing\n            (90 - degrees) % 360\n        }\n    }\n\n    override fun hasMultipleCamera(): Boolean {\n        return Camera.getNumberOfCameras() > 1\n    }\n\n    private fun setUpCamera() {\n        val id = getCurrentCameraId()\n        try {\n            cameraInstance = getCameraInstance(id)\n        } catch (e: IllegalAccessError) {\n            Log.e(TAG, \"Camera not found\")\n            return\n        }\n        val parameters = cameraInstance!!.parameters\n\n        if (parameters.supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {\n            parameters.focusMode = Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE\n        }\n        cameraInstance!!.parameters = parameters\n\n        cameraInstance!!.setPreviewCallback { data, camera ->\n            if (data == null || camera == null) {\n                return@setPreviewCallback\n            }\n            val size = camera.parameters.previewSize\n            onPreviewFrame?.invoke(data, size.width, size.height)\n        }\n        cameraInstance!!.startPreview()\n    }\n\n    private fun getCurrentCameraId(): Int {\n        val cameraInfo = Camera.CameraInfo()\n        for (id in 0 until Camera.getNumberOfCameras()) {\n            Camera.getCameraInfo(id, cameraInfo)\n            if (cameraInfo.facing == cameraFacing) {\n                return id\n            }\n        }\n        return 0\n    }\n\n    private fun getCameraInstance(id: Int): Camera {\n        return try {\n            Camera.open(id)\n        } catch (e: Exception) {\n            throw IllegalAccessError(\"Camera not found\")\n        }\n    }\n\n    private fun releaseCamera() {\n        cameraInstance!!.setPreviewCallback(null)\n        cameraInstance!!.release()\n        cameraInstance = null\n    }\n\n    companion object {\n        private const val TAG = \"Camera1Loader\"\n    }\n}"
  },
  {
    "path": "sample/src/main/java/jp/co/cyberagent/android/gpuimage/sample/utils/Camera2Loader.kt",
    "content": "package jp.co.cyberagent.android.gpuimage.sample.utils\n\nimport android.annotation.SuppressLint\nimport android.app.Activity\nimport android.content.Context\nimport android.graphics.ImageFormat\nimport android.hardware.camera2.*\nimport android.media.ImageReader\nimport android.os.Build\nimport android.util.Log\nimport android.util.Size\nimport android.view.Surface\nimport androidx.annotation.RequiresApi\n\n@RequiresApi(Build.VERSION_CODES.LOLLIPOP)\nclass Camera2Loader(private val activity: Activity) : CameraLoader() {\n\n    private var cameraInstance: CameraDevice? = null\n    private var captureSession: CameraCaptureSession? = null\n    private var imageReader: ImageReader? = null\n    private var cameraFacing: Int = CameraCharacteristics.LENS_FACING_BACK\n    private var viewWidth: Int = 0\n    private var viewHeight: Int = 0\n\n    private val cameraManager: CameraManager by lazy {\n        activity.getSystemService(Context.CAMERA_SERVICE) as CameraManager\n    }\n\n    override fun onResume(width: Int, height: Int) {\n        viewWidth = width\n        viewHeight = height\n        setUpCamera()\n    }\n\n    override fun onPause() {\n        releaseCamera()\n    }\n\n    override fun switchCamera() {\n        cameraFacing = when (cameraFacing) {\n            CameraCharacteristics.LENS_FACING_BACK -> CameraCharacteristics.LENS_FACING_FRONT\n            CameraCharacteristics.LENS_FACING_FRONT -> CameraCharacteristics.LENS_FACING_BACK\n            else -> return\n        }\n        releaseCamera()\n        setUpCamera()\n    }\n\n    override fun getCameraOrientation(): Int {\n        val degrees = when (activity.windowManager.defaultDisplay.rotation) {\n            Surface.ROTATION_0 -> 0\n            Surface.ROTATION_90 -> 90\n            Surface.ROTATION_180 -> 180\n            Surface.ROTATION_270 -> 270\n            else -> 0\n        }\n        val cameraId = getCameraId(cameraFacing) ?: return 0\n        val characteristics = cameraManager.getCameraCharacteristics(cameraId)\n        val orientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION) ?: return 0\n        return if (cameraFacing == CameraCharacteristics.LENS_FACING_FRONT) {\n            (orientation + degrees) % 360\n        } else { // back-facing\n            (orientation - degrees) % 360\n        }\n    }\n\n    override fun hasMultipleCamera(): Boolean {\n        return cameraManager.cameraIdList.size > 1\n    }\n\n    @SuppressLint(\"MissingPermission\")\n    private fun setUpCamera() {\n        val cameraId = getCameraId(cameraFacing) ?: return\n        try {\n            cameraManager.openCamera(cameraId, CameraDeviceCallback(), null)\n        } catch (e: CameraAccessException) {\n            Log.e(TAG, \"Opening camera (ID: $cameraId) failed.\")\n        }\n    }\n\n    private fun releaseCamera() {\n        imageReader?.close()\n        cameraInstance?.close()\n        captureSession?.close()\n        imageReader = null\n        cameraInstance = null\n        captureSession = null\n    }\n\n    private fun getCameraId(facing: Int): String? {\n        return cameraManager.cameraIdList.find { id ->\n            cameraManager.getCameraCharacteristics(id).get(CameraCharacteristics.LENS_FACING) == facing\n        }\n    }\n\n    private fun startCaptureSession() {\n        val size = chooseOptimalSize()\n        imageReader =\n                ImageReader.newInstance(size.width, size.height, ImageFormat.YUV_420_888, 2).apply {\n                    setOnImageAvailableListener({ reader ->\n                        val image = reader?.acquireNextImage() ?: return@setOnImageAvailableListener\n                        onPreviewFrame?.invoke(image.generateNV21Data(), image.width, image.height)\n                        image.close()\n                    }, null)\n                }\n\n        try {\n            cameraInstance?.createCaptureSession(\n                listOf(imageReader!!.surface),\n                CaptureStateCallback(),\n                null\n            )\n        } catch (e: CameraAccessException) {\n            Log.e(TAG, \"Failed to start camera session\")\n        }\n    }\n\n    private fun chooseOptimalSize(): Size {\n        if (viewWidth == 0 || viewHeight == 0) {\n            return Size(0, 0)\n        }\n        val cameraId = getCameraId(cameraFacing) ?: return Size(0, 0)\n        val outputSizes = cameraManager.getCameraCharacteristics(cameraId)\n            .get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)\n            ?.getOutputSizes(ImageFormat.YUV_420_888)\n\n        val orientation = getCameraOrientation()\n        val maxPreviewWidth = if (orientation == 90 or 270) viewHeight else viewWidth\n        val maxPreviewHeight = if (orientation == 90 or 270) viewWidth else viewHeight\n\n        return outputSizes?.filter {\n            it.width < maxPreviewWidth / 2 && it.height < maxPreviewHeight / 2\n        }?.maxBy {\n            it.width * it.height\n        } ?: Size(PREVIEW_WIDTH, PREVIEW_HEIGHT)\n    }\n\n    private inner class CameraDeviceCallback : CameraDevice.StateCallback() {\n        override fun onOpened(camera: CameraDevice) {\n            cameraInstance = camera\n            startCaptureSession()\n        }\n\n        override fun onDisconnected(camera: CameraDevice) {\n            camera.close()\n            cameraInstance = null\n        }\n\n        override fun onError(camera: CameraDevice, error: Int) {\n            camera.close()\n            cameraInstance = null\n        }\n    }\n\n    private inner class CaptureStateCallback : CameraCaptureSession.StateCallback() {\n        override fun onConfigureFailed(session: CameraCaptureSession) {\n            Log.e(TAG, \"Failed to configure capture session.\")\n        }\n\n        override fun onConfigured(session: CameraCaptureSession) {\n            cameraInstance ?: return\n            captureSession = session\n            val builder = cameraInstance!!.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)\n            builder.addTarget(imageReader!!.surface)\n            try {\n                session.setRepeatingRequest(builder.build(), null, null)\n            } catch (e: CameraAccessException) {\n                Log.e(TAG, \"Failed to start camera preview because it couldn't access camera\", e)\n            } catch (e: IllegalStateException) {\n                Log.e(TAG, \"Failed to start camera preview.\", e)\n            }\n        }\n    }\n\n    companion object {\n        private const val TAG = \"Camera2Loader\"\n\n        private const val PREVIEW_WIDTH = 480\n        private const val PREVIEW_HEIGHT = 640\n    }\n}"
  },
  {
    "path": "sample/src/main/java/jp/co/cyberagent/android/gpuimage/sample/utils/CameraLoader.kt",
    "content": "package jp.co.cyberagent.android.gpuimage.sample.utils\n\n\nabstract class CameraLoader {\n\n    protected var onPreviewFrame: ((data: ByteArray, width: Int, height: Int) -> Unit)? = null\n\n    abstract fun onResume(width: Int, height: Int)\n\n    abstract fun onPause()\n\n    abstract fun switchCamera()\n\n    abstract fun getCameraOrientation(): Int\n\n    abstract fun hasMultipleCamera(): Boolean\n\n    fun setOnPreviewFrameListener(onPreviewFrame: (data: ByteArray, width: Int, height: Int) -> Unit) {\n        this.onPreviewFrame = onPreviewFrame\n    }\n}"
  },
  {
    "path": "sample/src/main/java/jp/co/cyberagent/android/gpuimage/sample/utils/ImageExt.kt",
    "content": "package jp.co.cyberagent.android.gpuimage.sample.utils\n\nimport android.graphics.ImageFormat\nimport android.media.Image\nimport android.os.Build\nimport androidx.annotation.RequiresApi\n\n@RequiresApi(Build.VERSION_CODES.LOLLIPOP)\nfun Image.generateNV21Data(): ByteArray {\n    val crop = cropRect\n    val format = format\n    val width = crop.width()\n    val height = crop.height()\n    val planes = planes\n    val data = ByteArray(width * height * ImageFormat.getBitsPerPixel(format) / 8)\n    val rowData = ByteArray(planes[0].rowStride)\n    var channelOffset = 0\n    var outputStride = 1\n    for (i in planes.indices) {\n        when (i) {\n            0 -> {\n                channelOffset = 0\n                outputStride = 1\n            }\n            1 -> {\n                channelOffset = width * height + 1\n                outputStride = 2\n            }\n            2 -> {\n                channelOffset = width * height\n                outputStride = 2\n            }\n        }\n        val buffer = planes[i].buffer\n        val rowStride = planes[i].rowStride\n        val pixelStride = planes[i].pixelStride\n        val shift = if (i == 0) 0 else 1\n        val w = width shr shift\n        val h = height shr shift\n        buffer.position(rowStride * (crop.top shr shift) + pixelStride * (crop.left shr shift))\n        for (row in 0 until h) {\n            val length: Int\n            if (pixelStride == 1 && outputStride == 1) {\n                length = w\n                buffer.get(data, channelOffset, length)\n                channelOffset += length\n            } else {\n                length = (w - 1) * pixelStride + 1\n                buffer.get(rowData, 0, length)\n                for (col in 0 until w) {\n                    data[channelOffset] = rowData[col * pixelStride]\n                    channelOffset += outputStride\n                }\n            }\n            if (row < h - 1) {\n                buffer.position(buffer.position() + rowStride - length)\n            }\n        }\n    }\n    return data\n}\n"
  },
  {
    "path": "sample/src/main/java/jp/co/cyberagent/android/gpuimage/sample/utils/ViewExt.kt",
    "content": "package jp.co.cyberagent.android.gpuimage.sample.utils\n\nimport android.view.View\nimport androidx.core.view.ViewCompat\n\ninline fun View.doOnLayout(crossinline action: (view: View) -> Unit) {\n    if (ViewCompat.isLaidOut(this) && !isLayoutRequested) {\n        action(this)\n    } else {\n        doOnNextLayout { action(it) }\n    }\n}\n\ninline fun View.doOnNextLayout(crossinline action: (view: View) -> Unit) {\n    addOnLayoutChangeListener(object : View.OnLayoutChangeListener {\n        override fun onLayoutChange(\n            view: View,\n            left: Int,\n            top: Int,\n            right: Int,\n            bottom: Int,\n            oldLeft: Int,\n            oldTop: Int,\n            oldRight: Int,\n            oldBottom: Int\n        ) {\n            view.removeOnLayoutChangeListener(this)\n            action(view)\n        }\n    })\n}\n"
  },
  {
    "path": "sample/src/main/res/layout/activity_camera.xml",
    "content": "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <!--<android.opengl.GLSurfaceView-->\n    <!--android:id=\"@+id/surfaceView\"-->\n    <!--android:layout_width=\"match_parent\"-->\n    <!--android:layout_height=\"match_parent\"-->\n    <!--android:layout_above=\"@+id/bar\" />-->\n\n    <!--<jp.co.cyberagent.android.gpuimage.GLTextureView-->\n    <!--android:id=\"@+id/surfaceView\"-->\n    <!--android:layout_width=\"match_parent\"-->\n    <!--android:layout_height=\"match_parent\"-->\n    <!--android:layout_above=\"@+id/bar\" />-->\n\n    <jp.co.cyberagent.android.gpuimage.GPUImageView\n        android:id=\"@+id/surfaceView\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        app:gpuimage_show_loading=\"false\"\n        app:gpuimage_surface_type=\"texture_view\" /> <!-- surface_view or texture_view -->\n\n    <ImageView\n        android:id=\"@+id/img_switch_camera\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentRight=\"true\"\n        android:contentDescription=\"@null\"\n        android:padding=\"10dp\"\n        android:src=\"@drawable/ic_switch_camera\"\n        tools:ignore=\"HardcodedText,RtlHardcoded\" />\n\n    <LinearLayout\n        android:id=\"@+id/bar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentBottom=\"true\"\n        android:background=\"#000000\"\n        android:gravity=\"center_vertical\"\n        android:orientation=\"horizontal\">\n\n        <SeekBar\n            android:id=\"@+id/seekBar\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:max=\"100\" />\n\n        <Button\n            android:id=\"@+id/button_choose_filter\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"Choose Filter\"\n            tools:ignore=\"HardcodedText\" />\n\n        <ImageButton\n            android:id=\"@+id/button_capture\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:contentDescription=\"@null\"\n            android:src=\"@android:drawable/ic_menu_camera\" />\n    </LinearLayout>\n\n</RelativeLayout>"
  },
  {
    "path": "sample/src/main/res/layout/activity_gallery.xml",
    "content": "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@android:color/black\"\n    android:orientation=\"vertical\">\n\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\">\n\n        <jp.co.cyberagent.android.gpuimage.GPUImageView\n            android:id=\"@+id/gpuimage\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center\" />\n\n        <SeekBar\n            android:id=\"@+id/seekBar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"bottom\"\n            android:max=\"100\" />\n    </FrameLayout>\n\n    <LinearLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_horizontal\">\n\n        <Button\n            android:id=\"@+id/button_choose_filter\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"Choose filter\"\n            tools:ignore=\"HardcodedText\" />\n\n        <Button\n            android:id=\"@+id/button_save\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"Save\"\n            tools:ignore=\"HardcodedText\" />\n    </LinearLayout>\n\n</LinearLayout>"
  },
  {
    "path": "sample/src/main/res/layout/activity_main.xml",
    "content": "<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <LinearLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"\n        android:gravity=\"center\"\n        android:orientation=\"vertical\">\n\n        <Button\n            android:id=\"@+id/button_gallery\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"10dp\"\n            android:drawableTop=\"@android:drawable/ic_menu_gallery\"\n            android:text=\"Gallery\"\n            tools:ignore=\"HardcodedText\" />\n\n        <Button\n            android:id=\"@+id/button_camera\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:drawableTop=\"@android:drawable/ic_menu_camera\"\n            android:text=\"Camera\"\n            tools:ignore=\"HardcodedText\" />\n    </LinearLayout>\n\n</FrameLayout>"
  },
  {
    "path": "sample/src/main/res/values/strings.xml",
    "content": "<resources>\n\n    <string name=\"app_name\">GPUImage for Android</string>\n    <string name=\"title_activity_activity_main\">GPUImage Sample</string>\n\n</resources>"
  },
  {
    "path": "sample/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light\" />\n\n    <style name=\"AppTheme.NoActionBar\" parent=\"Theme.AppCompat.Light.NoActionBar\" />\n\n</resources>"
  },
  {
    "path": "settings.gradle",
    "content": "include ':library'\ninclude ':sample'\n"
  },
  {
    "path": "utils/Shader2String.py",
    "content": "#!/usr/bin/python\n\nimport sys\n\nf = sys.stdin\nif len(sys.argv) > 1:\n  f = open(sys.argv[1])\n\nlines = f.readlines()\nfor line in lines[:-1]:\n  print '\"' + line.rstrip() + '\\\\n\\\" +'\nprint '\"' + lines[-1].rstrip() + '\\\\n\\\"'\n\nf.close()\n"
  }
]