propane 3.4.2-java → 3.8.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.mvn/extensions.xml +1 -1
- data/.mvn/wrapper/MavenWrapperDownloader.java +2 -2
- data/.mvn/wrapper/maven-wrapper.properties +2 -2
- data/.travis.yml +1 -1
- data/CHANGELOG.md +9 -1
- data/Gemfile +2 -0
- data/README.md +7 -10
- data/Rakefile +10 -11
- data/bin/propane +3 -1
- data/lib/propane.rb +4 -2
- data/lib/propane/app.rb +5 -1
- data/lib/propane/creators/sketch_class.rb +7 -1
- data/lib/propane/creators/sketch_factory.rb +4 -2
- data/lib/propane/creators/sketch_writer.rb +1 -0
- data/lib/propane/helper_methods.rb +22 -23
- data/lib/propane/helpers/numeric.rb +2 -0
- data/lib/propane/helpers/version_error.rb +1 -0
- data/lib/propane/library.rb +5 -1
- data/lib/propane/library_loader.rb +2 -0
- data/lib/propane/native_folder.rb +10 -9
- data/lib/propane/native_loader.rb +3 -0
- data/lib/propane/runner.rb +20 -14
- data/lib/propane/version.rb +2 -1
- data/library/boids/boids.rb +21 -11
- data/library/color_group/color_group.rb +2 -0
- data/library/control_panel/control_panel.rb +8 -5
- data/library/dxf/dxf.rb +2 -0
- data/library/file_chooser/chooser.rb +10 -9
- data/library/file_chooser/file_chooser.rb +10 -9
- data/library/library_proxy/library_proxy.rb +2 -0
- data/library/net/net.rb +2 -0
- data/library/slider/slider.rb +23 -22
- data/library/vector_utils/vector_utils.rb +4 -0
- data/library/video_event/video_event.rb +2 -0
- data/pom.rb +37 -36
- data/pom.xml +7 -7
- data/propane.gemspec +13 -9
- data/src/main/java/japplemenubar/JAppleMenuBar.java +3 -3
- data/src/main/java/monkstone/ColorUtil.java +1 -3
- data/src/main/java/monkstone/MathToolModule.java +1 -1
- data/src/main/java/monkstone/PropaneLibrary.java +2 -2
- data/src/main/java/monkstone/fastmath/DegLutTables.java +111 -0
- data/src/main/java/monkstone/fastmath/Deglut.java +6 -56
- data/src/main/java/monkstone/filechooser/Chooser.java +1 -1
- data/src/main/java/monkstone/noise/Noise.java +116 -0
- data/src/main/java/monkstone/noise/NoiseGenerator.java +63 -0
- data/src/main/java/monkstone/noise/NoiseMode.java +15 -0
- data/src/main/java/monkstone/noise/SimplexNoise.java +137 -103
- data/src/main/java/monkstone/noise/ValueNoise.java +170 -0
- data/src/main/java/monkstone/slider/CustomHorizontalSlider.java +1 -1
- data/src/main/java/monkstone/slider/CustomVerticalSlider.java +1 -1
- data/src/main/java/monkstone/slider/SimpleHorizontalSlider.java +1 -1
- data/src/main/java/monkstone/slider/SimpleVerticalSlider.java +1 -1
- data/src/main/java/monkstone/slider/SliderBar.java +1 -1
- data/src/main/java/monkstone/slider/SliderGroup.java +1 -1
- data/src/main/java/monkstone/slider/WheelHandler.java +1 -1
- data/src/main/java/monkstone/vecmath/package-info.java +1 -1
- data/src/main/java/monkstone/vecmath/vec2/Vec2.java +1 -1
- data/src/main/java/monkstone/vecmath/vec3/Vec3.java +1 -2
- data/src/main/java/monkstone/videoevent/CaptureEvent.java +1 -1
- data/src/main/java/monkstone/videoevent/MovieEvent.java +1 -1
- data/src/main/java/monkstone/videoevent/package-info.java +1 -1
- data/src/main/java/processing/awt/PGraphicsJava2D.java +781 -285
- data/src/main/java/processing/awt/PImageAWT.java +377 -0
- data/src/main/java/processing/awt/PShapeJava2D.java +56 -52
- data/src/main/java/processing/awt/PSurfaceAWT.java +308 -208
- data/src/main/java/processing/awt/ShimAWT.java +581 -0
- data/src/main/java/processing/core/PApplet.java +13142 -13883
- data/src/main/java/processing/core/PConstants.java +477 -447
- data/src/main/java/processing/core/PFont.java +914 -880
- data/src/main/java/processing/core/PGraphics.java +152 -136
- data/src/main/java/processing/core/PImage.java +275 -372
- data/src/main/java/processing/core/PMatrix.java +172 -159
- data/src/main/java/processing/core/PMatrix2D.java +478 -415
- data/src/main/java/processing/core/PMatrix3D.java +762 -735
- data/src/main/java/processing/core/PShape.java +2887 -2651
- data/src/main/java/processing/core/PShapeOBJ.java +97 -92
- data/src/main/java/processing/core/PShapeSVG.java +1705 -1490
- data/src/main/java/processing/core/PStyle.java +40 -37
- data/src/main/java/processing/core/PSurface.java +139 -97
- data/src/main/java/processing/core/PSurfaceNone.java +296 -218
- data/src/main/java/processing/core/PVector.java +995 -963
- data/src/main/java/processing/core/ThinkDifferent.java +12 -8
- data/src/main/java/processing/data/DoubleDict.java +756 -710
- data/src/main/java/processing/data/DoubleList.java +749 -696
- data/src/main/java/processing/data/FloatDict.java +748 -702
- data/src/main/java/processing/data/FloatList.java +751 -697
- data/src/main/java/processing/data/IntDict.java +720 -673
- data/src/main/java/processing/data/IntList.java +699 -633
- data/src/main/java/processing/data/JSONArray.java +931 -873
- data/src/main/java/processing/data/JSONObject.java +1262 -1165
- data/src/main/java/processing/data/JSONTokener.java +351 -341
- data/src/main/java/processing/data/LongDict.java +710 -663
- data/src/main/java/processing/data/LongList.java +701 -635
- data/src/main/java/processing/data/Sort.java +37 -41
- data/src/main/java/processing/data/StringDict.java +525 -486
- data/src/main/java/processing/data/StringList.java +626 -580
- data/src/main/java/processing/data/Table.java +3690 -3510
- data/src/main/java/processing/data/TableRow.java +182 -183
- data/src/main/java/processing/data/XML.java +957 -883
- data/src/main/java/processing/event/Event.java +87 -67
- data/src/main/java/processing/event/KeyEvent.java +48 -41
- data/src/main/java/processing/event/MouseEvent.java +88 -113
- data/src/main/java/processing/event/TouchEvent.java +10 -6
- data/src/main/java/processing/javafx/PGraphicsFX2D.java +20 -345
- data/src/main/java/processing/javafx/PSurfaceFX.java +149 -121
- data/src/main/java/processing/net/Client.java +20 -20
- data/src/main/java/processing/net/Server.java +9 -9
- data/src/main/java/processing/opengl/FontTexture.java +286 -266
- data/src/main/java/processing/opengl/FrameBuffer.java +389 -377
- data/src/main/java/processing/opengl/LinePath.java +132 -89
- data/src/main/java/processing/opengl/LineStroker.java +588 -581
- data/src/main/java/processing/opengl/PGL.java +660 -567
- data/src/main/java/processing/opengl/PGraphics2D.java +408 -315
- data/src/main/java/processing/opengl/PGraphics3D.java +107 -72
- data/src/main/java/processing/opengl/PGraphicsOpenGL.java +12378 -12075
- data/src/main/java/processing/opengl/PJOGL.java +1753 -1670
- data/src/main/java/processing/opengl/PShader.java +369 -461
- data/src/main/java/processing/opengl/PShapeOpenGL.java +4678 -4580
- data/src/main/java/processing/opengl/PSurfaceJOGL.java +1114 -1027
- data/src/main/java/processing/opengl/Texture.java +1492 -1401
- data/src/main/java/processing/opengl/VertexBuffer.java +57 -55
- data/test/create_test.rb +21 -20
- data/test/deglut_spec_test.rb +4 -2
- data/test/helper_methods_test.rb +49 -20
- data/test/math_tool_test.rb +39 -32
- data/test/native_folder.rb +47 -0
- data/test/respond_to_test.rb +3 -2
- data/test/sketches/key_event.rb +2 -2
- data/test/sketches/library/my_library/my_library.rb +3 -0
- data/test/test_helper.rb +2 -0
- data/test/vecmath_spec_test.rb +35 -22
- data/vendors/Rakefile +35 -40
- metadata +47 -23
- data/library/simplex_noise/simplex_noise.rb +0 -3
- data/src/main/java/processing/opengl/shaders/LightVert-brcm.glsl +0 -154
- data/src/main/java/processing/opengl/shaders/LightVert-vc4.glsl +0 -154
- data/src/main/java/processing/opengl/shaders/TexLightVert-brcm.glsl +0 -160
- data/src/main/java/processing/opengl/shaders/TexLightVert-vc4.glsl +0 -160
|
@@ -24,13 +24,12 @@
|
|
|
24
24
|
|
|
25
25
|
package processing.core;
|
|
26
26
|
|
|
27
|
-
import java.
|
|
28
|
-
import java.
|
|
29
|
-
import java.io
|
|
30
|
-
import java.
|
|
31
|
-
|
|
32
|
-
import
|
|
33
|
-
import javax.imageio.metadata.*;
|
|
27
|
+
import java.io.BufferedOutputStream;
|
|
28
|
+
import java.io.File;
|
|
29
|
+
import java.io.FileOutputStream;
|
|
30
|
+
import java.io.IOException;
|
|
31
|
+
import java.io.InputStream;
|
|
32
|
+
import java.io.OutputStream;
|
|
34
33
|
|
|
35
34
|
|
|
36
35
|
/**
|
|
@@ -43,11 +42,11 @@ import javax.imageio.metadata.*;
|
|
|
43
42
|
* fields for the <b>width</b> and <b>height</b> of the image, as well as
|
|
44
43
|
* an array called <b>pixels[]</b> that contains the values for every pixel
|
|
45
44
|
* in the image. The methods described below allow easy access to the
|
|
46
|
-
* image's pixels and alpha channel and simplify the process of compositing
|
|
47
|
-
*
|
|
45
|
+
* image's pixels and alpha channel and simplify the process of compositing.
|
|
46
|
+
* using the <b>pixels[]</b> array, be sure to use the
|
|
48
47
|
* <b>loadPixels()</b> method on the image to make sure that the pixel data
|
|
49
|
-
* is properly loaded
|
|
50
|
-
*
|
|
48
|
+
* is properly loaded.
|
|
49
|
+
* create a new image, use the <b>createImage()</b> function. Do not
|
|
51
50
|
* use the syntax <b>new PImage()</b>.
|
|
52
51
|
*
|
|
53
52
|
* ( end auto-generated )
|
|
@@ -198,11 +197,11 @@ public class PImage implements PConstants, Cloneable {
|
|
|
198
197
|
* pixel in the image. A group of methods, described below, allow easy
|
|
199
198
|
* access to the image's pixels and alpha channel and simplify the process
|
|
200
199
|
* of compositing.
|
|
201
|
-
*
|
|
200
|
+
*
|
|
202
201
|
* Before using the <b>pixels[]</b> array, be sure to use the
|
|
203
202
|
* <b>loadPixels()</b> method on the image to make sure that the pixel data
|
|
204
203
|
* is properly loaded.
|
|
205
|
-
*
|
|
204
|
+
*
|
|
206
205
|
* To create a new image, use the <b>createImage()</b> function (do not use
|
|
207
206
|
* <b>new PImage()</b>).
|
|
208
207
|
* ( end auto-generated )
|
|
@@ -281,7 +280,7 @@ public class PImage implements PConstants, Cloneable {
|
|
|
281
280
|
/**
|
|
282
281
|
* Check the alpha on an image, using a really primitive loop.
|
|
283
282
|
*/
|
|
284
|
-
|
|
283
|
+
public void checkAlpha() {
|
|
285
284
|
if (pixels == null) return;
|
|
286
285
|
|
|
287
286
|
for (int i = 0; i < pixels.length; i++) {
|
|
@@ -332,82 +331,9 @@ public class PImage implements PConstants, Cloneable {
|
|
|
332
331
|
this.pixels = pixels;
|
|
333
332
|
}
|
|
334
333
|
|
|
335
|
-
/**
|
|
336
|
-
* Construct a new PImage from a java.awt.Image. This constructor assumes
|
|
337
|
-
* that you've done the work of making sure a MediaTracker has been used
|
|
338
|
-
* to fully download the data and that the img is valid.
|
|
339
|
-
*
|
|
340
|
-
* @nowebref
|
|
341
|
-
* @param img assumes a MediaTracker has been used to fully download
|
|
342
|
-
* the data and the img is valid
|
|
343
|
-
*/
|
|
344
|
-
public PImage(Image img) {
|
|
345
|
-
format = RGB;
|
|
346
|
-
if (img instanceof BufferedImage) {
|
|
347
|
-
BufferedImage bi = (BufferedImage) img;
|
|
348
|
-
width = bi.getWidth();
|
|
349
|
-
height = bi.getHeight();
|
|
350
|
-
int type = bi.getType();
|
|
351
|
-
if (type == BufferedImage.TYPE_3BYTE_BGR ||
|
|
352
|
-
type == BufferedImage.TYPE_4BYTE_ABGR) {
|
|
353
|
-
pixels = new int[width * height];
|
|
354
|
-
bi.getRGB(0, 0, width, height, pixels, 0, width);
|
|
355
|
-
if (type == BufferedImage.TYPE_4BYTE_ABGR) {
|
|
356
|
-
format = ARGB;
|
|
357
|
-
} else {
|
|
358
|
-
opaque();
|
|
359
|
-
}
|
|
360
|
-
} else {
|
|
361
|
-
DataBuffer db = bi.getRaster().getDataBuffer();
|
|
362
|
-
if (db instanceof DataBufferInt) {
|
|
363
|
-
pixels = ((DataBufferInt) db).getData();
|
|
364
|
-
if (type == BufferedImage.TYPE_INT_ARGB) {
|
|
365
|
-
format = ARGB;
|
|
366
|
-
} else if (type == BufferedImage.TYPE_INT_RGB) {
|
|
367
|
-
opaque();
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
// Implements fall-through if not DataBufferInt above, or not a
|
|
373
|
-
// known type, or not DataBufferInt for the data itself.
|
|
374
|
-
if (pixels == null) { // go the old school Java 1.0 route
|
|
375
|
-
width = img.getWidth(null);
|
|
376
|
-
height = img.getHeight(null);
|
|
377
|
-
pixels = new int[width * height];
|
|
378
|
-
PixelGrabber pg =
|
|
379
|
-
new PixelGrabber(img, 0, 0, width, height, pixels, 0, width);
|
|
380
|
-
try {
|
|
381
|
-
pg.grabPixels();
|
|
382
|
-
} catch (InterruptedException e) { }
|
|
383
|
-
}
|
|
384
|
-
pixelDensity = 1;
|
|
385
|
-
pixelWidth = width;
|
|
386
|
-
pixelHeight = height;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
334
|
|
|
390
|
-
/**
|
|
391
|
-
* Use the getNative() method instead, which allows library interfaces to be
|
|
392
|
-
* written in a cross-platform fashion for desktop, Android, and others.
|
|
393
|
-
* This is still included for PGraphics objects, which may need the image.
|
|
394
|
-
*/
|
|
395
|
-
public Image getImage() { // ignore
|
|
396
|
-
return (Image) getNative();
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
/**
|
|
401
|
-
* Returns a native BufferedImage from this PImage.
|
|
402
|
-
*/
|
|
403
335
|
public Object getNative() { // ignore
|
|
404
|
-
|
|
405
|
-
int type = (format == RGB) ?
|
|
406
|
-
BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
|
|
407
|
-
BufferedImage image = new BufferedImage(pixelWidth, pixelHeight, type);
|
|
408
|
-
WritableRaster wr = image.getRaster();
|
|
409
|
-
wr.setDataElements(0, 0, pixelWidth, pixelHeight, pixels);
|
|
410
|
-
return image;
|
|
336
|
+
return null;
|
|
411
337
|
}
|
|
412
338
|
|
|
413
339
|
|
|
@@ -506,7 +432,7 @@ public class PImage implements PConstants, Cloneable {
|
|
|
506
432
|
* <b>updatePixels()</b>. Even if the renderer may not seem to use this
|
|
507
433
|
* function in the current Processing release, this will always be subject
|
|
508
434
|
* to change.
|
|
509
|
-
*
|
|
435
|
+
*
|
|
510
436
|
* Currently, none of the renderers use the additional parameters to
|
|
511
437
|
* <b>updatePixels()</b>, however this may be implemented in the future.
|
|
512
438
|
*
|
|
@@ -592,104 +518,7 @@ public class PImage implements PConstants, Cloneable {
|
|
|
592
518
|
* @see PImage#get(int, int, int, int)
|
|
593
519
|
*/
|
|
594
520
|
public void resize(int w, int h) { // ignore
|
|
595
|
-
|
|
596
|
-
throw new IllegalArgumentException("width or height must be > 0 for resize");
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
if (w == 0) { // Use height to determine relative size
|
|
600
|
-
float diff = (float) h / (float) height;
|
|
601
|
-
w = (int) (width * diff);
|
|
602
|
-
} else if (h == 0) { // Use the width to determine relative size
|
|
603
|
-
float diff = (float) w / (float) width;
|
|
604
|
-
h = (int) (height * diff);
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
BufferedImage img =
|
|
608
|
-
shrinkImage((BufferedImage) getNative(), w*pixelDensity, h*pixelDensity);
|
|
609
|
-
|
|
610
|
-
PImage temp = new PImage(img);
|
|
611
|
-
this.pixelWidth = temp.width;
|
|
612
|
-
this.pixelHeight = temp.height;
|
|
613
|
-
|
|
614
|
-
// Get the resized pixel array
|
|
615
|
-
this.pixels = temp.pixels;
|
|
616
|
-
|
|
617
|
-
this.width = pixelWidth / pixelDensity;
|
|
618
|
-
this.height = pixelHeight / pixelDensity;
|
|
619
|
-
|
|
620
|
-
// Mark the pixels array as altered
|
|
621
|
-
updatePixels();
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
// Adapted from getFasterScaledInstance() method from page 111 of
|
|
626
|
-
// "Filthy Rich Clients" by Chet Haase and Romain Guy
|
|
627
|
-
// Additional modifications and simplifications have been added,
|
|
628
|
-
// plus a fix to deal with an infinite loop if images are expanded.
|
|
629
|
-
// http://code.google.com/p/processing/issues/detail?id=1463
|
|
630
|
-
static private BufferedImage shrinkImage(BufferedImage img,
|
|
631
|
-
int targetWidth, int targetHeight) {
|
|
632
|
-
int type = (img.getTransparency() == Transparency.OPAQUE) ?
|
|
633
|
-
BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
|
|
634
|
-
BufferedImage outgoing = img;
|
|
635
|
-
BufferedImage scratchImage = null;
|
|
636
|
-
Graphics2D g2 = null;
|
|
637
|
-
int prevW = outgoing.getWidth();
|
|
638
|
-
int prevH = outgoing.getHeight();
|
|
639
|
-
boolean isTranslucent = img.getTransparency() != Transparency.OPAQUE;
|
|
640
|
-
|
|
641
|
-
// Use multi-step technique: start with original size, then scale down in
|
|
642
|
-
// multiple passes with drawImage() until the target size is reached
|
|
643
|
-
int w = img.getWidth();
|
|
644
|
-
int h = img.getHeight();
|
|
645
|
-
|
|
646
|
-
do {
|
|
647
|
-
if (w > targetWidth) {
|
|
648
|
-
w /= 2;
|
|
649
|
-
// if this is the last step, do the exact size
|
|
650
|
-
if (w < targetWidth) {
|
|
651
|
-
w = targetWidth;
|
|
652
|
-
}
|
|
653
|
-
} else if (targetWidth >= w) {
|
|
654
|
-
w = targetWidth;
|
|
655
|
-
}
|
|
656
|
-
if (h > targetHeight) {
|
|
657
|
-
h /= 2;
|
|
658
|
-
if (h < targetHeight) {
|
|
659
|
-
h = targetHeight;
|
|
660
|
-
}
|
|
661
|
-
} else if (targetHeight >= h) {
|
|
662
|
-
h = targetHeight;
|
|
663
|
-
}
|
|
664
|
-
if (scratchImage == null || isTranslucent) {
|
|
665
|
-
// Use a single scratch buffer for all iterations and then copy
|
|
666
|
-
// to the final, correctly-sized image before returning
|
|
667
|
-
scratchImage = new BufferedImage(w, h, type);
|
|
668
|
-
g2 = scratchImage.createGraphics();
|
|
669
|
-
}
|
|
670
|
-
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
|
|
671
|
-
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
|
672
|
-
g2.drawImage(outgoing, 0, 0, w, h, 0, 0, prevW, prevH, null);
|
|
673
|
-
prevW = w;
|
|
674
|
-
prevH = h;
|
|
675
|
-
outgoing = scratchImage;
|
|
676
|
-
} while (w != targetWidth || h != targetHeight);
|
|
677
|
-
|
|
678
|
-
if (g2 != null) {
|
|
679
|
-
g2.dispose();
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
// If we used a scratch buffer that is larger than our target size,
|
|
683
|
-
// create an image of the right size and copy the results into it
|
|
684
|
-
if (targetWidth != outgoing.getWidth() ||
|
|
685
|
-
targetHeight != outgoing.getHeight()) {
|
|
686
|
-
scratchImage = new BufferedImage(targetWidth, targetHeight, type);
|
|
687
|
-
g2 = scratchImage.createGraphics();
|
|
688
|
-
g2.drawImage(outgoing, 0, 0, null);
|
|
689
|
-
g2.dispose();
|
|
690
|
-
outgoing = scratchImage;
|
|
691
|
-
}
|
|
692
|
-
return outgoing;
|
|
521
|
+
throw new RuntimeException("resize() not implemented for this PImage type");
|
|
693
522
|
}
|
|
694
523
|
|
|
695
524
|
|
|
@@ -889,7 +718,7 @@ public class PImage implements PConstants, Cloneable {
|
|
|
889
718
|
* 255). When setting an image, the <b>x</b> and <b>y</b> parameters define
|
|
890
719
|
* the coordinates for the upper-left corner of the image, regardless of
|
|
891
720
|
* the current <b>imageMode()</b>.
|
|
892
|
-
|
|
721
|
+
*
|
|
893
722
|
* Setting the color of a single pixel with <b>set(x, y)</b> is easy, but
|
|
894
723
|
* not as fast as putting the data directly into <b>pixels[]</b>. The
|
|
895
724
|
* equivalent statement to <b>set(x, y, #000000)</b> using <b>pixels[]</b>
|
|
@@ -985,7 +814,7 @@ public class PImage implements PConstants, Cloneable {
|
|
|
985
814
|
* @param maskArray array of integers used as the alpha channel, needs to be
|
|
986
815
|
* the same length as the image's pixel array.
|
|
987
816
|
*/
|
|
988
|
-
public void mask(int maskArray
|
|
817
|
+
public void mask(int[] maskArray) { // ignore
|
|
989
818
|
loadPixels();
|
|
990
819
|
// don't execute if mask image is different size
|
|
991
820
|
if (maskArray.length != pixels.length) {
|
|
@@ -1120,8 +949,8 @@ public class PImage implements PConstants, Cloneable {
|
|
|
1120
949
|
/**
|
|
1121
950
|
* ( begin auto-generated from PImage_filter.xml )
|
|
1122
951
|
*
|
|
1123
|
-
* Filters an image as defined by one of the following modes
|
|
1124
|
-
*
|
|
952
|
+
* Filters an image as defined by one of the following modes:
|
|
953
|
+
* THRESHOLD - converts the image to black and white pixels depending if
|
|
1125
954
|
* they are above or below the threshold defined by the level parameter.
|
|
1126
955
|
* The level must be between 0.0 (black) and 1.0(white). If no level is
|
|
1127
956
|
* specified, 0.5 is used.
|
|
@@ -1175,14 +1004,20 @@ public class PImage implements PConstants, Cloneable {
|
|
|
1175
1004
|
|
|
1176
1005
|
switch (kind) {
|
|
1177
1006
|
case BLUR:
|
|
1178
|
-
|
|
1007
|
+
switch (format) {
|
|
1008
|
+
case ALPHA:
|
|
1179
1009
|
blurAlpha(param);
|
|
1180
|
-
|
|
1010
|
+
break;
|
|
1011
|
+
case ARGB:
|
|
1181
1012
|
blurARGB(param);
|
|
1182
|
-
|
|
1013
|
+
break;
|
|
1014
|
+
default:
|
|
1183
1015
|
blurRGB(param);
|
|
1016
|
+
break;
|
|
1017
|
+
}
|
|
1184
1018
|
break;
|
|
1185
1019
|
|
|
1020
|
+
|
|
1186
1021
|
case GRAY:
|
|
1187
1022
|
throw new RuntimeException("Use filter(GRAY) instead of " +
|
|
1188
1023
|
"filter(GRAY, param)");
|
|
@@ -1284,7 +1119,7 @@ public class PImage implements PConstants, Cloneable {
|
|
|
1284
1119
|
protected void blurAlpha(float r) {
|
|
1285
1120
|
int sum, cb;
|
|
1286
1121
|
int read, ri, ym, ymi, bk0;
|
|
1287
|
-
int
|
|
1122
|
+
int[] b2 = new int[pixels.length];
|
|
1288
1123
|
int yi = 0;
|
|
1289
1124
|
|
|
1290
1125
|
buildBlurKernel(r);
|
|
@@ -1355,9 +1190,9 @@ public class PImage implements PConstants, Cloneable {
|
|
|
1355
1190
|
protected void blurRGB(float r) {
|
|
1356
1191
|
int sum, cr, cg, cb; //, k;
|
|
1357
1192
|
int /*pixel,*/ read, ri, /*roff,*/ ym, ymi, /*riw,*/ bk0;
|
|
1358
|
-
int
|
|
1359
|
-
int
|
|
1360
|
-
int
|
|
1193
|
+
int[] r2 = new int[pixels.length];
|
|
1194
|
+
int[] g2 = new int[pixels.length];
|
|
1195
|
+
int[] b2 = new int[pixels.length];
|
|
1361
1196
|
int yi = 0;
|
|
1362
1197
|
|
|
1363
1198
|
buildBlurKernel(r);
|
|
@@ -1438,10 +1273,10 @@ public class PImage implements PConstants, Cloneable {
|
|
|
1438
1273
|
int sum, cr, cg, cb, ca;
|
|
1439
1274
|
int /*pixel,*/ read, ri, /*roff,*/ ym, ymi, /*riw,*/ bk0;
|
|
1440
1275
|
int wh = pixels.length;
|
|
1441
|
-
int
|
|
1442
|
-
int
|
|
1443
|
-
int
|
|
1444
|
-
int
|
|
1276
|
+
int[] r2 = new int[wh];
|
|
1277
|
+
int[] g2 = new int[wh];
|
|
1278
|
+
int[] b2 = new int[wh];
|
|
1279
|
+
int[] a2 = new int[wh];
|
|
1445
1280
|
int yi = 0;
|
|
1446
1281
|
|
|
1447
1282
|
buildBlurKernel(r);
|
|
@@ -1677,7 +1512,7 @@ public class PImage implements PConstants, Cloneable {
|
|
|
1677
1512
|
* source pixels to fit the specified target region. No alpha information
|
|
1678
1513
|
* is used in the process, however if the source image has an alpha channel
|
|
1679
1514
|
* set, it will be copied as well.
|
|
1680
|
-
|
|
1515
|
+
*
|
|
1681
1516
|
* As of release 0149, this function ignores <b>imageMode()</b>.
|
|
1682
1517
|
*
|
|
1683
1518
|
* ( end auto-generated )
|
|
@@ -1781,7 +1616,7 @@ public class PImage implements PConstants, Cloneable {
|
|
|
1781
1616
|
* necessarily "correct" code. No biggie, most software does. A nitpicker
|
|
1782
1617
|
* can find numerous "off by 1 division" problems in the blend code where
|
|
1783
1618
|
* <TT>>>8</TT> or <TT>>>7</TT> is used when strictly speaking
|
|
1784
|
-
* <TT>/255.0</
|
|
1619
|
+
* <TT>/255.0</TT> or <TT>/127.0</TT> should have been used.</P>
|
|
1785
1620
|
* <P>For instance, exclusion (not intended for real-time use) reads
|
|
1786
1621
|
* <TT>r1 + r2 - ((2 * r1 * r2) / 255)</TT> because <TT>255 == 1.0</TT>
|
|
1787
1622
|
* not <TT>256 == 1.0</TT>. In other words, <TT>(255*255)>>8</TT> is not
|
|
@@ -2992,7 +2827,15 @@ int testFunction(int dst, int src) {
|
|
|
2992
2827
|
|
|
2993
2828
|
// FILE I/O
|
|
2994
2829
|
|
|
2995
|
-
|
|
2830
|
+
|
|
2831
|
+
protected boolean saveImpl(String filename) {
|
|
2832
|
+
return false;
|
|
2833
|
+
}
|
|
2834
|
+
|
|
2835
|
+
|
|
2836
|
+
static public PImage loadTIFF(InputStream input) { // ignore
|
|
2837
|
+
byte tiff[] = PApplet.loadBytes(input);
|
|
2838
|
+
|
|
2996
2839
|
if ((tiff[42] != tiff[102]) || // width/height in both places
|
|
2997
2840
|
(tiff[43] != tiff[103])) {
|
|
2998
2841
|
System.err.println(TIFF_ERROR);
|
|
@@ -3048,14 +2891,8 @@ int testFunction(int dst, int src) {
|
|
|
3048
2891
|
}
|
|
3049
2892
|
*/
|
|
3050
2893
|
try {
|
|
3051
|
-
byte
|
|
3052
|
-
System.arraycopy(
|
|
3053
|
-
TIFF_HEADER,
|
|
3054
|
-
0,
|
|
3055
|
-
tiff,
|
|
3056
|
-
0,
|
|
3057
|
-
TIFF_HEADER.length
|
|
3058
|
-
);
|
|
2894
|
+
byte[] tiff = new byte[768];
|
|
2895
|
+
System.arraycopy(TIFF_HEADER, 0, tiff, 0, TIFF_HEADER.length);
|
|
3059
2896
|
|
|
3060
2897
|
tiff[30] = (byte) ((pixelWidth >> 8) & 0xff);
|
|
3061
2898
|
tiff[31] = (byte) ((pixelWidth) & 0xff);
|
|
@@ -3080,16 +2917,214 @@ int testFunction(int dst, int src) {
|
|
|
3080
2917
|
return true;
|
|
3081
2918
|
|
|
3082
2919
|
} catch (IOException e) {
|
|
3083
|
-
e.printStackTrace();
|
|
3084
2920
|
}
|
|
3085
2921
|
return false;
|
|
3086
2922
|
}
|
|
3087
2923
|
|
|
3088
2924
|
|
|
2925
|
+
/**
|
|
2926
|
+
* Targa image loader for RLE-compressed TGA files.
|
|
2927
|
+
* <p>
|
|
2928
|
+
* Rewritten for 0115 to read/write RLE-encoded targa images.
|
|
2929
|
+
* For 0125, non-RLE encoded images are now supported, along with
|
|
2930
|
+
* images whose y-order is reversed (which is standard for TGA files).
|
|
2931
|
+
* <p>
|
|
2932
|
+
* A version of this function is in MovieMaker.java. Any fixes here
|
|
2933
|
+
* should be applied over in MovieMaker as well.
|
|
2934
|
+
* <p>
|
|
2935
|
+
* Known issue with RLE encoding and odd behavior in some apps:
|
|
2936
|
+
* https://github.com/processing/processing/issues/2096
|
|
2937
|
+
* Please help!
|
|
2938
|
+
*/
|
|
2939
|
+
static public PImage loadTGA(InputStream input) throws IOException { // ignore
|
|
2940
|
+
byte[] header = new byte[18];
|
|
2941
|
+
int offset = 0;
|
|
2942
|
+
do {
|
|
2943
|
+
int count = input.read(header, offset, header.length - offset);
|
|
2944
|
+
if (count == -1) return null;
|
|
2945
|
+
offset += count;
|
|
2946
|
+
} while (offset < 18);
|
|
2947
|
+
|
|
2948
|
+
/*
|
|
2949
|
+
header[2] image type code
|
|
2950
|
+
2 (0x02) - Uncompressed, RGB images.
|
|
2951
|
+
3 (0x03) - Uncompressed, black and white images.
|
|
2952
|
+
10 (0x0A) - Run-length encoded RGB images.
|
|
2953
|
+
11 (0x0B) - Compressed, black and white images. (grayscale?)
|
|
2954
|
+
|
|
2955
|
+
header[16] is the bit depth (8, 24, 32)
|
|
2956
|
+
|
|
2957
|
+
header[17] image descriptor (packed bits)
|
|
2958
|
+
0x20 is 32 = origin upper-left
|
|
2959
|
+
0x28 is 32 + 8 = origin upper-left + 32 bits
|
|
2960
|
+
|
|
2961
|
+
7 6 5 4 3 2 1 0
|
|
2962
|
+
128 64 32 16 8 4 2 1
|
|
2963
|
+
*/
|
|
2964
|
+
|
|
2965
|
+
int format = 0;
|
|
2966
|
+
|
|
2967
|
+
if (((header[2] == 3) || (header[2] == 11)) && // B&W, plus RLE or not
|
|
2968
|
+
(header[16] == 8) && // 8 bits
|
|
2969
|
+
((header[17] == 0x8) || (header[17] == 0x28))) { // origin, 32 bit
|
|
2970
|
+
format = ALPHA;
|
|
2971
|
+
|
|
2972
|
+
} else if (((header[2] == 2) || (header[2] == 10)) && // RGB, RLE or not
|
|
2973
|
+
(header[16] == 24) && // 24 bits
|
|
2974
|
+
((header[17] == 0x20) || (header[17] == 0))) { // origin
|
|
2975
|
+
format = RGB;
|
|
2976
|
+
|
|
2977
|
+
} else if (((header[2] == 2) || (header[2] == 10)) &&
|
|
2978
|
+
(header[16] == 32) &&
|
|
2979
|
+
((header[17] == 0x8) || (header[17] == 0x28))) { // origin, 32
|
|
2980
|
+
format = ARGB;
|
|
2981
|
+
}
|
|
2982
|
+
|
|
2983
|
+
if (format == 0) {
|
|
2984
|
+
System.err.println("Unknown .tga file format");
|
|
2985
|
+
return null;
|
|
2986
|
+
}
|
|
2987
|
+
|
|
2988
|
+
int w = ((header[13] & 0xff) << 8) + (header[12] & 0xff);
|
|
2989
|
+
int h = ((header[15] & 0xff) << 8) + (header[14] & 0xff);
|
|
2990
|
+
PImage outgoing = new PImage(w, h, format);
|
|
2991
|
+
|
|
2992
|
+
// where "reversed" means upper-left corner (normal for most of
|
|
2993
|
+
// the modernized world, but "reversed" for the tga spec)
|
|
2994
|
+
//boolean reversed = (header[17] & 0x20) != 0;
|
|
2995
|
+
// https://github.com/processing/processing/issues/1682
|
|
2996
|
+
boolean reversed = (header[17] & 0x20) == 0;
|
|
2997
|
+
|
|
2998
|
+
if ((header[2] == 2) || (header[2] == 3)) { // not RLE encoded
|
|
2999
|
+
if (reversed) {
|
|
3000
|
+
int index = (h-1) * w;
|
|
3001
|
+
switch (format) {
|
|
3002
|
+
case ALPHA:
|
|
3003
|
+
for (int y = h-1; y >= 0; y--) {
|
|
3004
|
+
for (int x = 0; x < w; x++) {
|
|
3005
|
+
outgoing.pixels[index + x] = input.read();
|
|
3006
|
+
}
|
|
3007
|
+
index -= w;
|
|
3008
|
+
}
|
|
3009
|
+
break;
|
|
3010
|
+
case RGB:
|
|
3011
|
+
for (int y = h-1; y >= 0; y--) {
|
|
3012
|
+
for (int x = 0; x < w; x++) {
|
|
3013
|
+
outgoing.pixels[index + x] =
|
|
3014
|
+
input.read() | (input.read() << 8) | (input.read() << 16) |
|
|
3015
|
+
0xff000000;
|
|
3016
|
+
}
|
|
3017
|
+
index -= w;
|
|
3018
|
+
}
|
|
3019
|
+
break;
|
|
3020
|
+
case ARGB:
|
|
3021
|
+
for (int y = h-1; y >= 0; y--) {
|
|
3022
|
+
for (int x = 0; x < w; x++) {
|
|
3023
|
+
outgoing.pixels[index + x] =
|
|
3024
|
+
input.read() | (input.read() << 8) | (input.read() << 16) |
|
|
3025
|
+
(input.read() << 24);
|
|
3026
|
+
}
|
|
3027
|
+
index -= w;
|
|
3028
|
+
}
|
|
3029
|
+
}
|
|
3030
|
+
} else { // not reversed
|
|
3031
|
+
int count = w * h;
|
|
3032
|
+
switch (format) {
|
|
3033
|
+
case ALPHA:
|
|
3034
|
+
for (int i = 0; i < count; i++) {
|
|
3035
|
+
outgoing.pixels[i] = input.read();
|
|
3036
|
+
}
|
|
3037
|
+
break;
|
|
3038
|
+
case RGB:
|
|
3039
|
+
for (int i = 0; i < count; i++) {
|
|
3040
|
+
outgoing.pixels[i] =
|
|
3041
|
+
input.read() | (input.read() << 8) | (input.read() << 16) |
|
|
3042
|
+
0xff000000;
|
|
3043
|
+
}
|
|
3044
|
+
break;
|
|
3045
|
+
case ARGB:
|
|
3046
|
+
for (int i = 0; i < count; i++) {
|
|
3047
|
+
outgoing.pixels[i] =
|
|
3048
|
+
input.read() | (input.read() << 8) | (input.read() << 16) |
|
|
3049
|
+
(input.read() << 24);
|
|
3050
|
+
}
|
|
3051
|
+
break;
|
|
3052
|
+
}
|
|
3053
|
+
}
|
|
3054
|
+
|
|
3055
|
+
} else { // header[2] is 10 or 11
|
|
3056
|
+
int index = 0;
|
|
3057
|
+
int[] px = outgoing.pixels;
|
|
3058
|
+
|
|
3059
|
+
while (index < px.length) {
|
|
3060
|
+
int num = input.read();
|
|
3061
|
+
boolean isRLE = (num & 0x80) != 0;
|
|
3062
|
+
if (isRLE) {
|
|
3063
|
+
num -= 127; // (num & 0x7F) + 1
|
|
3064
|
+
int pixel = 0;
|
|
3065
|
+
switch (format) {
|
|
3066
|
+
case ALPHA:
|
|
3067
|
+
pixel = input.read();
|
|
3068
|
+
break;
|
|
3069
|
+
case RGB:
|
|
3070
|
+
pixel = 0xFF000000 |
|
|
3071
|
+
input.read() | (input.read() << 8) | (input.read() << 16);
|
|
3072
|
+
//(is.read() << 16) | (is.read() << 8) | is.read();
|
|
3073
|
+
break;
|
|
3074
|
+
case ARGB:
|
|
3075
|
+
pixel = input.read() |
|
|
3076
|
+
(input.read() << 8) | (input.read() << 16) | (input.read() << 24);
|
|
3077
|
+
break;
|
|
3078
|
+
}
|
|
3079
|
+
for (int i = 0; i < num; i++) {
|
|
3080
|
+
px[index++] = pixel;
|
|
3081
|
+
if (index == px.length) break;
|
|
3082
|
+
}
|
|
3083
|
+
} else { // write up to 127 bytes as uncompressed
|
|
3084
|
+
num += 1;
|
|
3085
|
+
switch (format) {
|
|
3086
|
+
case ALPHA:
|
|
3087
|
+
for (int i = 0; i < num; i++) {
|
|
3088
|
+
px[index++] = input.read();
|
|
3089
|
+
}
|
|
3090
|
+
break;
|
|
3091
|
+
case RGB:
|
|
3092
|
+
for (int i = 0; i < num; i++) {
|
|
3093
|
+
px[index++] = 0xFF000000 |
|
|
3094
|
+
input.read() | (input.read() << 8) | (input.read() << 16);
|
|
3095
|
+
//(is.read() << 16) | (is.read() << 8) | is.read();
|
|
3096
|
+
}
|
|
3097
|
+
break;
|
|
3098
|
+
case ARGB:
|
|
3099
|
+
for (int i = 0; i < num; i++) {
|
|
3100
|
+
px[index++] = input.read() | //(is.read() << 24) |
|
|
3101
|
+
(input.read() << 8) | (input.read() << 16) | (input.read() << 24);
|
|
3102
|
+
//(is.read() << 16) | (is.read() << 8) | is.read();
|
|
3103
|
+
}
|
|
3104
|
+
break;
|
|
3105
|
+
}
|
|
3106
|
+
}
|
|
3107
|
+
}
|
|
3108
|
+
|
|
3109
|
+
if (!reversed) {
|
|
3110
|
+
int[] temp = new int[w];
|
|
3111
|
+
for (int y = 0; y < h/2; y++) {
|
|
3112
|
+
int z = (h-1) - y;
|
|
3113
|
+
System.arraycopy(px, y*w, temp, 0, w);
|
|
3114
|
+
System.arraycopy(px, z*w, px, y*w, w);
|
|
3115
|
+
System.arraycopy(temp, 0, px, z*w, w);
|
|
3116
|
+
}
|
|
3117
|
+
}
|
|
3118
|
+
}
|
|
3119
|
+
input.close();
|
|
3120
|
+
return outgoing;
|
|
3121
|
+
}
|
|
3122
|
+
|
|
3123
|
+
|
|
3089
3124
|
/**
|
|
3090
3125
|
* Creates a Targa32 formatted byte sequence of specified
|
|
3091
3126
|
* pixel buffer using RLE compression.
|
|
3092
|
-
*
|
|
3127
|
+
* <p>
|
|
3093
3128
|
* Also figured out how to avoid parsing the image upside-down
|
|
3094
3129
|
* (there's a header flag to set the image origin to top-left)
|
|
3095
3130
|
* </p>
|
|
@@ -3100,31 +3135,33 @@ int testFunction(int dst, int src) {
|
|
|
3100
3135
|
* <LI><TT>ARGB</TT> → 32 bits
|
|
3101
3136
|
* </UL>
|
|
3102
3137
|
* All versions are RLE compressed.
|
|
3103
|
-
*
|
|
3138
|
+
*
|
|
3104
3139
|
* Contributed by toxi 8-10 May 2005, based on this RLE
|
|
3105
3140
|
* <A HREF="http://www.wotsit.org/download.asp?f=tga">specification</A>
|
|
3106
3141
|
*/
|
|
3107
3142
|
protected boolean saveTGA(OutputStream output) {
|
|
3108
|
-
byte
|
|
3109
|
-
|
|
3110
|
-
if (format == ALPHA) { // save ALPHA images as 8bit grayscale
|
|
3111
|
-
header[2] = 0x0B;
|
|
3112
|
-
header[16] = 0x08;
|
|
3113
|
-
header[17] = 0x28;
|
|
3143
|
+
byte[] header = new byte[18];
|
|
3114
3144
|
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3145
|
+
switch (format) {
|
|
3146
|
+
case ALPHA:
|
|
3147
|
+
// save ALPHA images as 8bit grayscale
|
|
3148
|
+
header[2] = 0x0B;
|
|
3149
|
+
header[16] = 0x08;
|
|
3150
|
+
header[17] = 0x28;
|
|
3151
|
+
break;
|
|
3152
|
+
case RGB:
|
|
3153
|
+
header[2] = 0x0A;
|
|
3154
|
+
header[16] = 24;
|
|
3155
|
+
header[17] = 0x20;
|
|
3156
|
+
break;
|
|
3157
|
+
case ARGB:
|
|
3158
|
+
header[2] = 0x0A;
|
|
3159
|
+
header[16] = 32;
|
|
3160
|
+
header[17] = 0x28;
|
|
3161
|
+
break;
|
|
3162
|
+
default:
|
|
3163
|
+
throw new RuntimeException("Image format not recognized inside save()");
|
|
3164
|
+
}
|
|
3128
3165
|
// set image dimensions lo-hi byte order
|
|
3129
3166
|
header[12] = (byte) (pixelWidth & 0xff);
|
|
3130
3167
|
header[13] = (byte) (pixelWidth >> 8);
|
|
@@ -3234,133 +3271,11 @@ int testFunction(int dst, int src) {
|
|
|
3234
3271
|
return true;
|
|
3235
3272
|
|
|
3236
3273
|
} catch (IOException e) {
|
|
3237
|
-
e.printStackTrace();
|
|
3238
3274
|
return false;
|
|
3239
3275
|
}
|
|
3240
3276
|
}
|
|
3241
3277
|
|
|
3242
3278
|
|
|
3243
|
-
/**
|
|
3244
|
-
* Use ImageIO functions from Java 1.4 and later to handle image save.
|
|
3245
|
-
* Various formats are supported, typically jpeg, png, bmp, and wbmp.
|
|
3246
|
-
* To get a list of the supported formats for writing, use: <BR>
|
|
3247
|
-
* <TT>println(javax.imageio.ImageIO.getReaderFormatNames())</TT>
|
|
3248
|
-
*/
|
|
3249
|
-
protected boolean saveImageIO(String path) throws IOException {
|
|
3250
|
-
try {
|
|
3251
|
-
int outputFormat = (format == ARGB) ?
|
|
3252
|
-
BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB;
|
|
3253
|
-
|
|
3254
|
-
String extension =
|
|
3255
|
-
path.substring(path.lastIndexOf('.') + 1).toLowerCase();
|
|
3256
|
-
|
|
3257
|
-
// JPEG and BMP images that have an alpha channel set get pretty unhappy.
|
|
3258
|
-
// BMP just doesn't write, and JPEG writes it as a CMYK image.
|
|
3259
|
-
// http://code.google.com/p/processing/issues/detail?id=415
|
|
3260
|
-
if (extension.equals("bmp") || extension.equals("jpg") || extension.equals("jpeg")) {
|
|
3261
|
-
outputFormat = BufferedImage.TYPE_INT_RGB;
|
|
3262
|
-
}
|
|
3263
|
-
|
|
3264
|
-
BufferedImage bimage = new BufferedImage(pixelWidth, pixelHeight, outputFormat);
|
|
3265
|
-
bimage.setRGB(0, 0, pixelWidth, pixelHeight, pixels, 0, pixelWidth);
|
|
3266
|
-
|
|
3267
|
-
File file = new File(path);
|
|
3268
|
-
|
|
3269
|
-
ImageWriter writer = null;
|
|
3270
|
-
ImageWriteParam param = null;
|
|
3271
|
-
IIOMetadata metadata = null;
|
|
3272
|
-
|
|
3273
|
-
if (extension.equals("jpg") || extension.equals("jpeg")) {
|
|
3274
|
-
if ((writer = imageioWriter("jpeg")) != null) {
|
|
3275
|
-
// Set JPEG quality to 90% with baseline optimization. Setting this
|
|
3276
|
-
// to 1 was a huge jump (about triple the size), so this seems good.
|
|
3277
|
-
// Oddly, a smaller file size than Photoshop at 90%, but I suppose
|
|
3278
|
-
// it's a completely different algorithm.
|
|
3279
|
-
param = writer.getDefaultWriteParam();
|
|
3280
|
-
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
|
|
3281
|
-
param.setCompressionQuality(0.9f);
|
|
3282
|
-
}
|
|
3283
|
-
}
|
|
3284
|
-
|
|
3285
|
-
if (extension.equals("png")) {
|
|
3286
|
-
if ((writer = imageioWriter("png")) != null) {
|
|
3287
|
-
param = writer.getDefaultWriteParam();
|
|
3288
|
-
if (false) {
|
|
3289
|
-
metadata = imageioDPI(writer, param, 100);
|
|
3290
|
-
}
|
|
3291
|
-
}
|
|
3292
|
-
}
|
|
3293
|
-
|
|
3294
|
-
if (writer != null) {
|
|
3295
|
-
BufferedOutputStream output =
|
|
3296
|
-
new BufferedOutputStream(PApplet.createOutput(file));
|
|
3297
|
-
writer.setOutput(ImageIO.createImageOutputStream(output));
|
|
3298
|
-
// writer.write(null, new IIOImage(bimage, null, null), param);
|
|
3299
|
-
writer.write(metadata, new IIOImage(bimage, null, metadata), param);
|
|
3300
|
-
writer.dispose();
|
|
3301
|
-
|
|
3302
|
-
output.flush();
|
|
3303
|
-
output.close();
|
|
3304
|
-
return true;
|
|
3305
|
-
}
|
|
3306
|
-
// If iter.hasNext() somehow fails up top, it falls through to here
|
|
3307
|
-
return javax.imageio.ImageIO.write(bimage, extension, file);
|
|
3308
|
-
|
|
3309
|
-
} catch (Exception e) {
|
|
3310
|
-
e.printStackTrace();
|
|
3311
|
-
throw new IOException("image save failed.");
|
|
3312
|
-
}
|
|
3313
|
-
}
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
private ImageWriter imageioWriter(String extension) {
|
|
3317
|
-
Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName(extension);
|
|
3318
|
-
if (iter.hasNext()) {
|
|
3319
|
-
return iter.next();
|
|
3320
|
-
}
|
|
3321
|
-
return null;
|
|
3322
|
-
}
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
private IIOMetadata imageioDPI(ImageWriter writer, ImageWriteParam param, double dpi) {
|
|
3326
|
-
// http://stackoverflow.com/questions/321736/how-to-set-dpi-information-in-an-image
|
|
3327
|
-
ImageTypeSpecifier typeSpecifier =
|
|
3328
|
-
ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB);
|
|
3329
|
-
IIOMetadata metadata =
|
|
3330
|
-
writer.getDefaultImageMetadata(typeSpecifier, param);
|
|
3331
|
-
|
|
3332
|
-
if (!metadata.isReadOnly() && metadata.isStandardMetadataFormatSupported()) {
|
|
3333
|
-
// for PNG, it's dots per millimeter
|
|
3334
|
-
double dotsPerMilli = dpi / 25.4;
|
|
3335
|
-
|
|
3336
|
-
IIOMetadataNode horiz = new IIOMetadataNode("HorizontalPixelSize");
|
|
3337
|
-
horiz.setAttribute("value", Double.toString(dotsPerMilli));
|
|
3338
|
-
|
|
3339
|
-
IIOMetadataNode vert = new IIOMetadataNode("VerticalPixelSize");
|
|
3340
|
-
vert.setAttribute("value", Double.toString(dotsPerMilli));
|
|
3341
|
-
|
|
3342
|
-
IIOMetadataNode dim = new IIOMetadataNode("Dimension");
|
|
3343
|
-
dim.appendChild(horiz);
|
|
3344
|
-
dim.appendChild(vert);
|
|
3345
|
-
|
|
3346
|
-
IIOMetadataNode root = new IIOMetadataNode("javax_imageio_1.0");
|
|
3347
|
-
root.appendChild(dim);
|
|
3348
|
-
|
|
3349
|
-
try {
|
|
3350
|
-
metadata.mergeTree("javax_imageio_1.0", root);
|
|
3351
|
-
return metadata;
|
|
3352
|
-
|
|
3353
|
-
} catch (IIOInvalidTreeException e) {
|
|
3354
|
-
System.err.println("Could not set the DPI of the output image");
|
|
3355
|
-
e.printStackTrace();
|
|
3356
|
-
}
|
|
3357
|
-
}
|
|
3358
|
-
return null;
|
|
3359
|
-
}
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
protected String[] saveImageFormats;
|
|
3363
|
-
|
|
3364
3279
|
/**
|
|
3365
3280
|
* ( begin auto-generated from PImage_save.xml )
|
|
3366
3281
|
*
|
|
@@ -3370,7 +3285,7 @@ int testFunction(int dst, int src) {
|
|
|
3370
3285
|
* in the filename, the image will save in TIFF format and .tif will be
|
|
3371
3286
|
* added to the name. These files are saved to the sketch's folder, which
|
|
3372
3287
|
* may be opened by selecting "Show sketch folder" from the "Sketch" menu.
|
|
3373
|
-
|
|
3288
|
+
* To save an image created within the code, rather
|
|
3374
3289
|
* than through loading, it's necessary to make the image with the
|
|
3375
3290
|
* <b>createImage()</b> function so it is aware of the location of the
|
|
3376
3291
|
* program and can therefore save the file to the right place. See the
|
|
@@ -3433,19 +3348,8 @@ int testFunction(int dst, int src) {
|
|
|
3433
3348
|
try {
|
|
3434
3349
|
OutputStream os = null;
|
|
3435
3350
|
|
|
3436
|
-
if (
|
|
3437
|
-
|
|
3438
|
-
}
|
|
3439
|
-
if (saveImageFormats != null) {
|
|
3440
|
-
for (int i = 0; i < saveImageFormats.length; i++) {
|
|
3441
|
-
if (filename.endsWith("." + saveImageFormats[i])) {
|
|
3442
|
-
if (!saveImageIO(filename)) {
|
|
3443
|
-
System.err.println("Error while saving image.");
|
|
3444
|
-
return false;
|
|
3445
|
-
}
|
|
3446
|
-
return true;
|
|
3447
|
-
}
|
|
3448
|
-
}
|
|
3351
|
+
if (saveImpl(filename)) {
|
|
3352
|
+
return true;
|
|
3449
3353
|
}
|
|
3450
3354
|
|
|
3451
3355
|
if (filename.toLowerCase().endsWith(".tga")) {
|
|
@@ -3466,7 +3370,6 @@ int testFunction(int dst, int src) {
|
|
|
3466
3370
|
|
|
3467
3371
|
} catch (IOException e) {
|
|
3468
3372
|
System.err.println("Error while saving image.");
|
|
3469
|
-
e.printStackTrace();
|
|
3470
3373
|
success = false;
|
|
3471
3374
|
}
|
|
3472
3375
|
return success;
|