Resource optimizer
Showing 15 of 34 files from the diff.
Other files ignored by Codecov
template/build-tools/build.gradle
has changed.
template/build-tools/common-desktop.gradle
has changed.
CHANGELOG.md
has changed.
build.gradle
has changed.
template/build-res/optimizer.json
has changed.
@@ -24,6 +24,10 @@
Loading
24 | 24 | ||
25 | 25 | @Override |
|
26 | 26 | public ImageWithDef process(ImageWithDef original) { |
|
27 | + | if (scaleX == 1.0 && scaleY == 1.0) { |
|
28 | + | return original; |
|
29 | + | } |
|
30 | + | ||
27 | 31 | ImageDefinition originalDef = original.getDef(); |
|
28 | 32 | ||
29 | 33 | // Scale the image definition |
@@ -40,7 +44,7 @@
Loading
40 | 44 | ||
41 | 45 | // Resize the actual pixmap |
|
42 | 46 | Pixmap resizedPixmap = resizedCopy(original.getPixmap()); |
|
43 | - | ||
47 | + | original.dispose(); |
|
44 | 48 | return new ImageWithDef(resizedPixmap, newDef.build()); |
|
45 | 49 | } |
|
46 | 50 |
@@ -0,0 +1,30 @@
Loading
1 | + | package nl.weeaboo.vn.buildtools.optimizer.image.encoder; |
|
2 | + | ||
3 | + | import java.io.IOException; |
|
4 | + | ||
5 | + | import nl.weeaboo.common.Checks; |
|
6 | + | import nl.weeaboo.vn.buildtools.optimizer.image.EncodedImage; |
|
7 | + | import nl.weeaboo.vn.buildtools.optimizer.image.ImageWithDef; |
|
8 | + | ||
9 | + | /** |
|
10 | + | * Only performs lossless optimizations |
|
11 | + | */ |
|
12 | + | public class LosslessEncoder implements IImageEncoder { |
|
13 | + | ||
14 | + | private final IPngEncoder pngEncoder; |
|
15 | + | ||
16 | + | public LosslessEncoder() { |
|
17 | + | this(new DesktopPngEncoder()); |
|
18 | + | } |
|
19 | + | ||
20 | + | public LosslessEncoder(IPngEncoder pngEncoder) { |
|
21 | + | this.pngEncoder = Checks.checkNotNull(pngEncoder); |
|
22 | + | } |
|
23 | + | ||
24 | + | ||
25 | + | @Override |
|
26 | + | public EncodedImage encode(ImageWithDef image) throws IOException { |
|
27 | + | return pngEncoder.encode(image); |
|
28 | + | } |
|
29 | + | ||
30 | + | } |
@@ -1,7 +1,8 @@
Loading
1 | 1 | package nl.weeaboo.vn.buildtools.optimizer; |
|
2 | 2 | ||
3 | - | import java.io.File; |
|
4 | 3 | import java.io.IOException; |
|
4 | + | import java.nio.file.Path; |
|
5 | + | import java.nio.file.Paths; |
|
5 | 6 | ||
6 | 7 | import org.slf4j.Logger; |
|
7 | 8 | import org.slf4j.LoggerFactory; |
@@ -9,6 +10,7 @@
Loading
9 | 10 | import nl.weeaboo.io.FileUtil; |
|
10 | 11 | import nl.weeaboo.vn.buildtools.gdx.HeadlessGdx; |
|
11 | 12 | import nl.weeaboo.vn.buildtools.project.NvlistProjectConnection; |
|
13 | + | import nl.weeaboo.vn.buildtools.project.ProjectFolderConfig; |
|
12 | 14 | import nl.weeaboo.vn.impl.InitConfig; |
|
13 | 15 | import nl.weeaboo.vn.impl.save.JsonUtil; |
|
14 | 16 |
@@ -20,30 +22,44 @@
Loading
20 | 22 | InitConfig.init(); |
|
21 | 23 | HeadlessGdx.init(); |
|
22 | 24 | ||
23 | - | File configPath = new File(args.length >= 1 ? args[0] : "optimizer.json"); |
|
24 | - | File outputPath = new File(args.length >= 2 ? args[1] : "res-optimized"); |
|
25 | + | Path projectFolder = Paths.get(args.length >= 1 ? args[0] : ".").toRealPath(); |
|
25 | 26 | ||
26 | - | LOG.info("Reading config: {}", configPath.getAbsolutePath()); |
|
27 | - | String json = FileUtil.readUtf8(configPath); |
|
27 | + | Path buildToolsFolder = projectFolder.resolve("build-tools"); |
|
28 | + | if (args.length >= 2) { |
|
29 | + | buildToolsFolder = Paths.get(args[1]).toRealPath(); |
|
30 | + | } |
|
31 | + | ||
32 | + | Path configPath = ProjectFolderConfig.getBuildResFolder(projectFolder).resolve("optimizer.json"); |
|
33 | + | if (args.length >= 3) { |
|
34 | + | configPath = Paths.get(args[2]).toRealPath(); |
|
35 | + | } |
|
36 | + | ||
37 | + | Path outputPath = projectFolder.resolve("res-optimized"); |
|
38 | + | if (args.length >= 4) { |
|
39 | + | outputPath = Paths.get(args[3]).toAbsolutePath(); |
|
40 | + | } |
|
41 | + | ||
42 | + | LOG.info("Reading config: {}", configPath.toAbsolutePath()); |
|
43 | + | String json = FileUtil.readUtf8(configPath.toFile()); |
|
28 | 44 | OptimizerConfigJson config = JsonUtil.fromJson(OptimizerConfigJson.class, json); |
|
29 | 45 | ||
30 | - | LOG.info("Output folder: {}", outputPath.getAbsolutePath()); |
|
46 | + | LOG.info("Output folder: {}", outputPath.toAbsolutePath()); |
|
31 | 47 | if (isNonEmptyFolder(outputPath)) { |
|
32 | 48 | throw new IllegalStateException("Output folder isn't empty: " + outputPath); |
|
33 | 49 | } |
|
34 | 50 | ||
35 | - | try (NvlistProjectConnection connection = config.openProject()) { |
|
36 | - | try (OptimizerContext context = config.createContext(connection, outputPath)) { |
|
51 | + | try (NvlistProjectConnection connection = config.openProject(projectFolder, buildToolsFolder)) { |
|
52 | + | try (OptimizerContext context = config.createContext(connection, outputPath.toFile())) { |
|
37 | 53 | ResourceOptimizer optimizer = new ResourceOptimizer(); |
|
38 | 54 | optimizer.optimizeResources(context); |
|
39 | 55 | } |
|
40 | 56 | } |
|
41 | 57 | ||
42 | - | LOG.info("Resource optimized finished. Output folder: {}", outputPath.getAbsolutePath()); |
|
58 | + | LOG.info("Resource optimized finished. Output folder: {}", outputPath.toAbsolutePath()); |
|
43 | 59 | } |
|
44 | 60 | ||
45 | - | private static boolean isNonEmptyFolder(File outputPath) { |
|
46 | - | String[] contents = outputPath.list(); |
|
61 | + | private static boolean isNonEmptyFolder(Path outputPath) { |
|
62 | + | String[] contents = outputPath.toFile().list(); |
|
47 | 63 | return contents != null && contents.length > 0; |
|
48 | 64 | } |
|
49 | 65 |
@@ -26,6 +26,7 @@
Loading
26 | 26 | import nl.weeaboo.vn.buildtools.optimizer.IOptimizerFileSet; |
|
27 | 27 | import nl.weeaboo.vn.buildtools.optimizer.IParallelExecutor; |
|
28 | 28 | import nl.weeaboo.vn.buildtools.optimizer.MainOptimizerConfig; |
|
29 | + | import nl.weeaboo.vn.buildtools.optimizer.OptimizerPreset; |
|
29 | 30 | import nl.weeaboo.vn.buildtools.optimizer.sound.encoder.FfmpegSoundEncoder; |
|
30 | 31 | import nl.weeaboo.vn.buildtools.optimizer.sound.encoder.ISoundEncoder; |
|
31 | 32 | import nl.weeaboo.vn.buildtools.optimizer.sound.encoder.NoOpSoundEncoder; |
@@ -163,6 +164,10 @@
Loading
163 | 164 | } |
|
164 | 165 | ||
165 | 166 | private ISoundEncoder createEncoder() { |
|
167 | + | if (optimizerConfig.getPreset() == OptimizerPreset.LOSSLESS) { |
|
168 | + | return new NoOpSoundEncoder(); |
|
169 | + | } |
|
170 | + | ||
166 | 171 | if (ffmpegAvailable != EAvailable.NO) { |
|
167 | 172 | FfmpegSoundEncoder encoder = new FfmpegSoundEncoder(tempFileProvider); |
|
168 | 173 | if (ffmpegAvailable == EAvailable.YES || encoder.isAvailable()) { |
@@ -0,0 +1,14 @@
Loading
1 | + | package nl.weeaboo.vn.buildtools.optimizer; |
|
2 | + | ||
3 | + | /** |
|
4 | + | * Global quality profile for various optimizers. |
|
5 | + | */ |
|
6 | + | public enum OptimizerPreset { |
|
7 | + | ||
8 | + | /** Only perform lossless optimizations */ |
|
9 | + | LOSSLESS, |
|
10 | + | ||
11 | + | /** Allow lossy optimizations, optimize for quality over file size */ |
|
12 | + | QUALITY; |
|
13 | + | ||
14 | + | } |
@@ -21,14 +21,17 @@
Loading
21 | 21 | import nl.weeaboo.filesystem.IFileSystem; |
|
22 | 22 | import nl.weeaboo.io.FileUtil; |
|
23 | 23 | import nl.weeaboo.io.Filenames; |
|
24 | + | import nl.weeaboo.vn.buildtools.file.EncodedResource; |
|
25 | + | import nl.weeaboo.vn.buildtools.file.IEncodedResource; |
|
24 | 26 | import nl.weeaboo.vn.buildtools.file.OptimizerFileUtil; |
|
25 | 27 | import nl.weeaboo.vn.buildtools.optimizer.IOptimizerContext; |
|
26 | 28 | import nl.weeaboo.vn.buildtools.optimizer.IOptimizerFileSet; |
|
27 | 29 | import nl.weeaboo.vn.buildtools.optimizer.IParallelExecutor; |
|
28 | 30 | import nl.weeaboo.vn.buildtools.optimizer.MainOptimizerConfig; |
|
29 | - | import nl.weeaboo.vn.buildtools.optimizer.image.ImageEncoderConfig.EImageEncoding; |
|
31 | + | import nl.weeaboo.vn.buildtools.optimizer.OptimizerPreset; |
|
30 | 32 | import nl.weeaboo.vn.buildtools.optimizer.image.encoder.IImageEncoder; |
|
31 | 33 | import nl.weeaboo.vn.buildtools.optimizer.image.encoder.JngEncoder; |
|
34 | + | import nl.weeaboo.vn.buildtools.optimizer.image.encoder.LosslessEncoder; |
|
32 | 35 | import nl.weeaboo.vn.buildtools.project.NvlistProjectConnection; |
|
33 | 36 | import nl.weeaboo.vn.core.MediaType; |
|
34 | 37 | import nl.weeaboo.vn.core.NovelPrefs; |
@@ -53,7 +56,6 @@
Loading
53 | 56 | private final IParallelExecutor executor; |
|
54 | 57 | private final MainOptimizerConfig optimizerConfig; |
|
55 | 58 | private final ImageResizerConfig resizeConfig; |
|
56 | - | private final ImageEncoderConfig encoderConfig; |
|
57 | 59 | private final NvlistProjectConnection project; |
|
58 | 60 | private final IFileSystem resFileSystem; |
|
59 | 61 | private final IOptimizerFileSet optimizerFileSet; |
@@ -68,7 +70,6 @@
Loading
68 | 70 | executor = context.getExecutor(); |
|
69 | 71 | optimizerConfig = context.getMainConfig(); |
|
70 | 72 | resizeConfig = context.getConfig(ImageResizerConfig.class, new ImageResizerConfig()); |
|
71 | - | encoderConfig = context.getConfig(ImageEncoderConfig.class, new ImageEncoderConfig()); |
|
72 | 73 | ||
73 | 74 | optimizerFileSet = context.getFileSet(); |
|
74 | 75 |
@@ -150,50 +151,78 @@
Loading
150 | 151 | ||
151 | 152 | LOG.debug("Optimizing image: {}", inputFile); |
|
152 | 153 | ||
153 | - | Pixmap pixmap = PixmapLoader.load(resFileSystem, inputFile); |
|
154 | + | ImageWithDef imageWithDef = load(inputFile); |
|
155 | + | EncodedImage optimized; |
|
156 | + | try { |
|
157 | + | boolean resized = false; |
|
158 | + | if (!baseResolution.equals(targetResolution)) { |
|
159 | + | ImageResizer resizer = new ImageResizer(baseResolution, targetResolution); |
|
160 | + | imageWithDef = resizer.process(imageWithDef); |
|
161 | + | resized = true; |
|
162 | + | } |
|
154 | 163 | ||
155 | - | final boolean premultiplyAlpha = true && PixmapUtil.hasAlpha(pixmap.getFormat()); |
|
156 | - | if (premultiplyAlpha) { |
|
157 | - | PremultUtil.premultiplyAlpha(pixmap); |
|
158 | - | } |
|
164 | + | boolean premultiplyAlpha = premultiplyAlpha(imageWithDef.getPixmap()); |
|
165 | + | ||
166 | + | IImageEncoder imageEncoder = createEncoder(); |
|
167 | + | optimized = imageEncoder.encode(imageWithDef); |
|
168 | + | if (!resized && !premultiplyAlpha) { |
|
169 | + | // If the original image is usable and smaller, use it instead of our 'optimized' version |
|
170 | + | // If the original image is a different size, we can't use it |
|
171 | + | // If we can use premultiplied alpha, the load speed improvement is more important than file size |
|
172 | + | IEncodedResource original = EncodedResource.fromFileSystem(resFileSystem, inputFile); |
|
173 | + | if (original.getFileSize() < optimized.getFileSize()) { |
|
174 | + | optimized.dispose(); |
|
175 | + | optimized = new EncodedImage(original, imageWithDef.getDef()); |
|
176 | + | } |
|
177 | + | } |
|
159 | 178 | ||
160 | - | IImageDefinition imageDef = imageDefCache.getMetaData(inputFile); |
|
161 | - | if (imageDef == null) { |
|
162 | - | imageDef = new ImageDefinition(inputFile.getName(), Dim.of(pixmap.getWidth(), pixmap.getHeight())); |
|
179 | + | // Give files with premultiplied alpha .pre.ext-style extension. |
|
180 | + | if (premultiplyAlpha && optimized.hasAlpha()) { |
|
181 | + | addPremultipyFileExt(optimized); |
|
182 | + | } |
|
183 | + | } finally { |
|
184 | + | imageWithDef.dispose(); |
|
163 | 185 | } |
|
164 | 186 | ||
165 | - | ImageWithDef imageWithDef = new ImageWithDef(pixmap, imageDef); |
|
187 | + | FilePath outputPath = getOutputPath(inputFile, targetResolution, optimized.getDef().getFilename()); |
|
166 | 188 | ||
167 | - | ImageResizer resizer = new ImageResizer(baseResolution, targetResolution); |
|
168 | - | ImageWithDef optimized = resizer.process(imageWithDef); |
|
169 | - | pixmap.dispose(); |
|
189 | + | File outputF = new File(optimizerConfig.getOutputFolder(), outputPath.toString()); |
|
190 | + | Files.createParentDirs(outputF); |
|
191 | + | Files.write(optimized.readBytes(), outputF); |
|
170 | 192 | ||
171 | - | IImageEncoder imageEncoder = createEncoder(); |
|
172 | - | EncodedImage encoded = imageEncoder.encode(optimized); |
|
193 | + | optimizedDefs.put(outputPath, optimized.getDef()); |
|
194 | + | optimizerFileSet.markOptimized(inputFile); |
|
173 | 195 | optimized.dispose(); |
|
196 | + | } |
|
197 | + | ||
198 | + | private ImageWithDef load(FilePath inputFile) throws IOException { |
|
199 | + | Pixmap pixmap = PixmapLoader.load(resFileSystem, inputFile); |
|
174 | 200 | ||
175 | - | // Give files with premultiplied alpha .pre.ext-style extension. |
|
176 | - | if (premultiplyAlpha && encoded.hasAlpha()) { |
|
177 | - | addPremultipyFileExt(encoded); |
|
201 | + | IImageDefinition imageDef = imageDefCache.getMetaData(inputFile); |
|
202 | + | if (imageDef == null) { |
|
203 | + | imageDef = new ImageDefinition(inputFile.getName(), Dim.of(pixmap.getWidth(), pixmap.getHeight())); |
|
178 | 204 | } |
|
179 | - | FilePath outputPath = getOutputPath(inputFile, targetResolution, encoded.getDef().getFilename()); |
|
180 | 205 | ||
181 | - | File outputF = new File(optimizerConfig.getOutputFolder(), outputPath.toString()); |
|
182 | - | Files.createParentDirs(outputF); |
|
183 | - | Files.write(encoded.readBytes(), outputF); |
|
206 | + | return new ImageWithDef(pixmap, imageDef); |
|
207 | + | } |
|
184 | 208 | ||
185 | - | optimizedDefs.put(outputPath, encoded.getDef()); |
|
186 | - | optimizerFileSet.markOptimized(inputFile); |
|
187 | - | encoded.dispose(); |
|
209 | + | private boolean premultiplyAlpha(Pixmap pixmap) { |
|
210 | + | if (!PixmapUtil.hasAlpha(pixmap.getFormat())) { |
|
211 | + | return false; |
|
212 | + | } |
|
213 | + | PremultUtil.premultiplyAlpha(pixmap); |
|
214 | + | return true; |
|
188 | 215 | } |
|
189 | 216 | ||
190 | 217 | private IImageEncoder createEncoder() { |
|
191 | - | EImageEncoding encoding = encoderConfig.getEncoding(); |
|
192 | - | switch (encoding) { |
|
193 | - | case JNG: |
|
218 | + | OptimizerPreset preset = optimizerConfig.getPreset(); |
|
219 | + | switch (preset) { |
|
220 | + | case LOSSLESS: |
|
221 | + | return new LosslessEncoder(); |
|
222 | + | case QUALITY: |
|
194 | 223 | return new JngEncoder(); |
|
195 | 224 | } |
|
196 | - | throw new IllegalArgumentException("Unsupported encoding: " + encoding); |
|
225 | + | throw new IllegalArgumentException("Unsupported preset: " + preset); |
|
197 | 226 | } |
|
198 | 227 | ||
199 | 228 | private void addPremultipyFileExt(EncodedImage encoded) { |
@@ -37,6 +37,11 @@
Loading
37 | 37 | return encodedImage.readBytes(); |
|
38 | 38 | } |
|
39 | 39 | ||
40 | + | @Override |
|
41 | + | public long getFileSize() throws IOException { |
|
42 | + | return encodedImage.getFileSize(); |
|
43 | + | } |
|
44 | + | ||
40 | 45 | /** Returns the {@link IImageDefinition} accompanying the image. */ |
|
41 | 46 | public ImageDefinition getDef() { |
|
42 | 47 | return imageDefinition; |
@@ -19,6 +19,7 @@
Loading
19 | 19 | import nl.weeaboo.vn.buildtools.optimizer.IOptimizerFileSet; |
|
20 | 20 | import nl.weeaboo.vn.buildtools.optimizer.IParallelExecutor; |
|
21 | 21 | import nl.weeaboo.vn.buildtools.optimizer.MainOptimizerConfig; |
|
22 | + | import nl.weeaboo.vn.buildtools.optimizer.OptimizerPreset; |
|
22 | 23 | import nl.weeaboo.vn.buildtools.optimizer.video.encoder.FfmpegVideoEncoder; |
|
23 | 24 | import nl.weeaboo.vn.buildtools.optimizer.video.encoder.IVideoEncoder; |
|
24 | 25 | import nl.weeaboo.vn.buildtools.optimizer.video.encoder.NoOpVideoEncoder; |
@@ -118,6 +119,10 @@
Loading
118 | 119 | } |
|
119 | 120 | ||
120 | 121 | private IVideoEncoder createEncoder() { |
|
122 | + | if (optimizerConfig.getPreset() == OptimizerPreset.LOSSLESS) { |
|
123 | + | return new NoOpVideoEncoder(); |
|
124 | + | } |
|
125 | + | ||
121 | 126 | if (ffmpegAvailable != EAvailable.NO) { |
|
122 | 127 | FfmpegVideoEncoder encoder = new FfmpegVideoEncoder(tempFileProvider); |
|
123 | 128 | if (ffmpegAvailable == EAvailable.YES || encoder.isAvailable()) { |
@@ -4,6 +4,7 @@
Loading
4 | 4 | import java.io.FileInputStream; |
|
5 | 5 | import java.io.IOException; |
|
6 | 6 | import java.io.InputStream; |
|
7 | + | import java.nio.file.Files; |
|
7 | 8 | ||
8 | 9 | import javax.annotation.Nullable; |
|
9 | 10 |
@@ -63,6 +64,11 @@
Loading
63 | 64 | return FileSystemUtil.readBytes(fileSystem, path); |
|
64 | 65 | } |
|
65 | 66 | ||
67 | + | @Override |
|
68 | + | public long getFileSize() throws IOException { |
|
69 | + | return fileSystem.getFileSize(path); |
|
70 | + | } |
|
71 | + | ||
66 | 72 | } |
|
67 | 73 | ||
68 | 74 | private static final class InMemoryResource implements IEncodedResource { |
@@ -87,6 +93,11 @@
Loading
87 | 93 | return result; |
|
88 | 94 | } |
|
89 | 95 | ||
96 | + | @Override |
|
97 | + | public long getFileSize() { |
|
98 | + | return bytes.length; |
|
99 | + | } |
|
100 | + | ||
90 | 101 | } |
|
91 | 102 | ||
92 | 103 | /** |
@@ -113,6 +124,11 @@
Loading
113 | 124 | } |
|
114 | 125 | } |
|
115 | 126 | ||
127 | + | @Override |
|
128 | + | public long getFileSize() throws IOException { |
|
129 | + | return Files.size(file.toPath()); |
|
130 | + | } |
|
131 | + | ||
116 | 132 | } |
|
117 | 133 | ||
118 | 134 | } |
@@ -16,11 +16,13 @@
Loading
16 | 16 | import com.badlogic.gdx.graphics.Pixmap.Format; |
|
17 | 17 | import com.google.common.collect.Iterators; |
|
18 | 18 | ||
19 | + | import nl.weeaboo.io.Filenames; |
|
19 | 20 | import nl.weeaboo.vn.buildtools.file.EncodedResource; |
|
20 | 21 | import nl.weeaboo.vn.buildtools.file.IEncodedResource; |
|
21 | 22 | import nl.weeaboo.vn.buildtools.optimizer.image.BufferedImageUtil; |
|
22 | 23 | import nl.weeaboo.vn.buildtools.optimizer.image.EncodedImage; |
|
23 | 24 | import nl.weeaboo.vn.buildtools.optimizer.image.ImageWithDef; |
|
25 | + | import nl.weeaboo.vn.impl.image.desc.ImageDefinitionBuilder; |
|
24 | 26 | ||
25 | 27 | final class DesktopJpegEncoder implements IJpegEncoder { |
|
26 | 28 |
@@ -67,7 +69,9 @@
Loading
67 | 69 | byte[] bytes = encode(image.getPixmap(), new JpegEncoderParams()); |
|
68 | 70 | ||
69 | 71 | IEncodedResource encodedImage = EncodedResource.fromBytes(bytes); |
|
70 | - | return new EncodedImage(encodedImage, image.getDef()); |
|
72 | + | ImageDefinitionBuilder imageDef = image.getDef().builder(); |
|
73 | + | imageDef.setFilename(Filenames.replaceExt(imageDef.getFilename(), "jpg")); |
|
74 | + | return new EncodedImage(encodedImage, imageDef.build()); |
|
71 | 75 | } |
|
72 | 76 | ||
73 | 77 | } |
@@ -9,9 +9,11 @@
Loading
9 | 9 | public final class MainOptimizerConfig implements IOptimizerConfig { |
|
10 | 10 | ||
11 | 11 | private final File outputFolder; |
|
12 | + | private final OptimizerPreset preset; |
|
12 | 13 | ||
13 | - | public MainOptimizerConfig(File outputFolder) { |
|
14 | + | public MainOptimizerConfig(File outputFolder, OptimizerPreset preset) { |
|
14 | 15 | this.outputFolder = Objects.requireNonNull(outputFolder); |
|
16 | + | this.preset = Objects.requireNonNull(preset); |
|
15 | 17 | } |
|
16 | 18 | ||
17 | 19 | /** |
@@ -21,4 +23,11 @@
Loading
21 | 23 | return outputFolder; |
|
22 | 24 | } |
|
23 | 25 | ||
26 | + | /** |
|
27 | + | * Preset which controls various quality/file-format settings. |
|
28 | + | */ |
|
29 | + | public OptimizerPreset getPreset() { |
|
30 | + | return preset; |
|
31 | + | } |
|
32 | + | ||
24 | 33 | } |
@@ -1,7 +1,7 @@
Loading
1 | 1 | package nl.weeaboo.vn.buildtools.optimizer; |
|
2 | 2 | ||
3 | 3 | import java.io.File; |
|
4 | - | import java.nio.file.Paths; |
|
4 | + | import java.nio.file.Path; |
|
5 | 5 | import java.util.ArrayList; |
|
6 | 6 | import java.util.List; |
|
7 | 7 | import java.util.regex.Matcher; |
@@ -18,21 +18,19 @@
Loading
18 | 18 | */ |
|
19 | 19 | public final class OptimizerConfigJson { |
|
20 | 20 | ||
21 | - | public String projectFolder; |
|
22 | - | public String buildToolsFolder; |
|
23 | - | ||
24 | 21 | /** Screen resolutions formatted as width x height, e.g. "1280x720". */ |
|
25 | - | public List<String> targetResolutions = new ArrayList<>(); |
|
22 | + | public final List<String> targetResolutions = new ArrayList<>(); |
|
23 | + | ||
24 | + | public OptimizerPreset preset = OptimizerPreset.LOSSLESS; |
|
26 | 25 | ||
27 | - | /** File exclusion patterns, see {@link OptimizerFileSet#exclude(nl.weeaboo.vn.buildtools.file.FilePathPattern)}. */ |
|
28 | - | public List<String> exclude = new ArrayList<>(); |
|
26 | + | /** File exclusion patterns, see {@link OptimizerFileSet#exclude(FilePathPattern)}. */ |
|
27 | + | public final List<String> exclude = new ArrayList<>(); |
|
29 | 28 | ||
30 | 29 | /** |
|
31 | 30 | * Opens a connection to a NVList project using the settings from this config. |
|
32 | 31 | */ |
|
33 | - | public NvlistProjectConnection openProject() { |
|
34 | - | return NvlistProjectConnection.openProject(new ProjectFolderConfig(Paths.get(projectFolder), |
|
35 | - | Paths.get(buildToolsFolder))); |
|
32 | + | public NvlistProjectConnection openProject(Path projectFolder, Path buildToolsFolder) { |
|
33 | + | return NvlistProjectConnection.openProject(new ProjectFolderConfig(projectFolder, buildToolsFolder)); |
|
36 | 34 | } |
|
37 | 35 | ||
38 | 36 | /** |
@@ -40,7 +38,7 @@
Loading
40 | 38 | */ |
|
41 | 39 | public OptimizerContext createContext(NvlistProjectConnection projectConnection, File outputFolder) { |
|
42 | 40 | // Main config |
|
43 | - | MainOptimizerConfig mainConfig = new MainOptimizerConfig(outputFolder); |
|
41 | + | MainOptimizerConfig mainConfig = new MainOptimizerConfig(outputFolder, preset); |
|
44 | 42 | OptimizerContext context = new OptimizerContext(projectConnection, mainConfig); |
|
45 | 43 | ||
46 | 44 | // Exclusion patterns |
@@ -73,4 +71,5 @@
Loading
73 | 71 | throw new IllegalArgumentException("Invalid resolution string: " + resolution); |
|
74 | 72 | } |
|
75 | 73 | } |
|
74 | + | ||
76 | 75 | } |
@@ -8,11 +8,13 @@
Loading
8 | 8 | ||
9 | 9 | import com.badlogic.gdx.graphics.Pixmap; |
|
10 | 10 | ||
11 | + | import nl.weeaboo.io.Filenames; |
|
11 | 12 | import nl.weeaboo.vn.buildtools.file.EncodedResource; |
|
12 | 13 | import nl.weeaboo.vn.buildtools.file.IEncodedResource; |
|
13 | 14 | import nl.weeaboo.vn.buildtools.optimizer.image.BufferedImageUtil; |
|
14 | 15 | import nl.weeaboo.vn.buildtools.optimizer.image.EncodedImage; |
|
15 | 16 | import nl.weeaboo.vn.buildtools.optimizer.image.ImageWithDef; |
|
17 | + | import nl.weeaboo.vn.impl.image.desc.ImageDefinitionBuilder; |
|
16 | 18 | ||
17 | 19 | final class DesktopPngEncoder implements IPngEncoder { |
|
18 | 20 |
@@ -31,7 +33,9 @@
Loading
31 | 33 | byte[] bytes = encode(image.getPixmap(), new PngEncoderParams()); |
|
32 | 34 | ||
33 | 35 | IEncodedResource encodedImage = EncodedResource.fromBytes(bytes); |
|
34 | - | return new EncodedImage(encodedImage, image.getDef()); |
|
36 | + | ImageDefinitionBuilder imageDef = image.getDef().builder(); |
|
37 | + | imageDef.setFilename(Filenames.replaceExt(imageDef.getFilename(), "png")); |
|
38 | + | return new EncodedImage(encodedImage, imageDef.build()); |
|
35 | 39 | } |
|
36 | 40 | ||
37 | 41 | } |
Files | Complexity | Coverage |
---|---|---|
api/src/main/java/nl/weeaboo/vn | 91.53% | 96.76% |
buildtools/src/main/java/nl/weeaboo/vn/buildtools | 81.13% | 87.46% |
core/src/main/java/nl/weeaboo/vn | 82.55% | 86.77% |
desktop/src/main/java/nl/weeaboo/vn/desktop | 1.52% | 2.26% |
Project Totals (383 files) | 81.01% | 84.34% |
768258239
Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file.
The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files.
The size and color of each slice is representing the number of statements and the coverage, respectively.