anonl / nvlist
Showing 15 of 34 files from the diff.

@@ -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 +
}

@@ -41,4 +41,9 @@
Loading
41 41
        soundDefinition = def;
42 42
    }
43 43
44 +
    @Override
45 +
    public long getFileSize() throws IOException {
46 +
        return encodedSound.getFileSize();
47 +
    }
48 +
44 49
}

@@ -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;

@@ -34,4 +34,9 @@
Loading
34 34
        return encodedVideo.readBytes();
35 35
    }
36 36
37 +
    @Override
38 +
    public long getFileSize() throws IOException {
39 +
        return encodedVideo.getFileSize();
40 +
    }
41 +
37 42
}

@@ -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%
1
codecov:
2
  status:
3
    project: yes
4
    patch: no
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.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading