Skip to content

Instantly share code, notes, and snippets.

@saantiaguilera
Created November 21, 2018 02:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save saantiaguilera/2f007e41db46bc6226bd2a80644260a4 to your computer and use it in GitHub Desktop.
Save saantiaguilera/2f007e41db46bc6226bd2a80644260a4 to your computer and use it in GitHub Desktop.
// Root header to have dependencies
buildscript {
repositories {
jcenter()
google()
}
dependencies {
classpath "com.android.tools.build:gradle:$gradleBuildToolsVersion"
classpath gradleApi()
}
}
// Necessary imports we will be working with
import groovy.io.FileType
import org.gradle.workers.WorkerExecutor
import org.gradle.workers.WorkerConfiguration
import javax.inject.Inject
// Create our transform resources task
class TransformResourcesToWebpTask extends DefaultTask {
final WorkerExecutor workerExecutor
@Input
final Set<File> resources
@Input
String mergeTaskName
@Input
Integer compressionQuality
@Inject
TransformResourcesToWebpTask(WorkerExecutor workerExecutor) {
this.workerExecutor = workerExecutor
this.resources = new HashSet<>()
this.compressionQuality = 60
}
@TaskAction
void execute(IncrementalTaskInputs inputs) {
if (!inputs.incremental) {
// We don't delete them as they don't bother us and the files don't belong to us
resources.clear()
}
processResources()
}
private void processResources() {
// Get the MergeResources task, we can't use the class because gradle decorates it.
Task task = project.tasks.named(mergeTaskName).get()
// Define an interal processor. This will perform the heavy load of detecting which resources
// are available for processing
def internalProcess = { FileCollection files ->
files.asFileTree.visit { visitor ->
Set<File> allResources = new HashSet<>()
if (visitor.directory) {
visitor.file.eachFileRecurse(FileType.FILES, { allResources << it })
} else {
allResources << visitor.file
}
allResources.each { res ->
// Filter by image types we know we can transform to WebP
if (!res.name.contains(".9") && res.name =~ /\.(png|jpg|jpeg)$/) {
// Submit to a worker the transformation, so we can parallelize the work
workerExecutor.submit(WebpConvertRunnable.class) { WorkerConfiguration config ->
config.isolationMode = IsolationMode.NONE
config.params res, compressionQuality
}
// Add to our inputs the resource that will be transformed
resources.add(res.absolutePath)
}
}
}
}
// Trigger our own resources and the libraries for processing
task.resources.each { resource -> internalProcess.call(resource.fileCollection) }
internalProcess.call(task.libraries)
// Await termination of transformations
workerExecutor.await()
}
}
// Class that will perform a single file transformation
final class WebpConvertRunnable implements Runnable {
private final File inputFile
private final Integer compressionQuality
@Inject
WebpConvertRunnable(final File inputFile, final Integer compressionQuality) {
this.inputFile = inputFile
this.compressionQuality = compressionQuality
}
@Override
void run() {
final File outputFile = new File(inputFile.absolutePath.take(inputFile.absolutePath.lastIndexOf('.')) + ".webp")
if (compressionQuality < 0 || compressionQuality > 100) {
throw new GradleException("Compression quality should be a value between 0 and 100. Value: '$compressionQuality'")
}
if (!outputFile.exists()) {
def cwebp = [
"cwebp",
"-q",
compressionQuality,
"-m",
"6",
inputFile,
"-o",
outputFile
].execute()
cwebp.waitFor()
inputFile.delete()
}
}
}
// Layout the creation of the tasks we want to.
Task transformTask = task "transformReleaseResourcesToWebp"(type: TransformResourcesToWebpTask) {
mergeTaskName = 'mergeDebugResources'
group = 'Transform'
description = 'Transforms the release resources found to be packaged to the APK to WebP, if possible.'
}
project.tasks.whenTaskAdded { addedTask ->
if (addedTask.name =~ /mergeDebugResources$/) {
addedTask.dependsOn transformTask
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment