propane 3.5.0-java → 3.6.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.mvn/extensions.xml +1 -1
  3. data/.mvn/wrapper/MavenWrapperDownloader.java +1 -1
  4. data/.mvn/wrapper/maven-wrapper.properties +2 -2
  5. data/.travis.yml +1 -1
  6. data/CHANGELOG.md +3 -1
  7. data/README.md +5 -13
  8. data/Rakefile +1 -1
  9. data/lib/propane.rb +2 -1
  10. data/lib/propane/helper_methods.rb +0 -1
  11. data/lib/propane/runner.rb +2 -0
  12. data/lib/propane/version.rb +1 -1
  13. data/pom.rb +43 -43
  14. data/pom.xml +4 -4
  15. data/propane.gemspec +4 -3
  16. data/src/main/java/japplemenubar/JAppleMenuBar.java +3 -3
  17. data/src/main/java/processing/awt/PGraphicsJava2D.java +8 -17
  18. data/src/main/java/processing/awt/PImageAWT.java +123 -6
  19. data/src/main/java/processing/awt/PShapeJava2D.java +1 -0
  20. data/src/main/java/processing/awt/PSurfaceAWT.java +9 -7
  21. data/src/main/java/processing/awt/ShimAWT.java +2 -1
  22. data/src/main/java/processing/core/PApplet.java +4605 -6014
  23. data/src/main/java/processing/core/PConstants.java +5 -5
  24. data/src/main/java/processing/core/PFont.java +5 -17
  25. data/src/main/java/processing/core/PGraphics.java +308 -320
  26. data/src/main/java/processing/core/PImage.java +1440 -1537
  27. data/src/main/java/processing/core/PMatrix2D.java +24 -7
  28. data/src/main/java/processing/core/PMatrix3D.java +12 -5
  29. data/src/main/java/processing/core/PShape.java +155 -173
  30. data/src/main/java/processing/core/PShapeOBJ.java +2 -0
  31. data/src/main/java/processing/core/PShapeSVG.java +632 -611
  32. data/src/main/java/processing/core/PSurface.java +15 -10
  33. data/src/main/java/processing/core/PSurfaceNone.java +8 -4
  34. data/src/main/java/processing/core/PVector.java +35 -28
  35. data/src/main/java/processing/data/Table.java +20 -20
  36. data/src/main/java/processing/data/XML.java +1 -1
  37. data/src/main/java/processing/event/Event.java +1 -1
  38. data/src/main/java/processing/event/MouseEvent.java +7 -6
  39. data/src/main/java/processing/javafx/PGraphicsFX2D.java +20 -345
  40. data/src/main/java/processing/javafx/PSurfaceFX.java +127 -125
  41. data/src/main/java/processing/opengl/FrameBuffer.java +2 -4
  42. data/src/main/java/processing/opengl/LinePath.java +4 -0
  43. data/src/main/java/processing/opengl/LineStroker.java +2 -6
  44. data/src/main/java/processing/opengl/PGL.java +72 -45
  45. data/src/main/java/processing/opengl/PGraphicsOpenGL.java +106 -60
  46. data/src/main/java/processing/opengl/PJOGL.java +15 -3
  47. data/src/main/java/processing/opengl/PShader.java +26 -47
  48. data/src/main/java/processing/opengl/PShapeOpenGL.java +1041 -1001
  49. data/src/main/java/processing/opengl/PSurfaceJOGL.java +211 -208
  50. data/src/main/java/processing/opengl/Texture.java +7 -4
  51. data/src/main/java/processing/opengl/VertexBuffer.java +2 -2
  52. data/vendors/Rakefile +22 -33
  53. metadata +38 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7837b349f30c7e79ee7e90b36eb7603174a0228d49fcaa8ec321ea5db24ae112
4
- data.tar.gz: 38d0c0cc6972e111fe2bb7a81cf3f5bbe20cbb795b31f880acfaaff8a1008023
3
+ metadata.gz: f8e0f1b907888514e27260110225621d9fa5f7792d319ddae436540bd98be75a
4
+ data.tar.gz: f26c694203a50b98df365b2b003d2c258c11c87e550618a146158a69dfa7954e
5
5
  SHA512:
6
- metadata.gz: 9f2f530ad672d28338340409760883e5bec5ce735a07fac5b76e9fba5e8965c37674410eb54c6aeec46d78e3568850719765738c71b359cdb37a0b30d6060af5
7
- data.tar.gz: b0f30134fb858c2dbbc3a40eb9772e9788e1bca09f3cb2c893139bf690cef294d9dc5a30cf3667fd73016144807f6778b2cb5d13a02111f85ae56c91e5a64a17
6
+ metadata.gz: 1263af382d8cec20f5d16d760d0afe542802955ee42bb398e4ca28e8e5583ca04a04fd619529567b5df78cadd3f824c17de8d860a8ba1c3f003b2453a87fa16a
7
+ data.tar.gz: 90b9e87ca02ee5dde1bfd71dc51efc91574ee2855fddfea113793d2e3d8434b07f090d2170c0a4df798fd6b200846cb9645415c09158d684f3a757ef8ee0682f
@@ -3,6 +3,6 @@
3
3
  <extension>
4
4
  <groupId>io.takari.polyglot</groupId>
5
5
  <artifactId>polyglot-ruby</artifactId>
6
- <version>0.4.4</version>
6
+ <version>0.4.5</version>
7
7
  </extension>
8
8
  </extensions>
@@ -20,7 +20,7 @@ import java.util.Properties;
20
20
 
21
21
  public class MavenWrapperDownloader {
22
22
 
23
- private static final String WRAPPER_VERSION = "0.5.5";
23
+ private static final String WRAPPER_VERSION = "0.5.6";
24
24
  /**
25
25
  * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
26
26
  */
@@ -1,2 +1,2 @@
1
- distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.1/apache-maven-3.6.1-bin.zip
2
- wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar
1
+ distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
2
+ wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
@@ -2,7 +2,7 @@ language: java
2
2
  dist: bionic
3
3
 
4
4
  rvm:
5
- - jruby-9.2.11.1
5
+ - jruby-9.2.12.0
6
6
  jdk:
7
7
  - openjdk11
8
8
  os:
@@ -1,4 +1,6 @@
1
- **v3.5.0** Rebase processing core code around Sam Pottinhgers latest fixes for JOGL an image save, does mean breaking some of Diwis and Joshua Davis examples, but one hopes codeanticode knows what he's doing.
1
+ **v3.6.0** Recommend JRuby-9.2.14.0 use video-2.0 release
2
+
3
+ **v3.5.0** Rebase processing core code around Sam Pottingers latest fixes for JOGL an image save, does mean breaking some of Diwis and Joshua Davis examples, but one hopes codeanticode knows what he's doing.
2
4
 
3
5
  **v3.4.3** Use Map.of to initialize HashMap bump processing version in build bump to jruby-9.2.11.0
4
6
 
data/README.md CHANGED
@@ -11,7 +11,7 @@ adjust above for your OS/distro setup.
11
11
  There may be a linker issue with P2D or P3D sketches with stock openjdk with some linux distros, in which case you might find [Adopt open jdk binaries][adopt] will work for you.
12
12
 
13
13
  - `jdk-11.0.3+`
14
- - `jruby-9.2.11.1`
14
+ - `jruby-9.2.12.0`
15
15
 
16
16
  Currently you can ignore `illegal reflective access` warnings, see [here how to suppress them][warning].
17
17
 
@@ -27,10 +27,10 @@ rake javadoc
27
27
 
28
28
  ```bash
29
29
  jgem install propane # from rubygems
30
- jgem install propane-3.4.3-java.gem # local install
30
+ jgem install propane-3.6.0-java.gem # local install
31
31
  # Alternative
32
32
  jruby -S gem install propane # from rubygems
33
- jruby -S gem install propane-3.4.3-java.gem # local install
33
+ jruby -S gem install propane-3.6.0-java.gem # local install
34
34
  ```
35
35
 
36
36
  ## Check Install
@@ -42,15 +42,7 @@ propane --version
42
42
 
43
43
  ## Suppressing Reflective Access warnings
44
44
 
45
- Since propane-3.4.3 it is possible to suppress reflective access warnings by including a `~/.jruby.java_opts` file with following contents:-
46
-
47
- ```bash
48
- --add-opens java.base/java.lang=ALL-UNNAMED
49
- --add-opens java.desktop/java.awt=ALL-UNNAMED
50
- --add-opens java.desktop/sun.awt=ALL-UNNAMED
51
- --add-opens java.desktop/sun.java2d.opengl=ALL-UNNAMED
52
- ```
53
- Mainly needed for opengl sketches.
45
+ Since propane-3.5.0 it is possible to suppress reflective access warnings by setting JAVA_HOME environmental variable jruby does the rest.
54
46
 
55
47
  ## Usage
56
48
 
@@ -103,7 +95,7 @@ See [gh-pages][gh-pages] for more detailed instructions and much more.
103
95
 
104
96
  ## Examples
105
97
 
106
- [Worked Examples](https://github.com/ruby-processing/propane-examples) more to follow, feel free to add your own, especially ruby-2.4
98
+ [Worked Examples](https://github.com/ruby-processing/propane-examples) more to follow, feel free to add your own, especially ruby-2.5
107
99
  + syntax now we can. To install the samples. The samples get copied to `~/propane_samples`. Depends on wget.
108
100
  ```bash
109
101
  propane --install samples
data/Rakefile CHANGED
@@ -22,7 +22,7 @@ end
22
22
 
23
23
  desc 'Gem'
24
24
  task :gem do
25
- sh 'gem build propane.gemspec'
25
+ sh 'jgem build propane.gemspec'
26
26
  end
27
27
 
28
28
  desc 'Document'
@@ -8,4 +8,5 @@ end
8
8
  Dir["#{PROPANE_ROOT}/lib/*.jar"].sort.each do |jar|
9
9
  require jar
10
10
  end
11
- require_relative 'propane/app'
11
+ require "#{PROPANE_ROOT}/lib/propane/app"
12
+ require "#{PROPANE_ROOT}/lib/propane/helpers/numeric"
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: false
2
2
 
3
3
  # processing module wrapper
4
- require_relative 'helpers/numeric'
5
4
  module Propane
6
5
  # Provides some convenience methods
7
6
  module HelperMethods
@@ -55,6 +55,8 @@ module Propane
55
55
  # assumed to have this option.
56
56
  opts.on('-h', '--help', 'Display this screen') do
57
57
  puts opts
58
+ puts ''
59
+ puts 'Run a sketch: jruby [--dev] [<sketch.rb>]'
58
60
  exit
59
61
  end
60
62
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Propane
4
- VERSION = '3.5.0'
4
+ VERSION = '3.6.0'
5
5
  end
data/pom.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  project 'propane', 'https://github.com/monkstone/propane' do
4
4
  model_version '4.0.0'
5
- id 'propane:propane:3.5.0'
5
+ id 'propane:propane:3.6.0'
6
6
  packaging 'jar'
7
7
 
8
8
  description 'An integrated processing-core (somewhat hacked), with additional java code for a jruby version of processing.'
@@ -35,48 +35,48 @@ project 'propane', 'https://github.com/monkstone/propane' do
35
35
  issue_management 'https://github.com/ruby-processing/propane/issues', 'Github'
36
36
 
37
37
  source_control(url: 'https://github.com/ruby-processing/propane',
38
- connection: 'scm:git:git://github.com/ruby-processing/propane.git',
39
- developer_connection: 'scm:git:git@github.com/ruby-processing/propane.git')
38
+ connection: 'scm:git:git://github.com/ruby-processing/propane.git',
39
+ developer_connection: 'scm:git:git@github.com/ruby-processing/propane.git')
40
40
 
41
- properties('propane.basedir' => '${project.basedir}',
42
- 'processing.api' => 'http://processing.github.io/processing-javadocs/core/',
43
- 'source.directory' => 'src',
44
- 'polyglot.dump.pom' => 'pom.xml',
45
- 'project.build.sourceEncoding' => 'utf-8',
46
- 'jogl.version' => '2.3.2', # for compiling actual included 2.4.0-rc
47
- 'jruby.api' => 'http://jruby.org/apidocs/')
41
+ properties('propane.basedir' => '${project.basedir}',
42
+ 'processing.api' => 'http://processing.github.io/processing-javadocs/core/',
43
+ 'source.directory' => 'src',
44
+ 'polyglot.dump.pom' => 'pom.xml',
45
+ 'project.build.sourceEncoding' => 'utf-8',
46
+ 'jogl.version' => '2.3.2', # for compiling actual included 2.4.0-rc
47
+ 'jruby.api' => 'http://jruby.org/apidocs/')
48
48
 
49
- pom 'org.jruby:jruby:9.2.11.1'
50
- jar 'org.processing:video:3.3.7' # only for compiling
51
- jar 'org.jogamp.jogl:jogl-all:${jogl.version}'
52
- jar 'org.jogamp.gluegen:gluegen-rt-main:${jogl.version}'
49
+ pom 'org.jruby:jruby:9.2.14.0'
50
+ jar 'org.processing:video:3.3.7' # only for compiling
51
+ jar 'org.jogamp.jogl:jogl-all:${jogl.version}'
52
+ jar 'org.jogamp.gluegen:gluegen-rt-main:${jogl.version}'
53
53
 
54
- overrides do
55
- plugin('org.codehaus.mojo:versions-maven-plugin:2.7',
56
- 'generateBackupPoms' => 'false')
57
- plugin(:compiler, '3.8.1',
58
- 'release' => '11')
59
- plugin(:javadoc, '3.2.0',
60
- 'detectOfflineLinks' => 'false',
61
- 'links' => ['${jruby.api}',
62
- '${processing.api}'])
63
- plugin(
64
- :jar, '3.2.0',
65
- 'archive' => {
66
- 'manifestEntries' => { 'Class-Path' => 'gluegen-rt.jar jog-all.jar' }
67
- }
68
- )
69
- end
70
- build do
71
- resource do
72
- directory '${source.directory}/main/java'
73
- includes '**/**/*.glsl', '**/*.jnilib'
74
- excludes '**/**/*.java'
75
- end
76
- resource do
77
- directory '${source.directory}/main/resources'
78
- includes '**/*.png', '*.txt'
79
- excludes
80
- end
81
- end
82
- end
54
+ overrides do
55
+ plugin('org.codehaus.mojo:versions-maven-plugin:2.7',
56
+ 'generateBackupPoms' => 'false')
57
+ plugin(:compiler, '3.8.1',
58
+ 'release' => '11')
59
+ plugin(:javadoc, '3.2.0',
60
+ 'detectOfflineLinks' => 'false',
61
+ 'links' => ['${jruby.api}',
62
+ '${processing.api}'])
63
+ plugin(:jar, '3.2.0',
64
+ 'archive' => {
65
+ 'manifestEntries' => {
66
+ 'Automatic-Module-Name' => 'processing.core'
67
+ }
68
+ })
69
+ end
70
+ build do
71
+ resource do
72
+ directory '${source.directory}/main/java'
73
+ includes '**/**/*.glsl', '**/*.jnilib'
74
+ excludes '**/**/*.java'
75
+ end
76
+ resource do
77
+ directory '${source.directory}/main/resources'
78
+ includes '**/*.png', '*.txt'
79
+ excludes
80
+ end
81
+ end
82
+ end
data/pom.xml CHANGED
@@ -6,12 +6,12 @@ DO NOT MODIFIY - GENERATED CODE
6
6
 
7
7
 
8
8
  -->
9
- <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
9
+ <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
10
10
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
11
11
  <modelVersion>4.0.0</modelVersion>
12
12
  <groupId>propane</groupId>
13
13
  <artifactId>propane</artifactId>
14
- <version>3.5.0</version>
14
+ <version>3.6.0</version>
15
15
  <name>propane</name>
16
16
  <description>An integrated processing-core (somewhat hacked), with additional java code for a jruby version of processing.</description>
17
17
  <url>https://github.com/monkstone/propane</url>
@@ -74,7 +74,7 @@ DO NOT MODIFIY - GENERATED CODE
74
74
  <dependency>
75
75
  <groupId>org.jruby</groupId>
76
76
  <artifactId>jruby</artifactId>
77
- <version>9.2.11.1</version>
77
+ <version>9.2.14.0</version>
78
78
  <type>pom</type>
79
79
  </dependency>
80
80
  <dependency>
@@ -147,7 +147,7 @@ DO NOT MODIFIY - GENERATED CODE
147
147
  <configuration>
148
148
  <archive>
149
149
  <manifestEntries>
150
- <Class-Path>gluegen-rt.jar jog-all.jar</Class-Path>
150
+ <Automatic-Module-Name>processing.core</Automatic-Module-Name>
151
151
  </manifestEntries>
152
152
  </archive>
153
153
  </configuration>
@@ -27,9 +27,10 @@ Gem::Specification.new do |gem|
27
27
  gem.files << 'lib/jogl-all-natives-windows-amd64.jar'
28
28
  gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
29
29
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
30
- gem.add_development_dependency 'minitest', '~> 5.11'
31
- gem.add_development_dependency 'rake', '~> 12.3'
32
- gem.add_runtime_dependency 'arcball', '~> 1.0', '>= 1.0.0'
30
+ gem.add_development_dependency 'jruby-openssl', '~> 0.1.0', '>=0.1.3'
31
+ gem.add_development_dependency 'minitest', '~> 5.14'
32
+ gem.add_runtime_dependency 'rake', '~> 12.3'
33
+ gem.add_runtime_dependency 'arcball', '~> 1.0', '>= 1.0.2'
33
34
  gem.require_paths = ['lib']
34
35
  gem.platform = 'java'
35
36
  gem.requirements << 'java runtime >= 11.0.2+'
@@ -19,9 +19,8 @@
19
19
  */
20
20
  package japplemenubar;
21
21
 
22
- import java.io.File;
23
- import java.io.IOException;
24
- import java.io.InputStream;
22
+ import java.io.*;
23
+
25
24
  import processing.core.PApplet;
26
25
 
27
26
 
@@ -59,6 +58,7 @@ public class JAppleMenuBar {
59
58
  }
60
59
  } catch (IOException e) {
61
60
  sadness("Unknown error, here's the stack trace.");
61
+ e.printStackTrace();
62
62
  }
63
63
  }
64
64
 
@@ -541,7 +541,7 @@ public class PGraphicsJava2D extends PGraphics {
541
541
  // try {
542
542
  // ImageIO.write(image, "jpg", new java.io.File("/Users/fry/Desktop/buff.jpg"));
543
543
  // } catch (IOException e) {
544
- //
544
+ // e.printStackTrace();
545
545
  // }
546
546
  // }
547
547
  // }
@@ -994,10 +994,9 @@ public class PGraphicsJava2D extends PGraphics {
994
994
  // BLEND
995
995
 
996
996
  /**
997
+ * ( begin auto-generated from blendMode.xml )
997
998
  *
998
- * This is a new reference entry for Processing 2.0.It will be updated shortly.
999
- *
1000
- *
999
+ * This is a new reference entry for Processing 2.0.It will be updated shortly. ( end auto-generated )
1001
1000
  *
1002
1001
  * @webref Rendering
1003
1002
  */
@@ -1565,15 +1564,6 @@ public class PGraphicsJava2D extends PGraphics {
1565
1564
 
1566
1565
  /**
1567
1566
  * Handle renderer-specific image drawing.
1568
- * @param who
1569
- * @param x1
1570
- * @param y1
1571
- * @param x2
1572
- * @param y2
1573
- * @param u1
1574
- * @param v1
1575
- * @param u2
1576
- * @param v2
1577
1567
  */
1578
1568
  @Override
1579
1569
  protected void imageImpl(PImage who,
@@ -3042,8 +3032,9 @@ public class PGraphicsJava2D extends PGraphics {
3042
3032
  // SAVE
3043
3033
 
3044
3034
 
3045
- // public void save(String filename) {
3046
- // loadPixels();
3047
- // super.save(filename);
3048
- // }
3035
+ @Override
3036
+ public boolean save(String filename) {
3037
+ PImageAWT outImage = new PImageAWT(image);
3038
+ return outImage.save(filename);
3039
+ }
3049
3040
  }
@@ -31,8 +31,21 @@ import java.awt.image.DataBuffer;
31
31
  import java.awt.image.DataBufferInt;
32
32
  import java.awt.image.PixelGrabber;
33
33
  import java.awt.image.WritableRaster;
34
+ import java.io.BufferedOutputStream;
35
+ import java.io.File;
34
36
  import java.io.IOException;
35
-
37
+ import java.util.Iterator;
38
+
39
+ import javax.imageio.IIOImage;
40
+ import javax.imageio.ImageIO;
41
+ import javax.imageio.ImageTypeSpecifier;
42
+ import javax.imageio.ImageWriteParam;
43
+ import javax.imageio.ImageWriter;
44
+ import javax.imageio.metadata.IIOInvalidTreeException;
45
+ import javax.imageio.metadata.IIOMetadata;
46
+ import javax.imageio.metadata.IIOMetadataNode;
47
+
48
+ import processing.core.PApplet;
36
49
  import processing.core.PImage;
37
50
 
38
51
 
@@ -202,10 +215,8 @@ public class PImageAWT extends PImage {
202
215
  prevH = h;
203
216
  outgoing = scratchImage;
204
217
  } while (w != targetWidth || h != targetHeight);
218
+ g2.dispose();
205
219
 
206
- if (g2 != null) {
207
- g2.dispose();
208
- }
209
220
 
210
221
  // If we used a scratch buffer that is larger than our target size,
211
222
  // create an image of the right size and copy the results into it
@@ -251,10 +262,116 @@ public class PImageAWT extends PImage {
251
262
  * Use ImageIO functions from Java 1.4 and later to handle image save.
252
263
  * Various formats are supported, typically jpeg, png, bmp, and wbmp.
253
264
  * To get a list of the supported formats for writing, use: <BR>
254
- * <code>println(javax.imageio.ImageIO.getReaderFormatNames())</code>
265
+ * <TT>println(javax.imageio.ImageIO.getReaderFormatNames())</TT>
266
+ *
267
+ * @path The path to which the file should be written.
255
268
  */
256
269
  protected boolean saveImageIO(String path) throws IOException {
257
- return PImage.saveViaImageIO(this, path);
270
+ try {
271
+ int outputFormat = (format == ARGB) ?
272
+ BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB;
273
+
274
+ String extension =
275
+ path.substring(path.lastIndexOf('.') + 1).toLowerCase();
276
+
277
+ // JPEG and BMP images that have an alpha channel set get pretty unhappy.
278
+ // BMP just doesn't write, and JPEG writes it as a CMYK image.
279
+ // http://code.google.com/p/processing/issues/detail?id=415
280
+ if (extension.equals("bmp") || extension.equals("jpg") || extension.equals("jpeg")) {
281
+ outputFormat = BufferedImage.TYPE_INT_RGB;
282
+ }
283
+
284
+ BufferedImage bimage = new BufferedImage(pixelWidth, pixelHeight, outputFormat);
285
+ bimage.setRGB(0, 0, pixelWidth, pixelHeight, pixels, 0, pixelWidth);
286
+
287
+ File file = new File(path);
288
+
289
+ ImageWriter writer = null;
290
+ ImageWriteParam param = null;
291
+ IIOMetadata metadata = null;
292
+
293
+ if (extension.equals("jpg") || extension.equals("jpeg")) {
294
+ if ((writer = imageioWriter("jpeg")) != null) {
295
+ // Set JPEG quality to 90% with baseline optimization. Setting this
296
+ // to 1 was a huge jump (about triple the size), so this seems good.
297
+ // Oddly, a smaller file size than Photoshop at 90%, but I suppose
298
+ // it's a completely different algorithm.
299
+ param = writer.getDefaultWriteParam();
300
+ param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
301
+ param.setCompressionQuality(0.9f);
302
+ }
303
+ }
304
+
305
+ if (extension.equals("png")) {
306
+ if ((writer = imageioWriter("png")) != null) {
307
+ param = writer.getDefaultWriteParam();
308
+ if (false) {
309
+ metadata = imageioDPI(writer, param, 100);
310
+ }
311
+ }
312
+ }
313
+
314
+ if (writer != null) {
315
+ try (BufferedOutputStream output = new BufferedOutputStream(PApplet.createOutput(file))) {
316
+ writer.setOutput(ImageIO.createImageOutputStream(output));
317
+ // writer.write(null, new IIOImage(bimage, null, null), param);
318
+ writer.write(metadata, new IIOImage(bimage, null, metadata), param);
319
+ writer.dispose();
320
+
321
+ output.flush();
322
+ }
323
+ return true;
324
+ }
325
+ // If iter.hasNext() somehow fails up top, it falls through to here
326
+ return javax.imageio.ImageIO.write(bimage, extension, file);
327
+
328
+ } catch (IOException e) {
329
+ throw new IOException("image save failed.");
330
+ }
331
+ }
332
+
333
+
334
+ private ImageWriter imageioWriter(String extension) {
335
+ Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName(extension);
336
+ if (iter.hasNext()) {
337
+ return iter.next();
338
+ }
339
+ return null;
258
340
  }
259
341
 
342
+
343
+ private IIOMetadata imageioDPI(ImageWriter writer, ImageWriteParam param, double dpi) {
344
+ // http://stackoverflow.com/questions/321736/how-to-set-dpi-information-in-an-image
345
+ ImageTypeSpecifier typeSpecifier =
346
+ ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB);
347
+ IIOMetadata metadata =
348
+ writer.getDefaultImageMetadata(typeSpecifier, param);
349
+
350
+ if (!metadata.isReadOnly() && metadata.isStandardMetadataFormatSupported()) {
351
+ // for PNG, it's dots per millimeter
352
+ double dotsPerMilli = dpi / 25.4;
353
+
354
+ IIOMetadataNode horiz = new IIOMetadataNode("HorizontalPixelSize");
355
+ horiz.setAttribute("value", Double.toString(dotsPerMilli));
356
+
357
+ IIOMetadataNode vert = new IIOMetadataNode("VerticalPixelSize");
358
+ vert.setAttribute("value", Double.toString(dotsPerMilli));
359
+
360
+ IIOMetadataNode dim = new IIOMetadataNode("Dimension");
361
+ dim.appendChild(horiz);
362
+ dim.appendChild(vert);
363
+
364
+ IIOMetadataNode root = new IIOMetadataNode("javax_imageio_1.0");
365
+ root.appendChild(dim);
366
+
367
+ try {
368
+ metadata.mergeTree("javax_imageio_1.0", root);
369
+ return metadata;
370
+
371
+ } catch (IIOInvalidTreeException e) {
372
+ System.err.println("Could not set the DPI of the output image");
373
+ }
374
+ }
375
+ return null;
376
+ }
260
377
  }