propane 3.4.0-java → 3.7.0.pre-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 -2
- data/.mvn/wrapper/MavenWrapperDownloader.java +2 -2
- data/.mvn/wrapper/maven-wrapper.properties +2 -2
- data/.travis.yml +2 -2
- data/CHANGELOG.md +12 -0
- data/Gemfile +2 -0
- data/README.md +17 -8
- data/Rakefile +10 -11
- data/bin/propane +3 -1
- data/lib/propane.rb +6 -4
- data/lib/propane/app.rb +20 -10
- 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 +23 -24
- 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 +14 -6
- data/lib/propane/version.rb +2 -1
- data/library/boids/boids.rb +21 -11
- data/library/color_group/color_group.rb +28 -0
- data/library/control_panel/control_panel.rb +8 -5
- data/library/dxf/dxf.rb +6 -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 +7 -0
- data/library/simplex_noise/simplex_noise.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 +4 -1
- data/pom.rb +37 -36
- data/pom.xml +7 -7
- data/propane.gemspec +16 -12
- data/src/main/java/monkstone/ColorUtil.java +13 -1
- data/src/main/java/monkstone/MathToolModule.java +253 -203
- data/src/main/java/monkstone/PropaneLibrary.java +2 -2
- data/src/main/java/monkstone/fastmath/Deglut.java +1 -1
- data/src/main/java/monkstone/filechooser/Chooser.java +2 -1
- data/src/main/java/monkstone/noise/SimplexNoise.java +2 -2
- 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 +7 -6
- 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 +3 -3
- data/src/main/java/monkstone/videoevent/CaptureEvent.java +27 -0
- data/src/main/java/monkstone/videoevent/{VideoInterface.java → MovieEvent.java} +11 -27
- 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 +309 -209
- data/src/main/java/processing/awt/ShimAWT.java +581 -0
- data/src/main/java/processing/core/PApplet.java +4510 -4503
- 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 +193 -177
- data/src/main/java/processing/core/PImage.java +611 -309
- 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 +2888 -2652
- 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 +997 -965
- data/src/main/java/processing/core/ThinkDifferent.java +15 -13
- 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/dxf/RawDXF.java +404 -0
- 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 +744 -0
- data/src/main/java/processing/net/Server.java +388 -0
- data/src/main/java/processing/opengl/FontTexture.java +289 -270
- data/src/main/java/processing/opengl/FrameBuffer.java +386 -364
- data/src/main/java/processing/opengl/LinePath.java +547 -500
- data/src/main/java/processing/opengl/LineStroker.java +588 -581
- data/src/main/java/processing/opengl/PGL.java +3047 -2914
- 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 +1266 -1257
- 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 +33 -62
- metadata +56 -48
- data/src/main/java/processing/core/util/image/ImageLoadFacade.java +0 -161
- data/src/main/java/processing/core/util/image/ImageSaveFacade.java +0 -169
- data/src/main/java/processing/core/util/image/constants/TifConstants.java +0 -45
- data/src/main/java/processing/core/util/image/load/AwtImageLoadStrategy.java +0 -80
- data/src/main/java/processing/core/util/image/load/Base64StringImageLoadStrategy.java +0 -73
- data/src/main/java/processing/core/util/image/load/FallbackImageLoadStrategy.java +0 -70
- data/src/main/java/processing/core/util/image/load/ImageIoImageLoadStrategy.java +0 -132
- data/src/main/java/processing/core/util/image/load/ImageLoadStrategy.java +0 -48
- data/src/main/java/processing/core/util/image/load/ImageLoadUtil.java +0 -45
- data/src/main/java/processing/core/util/image/load/TgaImageLoadStrategy.java +0 -255
- data/src/main/java/processing/core/util/image/load/TiffImageLoadStrategy.java +0 -98
- data/src/main/java/processing/core/util/image/save/ImageSaveStrategy.java +0 -49
- data/src/main/java/processing/core/util/image/save/ImageSaveUtil.java +0 -48
- data/src/main/java/processing/core/util/image/save/ImageWriterImageSaveStrategy.java +0 -179
- data/src/main/java/processing/core/util/image/save/SaveImageException.java +0 -41
- data/src/main/java/processing/core/util/image/save/TgaImageSaveStrategy.java +0 -198
- data/src/main/java/processing/core/util/image/save/TiffImageSaveStrategy.java +0 -91
- data/src/main/java/processing/core/util/image/save/TiffNakedFilenameImageSaveStrategy.java +0 -57
- data/src/main/java/processing/core/util/io/InputFactory.java +0 -285
- data/src/main/java/processing/core/util/io/PathUtil.java +0 -109
- 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,10 +24,12 @@
|
|
24
24
|
|
25
25
|
package processing.core;
|
26
26
|
|
27
|
-
import
|
28
|
-
|
29
|
-
import java.
|
30
|
-
import java.
|
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;
|
31
33
|
|
32
34
|
|
33
35
|
/**
|
@@ -58,6 +60,17 @@ import java.awt.image.*;
|
|
58
60
|
*/
|
59
61
|
public class PImage implements PConstants, Cloneable {
|
60
62
|
|
63
|
+
private static final byte TIFF_HEADER[] = {
|
64
|
+
77, 77, 0, 42, 0, 0, 0, 8, 0, 9, 0, -2, 0, 4, 0, 0, 0, 1, 0, 0,
|
65
|
+
0, 0, 1, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 3, 0, 0, 0, 1,
|
66
|
+
0, 0, 0, 0, 1, 2, 0, 3, 0, 0, 0, 3, 0, 0, 0, 122, 1, 6, 0, 3, 0,
|
67
|
+
0, 0, 1, 0, 2, 0, 0, 1, 17, 0, 4, 0, 0, 0, 1, 0, 0, 3, 0, 1, 21,
|
68
|
+
0, 3, 0, 0, 0, 1, 0, 3, 0, 0, 1, 22, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0,
|
69
|
+
1, 23, 0, 4, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 8, 0, 8
|
70
|
+
};
|
71
|
+
|
72
|
+
private static final String TIFF_ERROR = "Error: Processing can only read its own TIFF files.";
|
73
|
+
|
61
74
|
/**
|
62
75
|
* Format for this image, one of RGB, ARGB or ALPHA.
|
63
76
|
* note that RGB images still require 0xff in the high byte
|
@@ -75,8 +88,8 @@ public class PImage implements PConstants, Cloneable {
|
|
75
88
|
* values. The <b>index</b> value defines the position of a value within
|
76
89
|
* the array. For example, the statement <b>color b = pixels[230]</b> will
|
77
90
|
* set the variable <b>b</b> to be equal to the value at that location in
|
78
|
-
* the array
|
79
|
-
*
|
91
|
+
* the array.
|
92
|
+
*
|
80
93
|
* Before accessing this array, the data must loaded with the
|
81
94
|
* <b>loadPixels()</b> function. After the array data has been modified,
|
82
95
|
* the <b>updatePixels()</b> function must be run to update the changes.
|
@@ -236,6 +249,7 @@ public class PImage implements PConstants, Cloneable {
|
|
236
249
|
init(width, height, format, factor);
|
237
250
|
}
|
238
251
|
|
252
|
+
|
239
253
|
/**
|
240
254
|
* Do not remove, see notes in the other variant.
|
241
255
|
*/
|
@@ -266,7 +280,7 @@ public class PImage implements PConstants, Cloneable {
|
|
266
280
|
/**
|
267
281
|
* Check the alpha on an image, using a really primitive loop.
|
268
282
|
*/
|
269
|
-
|
283
|
+
public void checkAlpha() {
|
270
284
|
if (pixels == null) return;
|
271
285
|
|
272
286
|
for (int i = 0; i < pixels.length; i++) {
|
@@ -315,117 +329,11 @@ public class PImage implements PConstants, Cloneable {
|
|
315
329
|
this.format = format;
|
316
330
|
this.pixelDensity = factor;
|
317
331
|
this.pixels = pixels;
|
318
|
-
this.pixelWidth = width * pixelDensity;
|
319
|
-
this.pixelHeight = height * pixelDensity;
|
320
|
-
}
|
321
|
-
|
322
|
-
/**
|
323
|
-
* Construct a new PImage from a java.awt.Image. This constructor assumes
|
324
|
-
* that you've done the work of making sure a MediaTracker has been used
|
325
|
-
* to fully download the data and that the img is valid.
|
326
|
-
*
|
327
|
-
* @nowebref
|
328
|
-
* @param img assumes a MediaTracker has been used to fully download
|
329
|
-
* the data and the img is valid
|
330
|
-
*/
|
331
|
-
public PImage(Image img) {
|
332
|
-
initFromImage(img);
|
333
|
-
}
|
334
|
-
|
335
|
-
/**
|
336
|
-
* @nowebref
|
337
|
-
*
|
338
|
-
* @param requiresCheckAlpha
|
339
|
-
*/
|
340
|
-
public PImage(Image img, boolean requiresCheckAlpha) {
|
341
|
-
initFromImage(img);
|
342
|
-
|
343
|
-
if (requiresCheckAlpha) {
|
344
|
-
checkAlpha();
|
345
|
-
}
|
346
|
-
}
|
347
|
-
|
348
|
-
/**
|
349
|
-
* @nowebref
|
350
|
-
*
|
351
|
-
* @param requiresCheckAlpha
|
352
|
-
*/
|
353
|
-
public PImage(Image img, boolean requiresCheckAlpha, PApplet parent) {
|
354
|
-
initFromImage(img);
|
355
|
-
|
356
|
-
this.parent = parent;
|
357
|
-
|
358
|
-
if (requiresCheckAlpha) {
|
359
|
-
checkAlpha();
|
360
|
-
}
|
361
|
-
}
|
362
|
-
|
363
|
-
private void initFromImage(Image img) {
|
364
|
-
format = RGB;
|
365
|
-
if (img instanceof BufferedImage) {
|
366
|
-
BufferedImage bi = (BufferedImage) img;
|
367
|
-
width = bi.getWidth();
|
368
|
-
height = bi.getHeight();
|
369
|
-
int type = bi.getType();
|
370
|
-
if (type == BufferedImage.TYPE_3BYTE_BGR ||
|
371
|
-
type == BufferedImage.TYPE_4BYTE_ABGR) {
|
372
|
-
pixels = new int[width * height];
|
373
|
-
bi.getRGB(0, 0, width, height, pixels, 0, width);
|
374
|
-
if (type == BufferedImage.TYPE_4BYTE_ABGR) {
|
375
|
-
format = ARGB;
|
376
|
-
} else {
|
377
|
-
opaque();
|
378
|
-
}
|
379
|
-
} else {
|
380
|
-
DataBuffer db = bi.getRaster().getDataBuffer();
|
381
|
-
if (db instanceof DataBufferInt) {
|
382
|
-
pixels = ((DataBufferInt) db).getData();
|
383
|
-
if (type == BufferedImage.TYPE_INT_ARGB) {
|
384
|
-
format = ARGB;
|
385
|
-
} else if (type == BufferedImage.TYPE_INT_RGB) {
|
386
|
-
opaque();
|
387
|
-
}
|
388
|
-
}
|
389
|
-
}
|
390
|
-
}
|
391
|
-
// Implements fall-through if not DataBufferInt above, or not a
|
392
|
-
// known type, or not DataBufferInt for the data itself.
|
393
|
-
if (pixels == null) { // go the old school Java 1.0 route
|
394
|
-
width = img.getWidth(null);
|
395
|
-
height = img.getHeight(null);
|
396
|
-
pixels = new int[width * height];
|
397
|
-
PixelGrabber pg =
|
398
|
-
new PixelGrabber(img, 0, 0, width, height, pixels, 0, width);
|
399
|
-
try {
|
400
|
-
pg.grabPixels();
|
401
|
-
} catch (InterruptedException e) { }
|
402
|
-
}
|
403
|
-
pixelDensity = 1;
|
404
|
-
pixelWidth = width;
|
405
|
-
pixelHeight = height;
|
406
|
-
}
|
407
|
-
|
408
|
-
/**
|
409
|
-
* Use the getNative() method instead, which allows library interfaces to be
|
410
|
-
* written in a cross-platform fashion for desktop, Android, and others.
|
411
|
-
* This is still included for PGraphics objects, which may need the image.
|
412
|
-
*/
|
413
|
-
public Image getImage() { // ignore
|
414
|
-
return (Image) getNative();
|
415
332
|
}
|
416
333
|
|
417
334
|
|
418
|
-
/**
|
419
|
-
* Returns a native BufferedImage from this PImage.
|
420
|
-
*/
|
421
335
|
public Object getNative() { // ignore
|
422
|
-
|
423
|
-
int type = (format == RGB) ?
|
424
|
-
BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
|
425
|
-
BufferedImage image = new BufferedImage(pixelWidth, pixelHeight, type);
|
426
|
-
WritableRaster wr = image.getRaster();
|
427
|
-
wr.setDataElements(0, 0, pixelWidth, pixelHeight, pixels);
|
428
|
-
return image;
|
336
|
+
return null;
|
429
337
|
}
|
430
338
|
|
431
339
|
|
@@ -490,7 +398,7 @@ public class PImage implements PConstants, Cloneable {
|
|
490
398
|
*
|
491
399
|
* <h3>Advanced</h3>
|
492
400
|
* Call this when you want to mess with the pixels[] array.
|
493
|
-
*
|
401
|
+
*
|
494
402
|
* For subclasses where the pixels[] buffer isn't set by default,
|
495
403
|
* this should copy all data into the pixels[] array
|
496
404
|
*
|
@@ -592,8 +500,8 @@ public class PImage implements PConstants, Cloneable {
|
|
592
500
|
* Resize the image to a new width and height. To make the image scale
|
593
501
|
* proportionally, use 0 as the value for the <b>wide</b> or <b>high</b>
|
594
502
|
* parameter. For instance, to make the width of an image 150 pixels, and
|
595
|
-
* change the height using the same proportion, use resize(150, 0)
|
596
|
-
*
|
503
|
+
* change the height using the same proportion, use resize(150, 0).
|
504
|
+
*
|
597
505
|
* Even though a PGraphics is technically a PImage, it is not possible to
|
598
506
|
* rescale the image data found in a PGraphics. (It's simply not possible
|
599
507
|
* to do this consistently across renderers: technically infeasible with
|
@@ -610,104 +518,7 @@ public class PImage implements PConstants, Cloneable {
|
|
610
518
|
* @see PImage#get(int, int, int, int)
|
611
519
|
*/
|
612
520
|
public void resize(int w, int h) { // ignore
|
613
|
-
|
614
|
-
throw new IllegalArgumentException("width or height must be > 0 for resize");
|
615
|
-
}
|
616
|
-
|
617
|
-
if (w == 0) { // Use height to determine relative size
|
618
|
-
float diff = (float) h / (float) height;
|
619
|
-
w = (int) (width * diff);
|
620
|
-
} else if (h == 0) { // Use the width to determine relative size
|
621
|
-
float diff = (float) w / (float) width;
|
622
|
-
h = (int) (height * diff);
|
623
|
-
}
|
624
|
-
|
625
|
-
BufferedImage img =
|
626
|
-
shrinkImage((BufferedImage) getNative(), w*pixelDensity, h*pixelDensity);
|
627
|
-
|
628
|
-
PImage temp = new PImage(img);
|
629
|
-
this.pixelWidth = temp.width;
|
630
|
-
this.pixelHeight = temp.height;
|
631
|
-
|
632
|
-
// Get the resized pixel array
|
633
|
-
this.pixels = temp.pixels;
|
634
|
-
|
635
|
-
this.width = pixelWidth / pixelDensity;
|
636
|
-
this.height = pixelHeight / pixelDensity;
|
637
|
-
|
638
|
-
// Mark the pixels array as altered
|
639
|
-
updatePixels();
|
640
|
-
}
|
641
|
-
|
642
|
-
|
643
|
-
// Adapted from getFasterScaledInstance() method from page 111 of
|
644
|
-
// "Filthy Rich Clients" by Chet Haase and Romain Guy
|
645
|
-
// Additional modifications and simplifications have been added,
|
646
|
-
// plus a fix to deal with an infinite loop if images are expanded.
|
647
|
-
// http://code.google.com/p/processing/issues/detail?id=1463
|
648
|
-
static private BufferedImage shrinkImage(BufferedImage img,
|
649
|
-
int targetWidth, int targetHeight) {
|
650
|
-
int type = (img.getTransparency() == Transparency.OPAQUE) ?
|
651
|
-
BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
|
652
|
-
BufferedImage outgoing = img;
|
653
|
-
BufferedImage scratchImage = null;
|
654
|
-
Graphics2D g2 = null;
|
655
|
-
int prevW = outgoing.getWidth();
|
656
|
-
int prevH = outgoing.getHeight();
|
657
|
-
boolean isTranslucent = img.getTransparency() != Transparency.OPAQUE;
|
658
|
-
|
659
|
-
// Use multi-step technique: start with original size, then scale down in
|
660
|
-
// multiple passes with drawImage() until the target size is reached
|
661
|
-
int w = img.getWidth();
|
662
|
-
int h = img.getHeight();
|
663
|
-
|
664
|
-
do {
|
665
|
-
if (w > targetWidth) {
|
666
|
-
w /= 2;
|
667
|
-
// if this is the last step, do the exact size
|
668
|
-
if (w < targetWidth) {
|
669
|
-
w = targetWidth;
|
670
|
-
}
|
671
|
-
} else if (targetWidth >= w) {
|
672
|
-
w = targetWidth;
|
673
|
-
}
|
674
|
-
if (h > targetHeight) {
|
675
|
-
h /= 2;
|
676
|
-
if (h < targetHeight) {
|
677
|
-
h = targetHeight;
|
678
|
-
}
|
679
|
-
} else if (targetHeight >= h) {
|
680
|
-
h = targetHeight;
|
681
|
-
}
|
682
|
-
if (scratchImage == null || isTranslucent) {
|
683
|
-
// Use a single scratch buffer for all iterations and then copy
|
684
|
-
// to the final, correctly-sized image before returning
|
685
|
-
scratchImage = new BufferedImage(w, h, type);
|
686
|
-
g2 = scratchImage.createGraphics();
|
687
|
-
}
|
688
|
-
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
|
689
|
-
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
690
|
-
g2.drawImage(outgoing, 0, 0, w, h, 0, 0, prevW, prevH, null);
|
691
|
-
prevW = w;
|
692
|
-
prevH = h;
|
693
|
-
outgoing = scratchImage;
|
694
|
-
} while (w != targetWidth || h != targetHeight);
|
695
|
-
|
696
|
-
if (g2 != null) {
|
697
|
-
g2.dispose();
|
698
|
-
}
|
699
|
-
|
700
|
-
// If we used a scratch buffer that is larger than our target size,
|
701
|
-
// create an image of the right size and copy the results into it
|
702
|
-
if (targetWidth != outgoing.getWidth() ||
|
703
|
-
targetHeight != outgoing.getHeight()) {
|
704
|
-
scratchImage = new BufferedImage(targetWidth, targetHeight, type);
|
705
|
-
g2 = scratchImage.createGraphics();
|
706
|
-
g2.drawImage(outgoing, 0, 0, null);
|
707
|
-
g2.dispose();
|
708
|
-
outgoing = scratchImage;
|
709
|
-
}
|
710
|
-
return outgoing;
|
521
|
+
throw new RuntimeException("resize() not implemented for this PImage type");
|
711
522
|
}
|
712
523
|
|
713
524
|
|
@@ -745,14 +556,14 @@ public class PImage implements PConstants, Cloneable {
|
|
745
556
|
* the display window by specifying an additional <b>width</b> and
|
746
557
|
* <b>height</b> parameter. When getting an image, the <b>x</b> and
|
747
558
|
* <b>y</b> parameters define the coordinates for the upper-left corner of
|
748
|
-
* the image, regardless of the current <b>imageMode()</b
|
749
|
-
*
|
559
|
+
* the image, regardless of the current <b>imageMode()</b>.
|
560
|
+
*
|
750
561
|
* If the pixel requested is outside of the image window, black is
|
751
562
|
* returned. The numbers returned are scaled according to the current color
|
752
563
|
* ranges, but only RGB values are returned by this function. For example,
|
753
564
|
* even though you may have drawn a shape with <b>colorMode(HSB)</b>, the
|
754
|
-
* numbers returned will be in RGB format
|
755
|
-
*
|
565
|
+
* numbers returned will be in RGB format.
|
566
|
+
*
|
756
567
|
* Getting the color of a single pixel with <b>get(x, y)</b> is easy, but
|
757
568
|
* not as fast as grabbing the data directly from <b>pixels[]</b>. The
|
758
569
|
* equivalent statement to <b>get(x, y)</b> using <b>pixels[]</b> is
|
@@ -899,15 +710,15 @@ public class PImage implements PConstants, Cloneable {
|
|
899
710
|
* ( begin auto-generated from PImage_set.xml )
|
900
711
|
*
|
901
712
|
* Changes the color of any pixel or writes an image directly into the
|
902
|
-
* display window
|
903
|
-
*
|
713
|
+
* display window.
|
714
|
+
*
|
904
715
|
* The <b>x</b> and <b>y</b> parameters specify the pixel to change and the
|
905
716
|
* <b>color</b> parameter specifies the color value. The color parameter is
|
906
717
|
* affected by the current color mode (the default is RGB values from 0 to
|
907
718
|
* 255). When setting an image, the <b>x</b> and <b>y</b> parameters define
|
908
719
|
* the coordinates for the upper-left corner of the image, regardless of
|
909
720
|
* the current <b>imageMode()</b>.
|
910
|
-
*
|
721
|
+
*
|
911
722
|
* Setting the color of a single pixel with <b>set(x, y)</b> is easy, but
|
912
723
|
* not as fast as putting the data directly into <b>pixels[]</b>. The
|
913
724
|
* equivalent statement to <b>set(x, y, #000000)</b> using <b>pixels[]</b>
|
@@ -1003,7 +814,7 @@ public class PImage implements PConstants, Cloneable {
|
|
1003
814
|
* @param maskArray array of integers used as the alpha channel, needs to be
|
1004
815
|
* the same length as the image's pixel array.
|
1005
816
|
*/
|
1006
|
-
public void mask(int maskArray
|
817
|
+
public void mask(int[] maskArray) { // ignore
|
1007
818
|
loadPixels();
|
1008
819
|
// don't execute if mask image is different size
|
1009
820
|
if (maskArray.length != pixels.length) {
|
@@ -1023,8 +834,8 @@ public class PImage implements PConstants, Cloneable {
|
|
1023
834
|
* Masks part of an image from displaying by loading another image and
|
1024
835
|
* using it as an alpha channel. This mask image should only contain
|
1025
836
|
* grayscale data, but only the blue color channel is used. The mask image
|
1026
|
-
* needs to be the same size as the image to which it is applied
|
1027
|
-
*
|
837
|
+
* needs to be the same size as the image to which it is applied.
|
838
|
+
*
|
1028
839
|
* In addition to using a mask image, an integer array containing the alpha
|
1029
840
|
* channel data can be specified directly. This method is useful for
|
1030
841
|
* creating dynamically generated alpha masks. This array must be of the
|
@@ -1138,28 +949,28 @@ public class PImage implements PConstants, Cloneable {
|
|
1138
949
|
/**
|
1139
950
|
* ( begin auto-generated from PImage_filter.xml )
|
1140
951
|
*
|
1141
|
-
* Filters an image as defined by one of the following modes
|
1142
|
-
*
|
952
|
+
* Filters an image as defined by one of the following modes:
|
953
|
+
* THRESHOLD - converts the image to black and white pixels depending if
|
1143
954
|
* they are above or below the threshold defined by the level parameter.
|
1144
955
|
* The level must be between 0.0 (black) and 1.0(white). If no level is
|
1145
|
-
* specified, 0.5 is used
|
1146
|
-
*
|
1147
|
-
* GRAY - converts any colors in the image to grayscale equivalents
|
1148
|
-
*
|
1149
|
-
* INVERT - sets each pixel to its inverse value
|
1150
|
-
*
|
956
|
+
* specified, 0.5 is used.
|
957
|
+
*
|
958
|
+
* GRAY - converts any colors in the image to grayscale equivalents
|
959
|
+
*
|
960
|
+
* INVERT - sets each pixel to its inverse value
|
961
|
+
*
|
1151
962
|
* POSTERIZE - limits each channel of the image to the number of colors
|
1152
|
-
* specified as the level parameter
|
1153
|
-
*
|
963
|
+
* specified as the level parameter
|
964
|
+
*
|
1154
965
|
* BLUR - executes a Guassian blur with the level parameter specifying the
|
1155
966
|
* extent of the blurring. If no level parameter is used, the blur is
|
1156
|
-
* equivalent to Guassian blur of radius 1
|
1157
|
-
*
|
1158
|
-
* OPAQUE - sets the alpha channel to entirely opaque
|
1159
|
-
*
|
967
|
+
* equivalent to Guassian blur of radius 1
|
968
|
+
*
|
969
|
+
* OPAQUE - sets the alpha channel to entirely opaque
|
970
|
+
*
|
1160
971
|
* ERODE - reduces the light areas with the amount defined by the level
|
1161
|
-
* parameter
|
1162
|
-
*
|
972
|
+
* parameter
|
973
|
+
*
|
1163
974
|
* DILATE - increases the light areas with the amount defined by the level parameter
|
1164
975
|
*
|
1165
976
|
* ( end auto-generated )
|
@@ -1178,7 +989,7 @@ public class PImage implements PConstants, Cloneable {
|
|
1178
989
|
* </UL>
|
1179
990
|
* Luminance conversion code contributed by
|
1180
991
|
* <A HREF="http://www.toxi.co.uk">toxi</A>
|
1181
|
-
*
|
992
|
+
*
|
1182
993
|
* Gaussian blur code contributed by
|
1183
994
|
* <A HREF="http://incubator.quasimondo.com">Mario Klingemann</A>
|
1184
995
|
*
|
@@ -1193,14 +1004,20 @@ public class PImage implements PConstants, Cloneable {
|
|
1193
1004
|
|
1194
1005
|
switch (kind) {
|
1195
1006
|
case BLUR:
|
1196
|
-
|
1007
|
+
switch (format) {
|
1008
|
+
case ALPHA:
|
1197
1009
|
blurAlpha(param);
|
1198
|
-
|
1010
|
+
break;
|
1011
|
+
case ARGB:
|
1199
1012
|
blurARGB(param);
|
1200
|
-
|
1013
|
+
break;
|
1014
|
+
default:
|
1201
1015
|
blurRGB(param);
|
1016
|
+
break;
|
1017
|
+
}
|
1202
1018
|
break;
|
1203
1019
|
|
1020
|
+
|
1204
1021
|
case GRAY:
|
1205
1022
|
throw new RuntimeException("Use filter(GRAY) instead of " +
|
1206
1023
|
"filter(GRAY, param)");
|
@@ -1302,7 +1119,7 @@ public class PImage implements PConstants, Cloneable {
|
|
1302
1119
|
protected void blurAlpha(float r) {
|
1303
1120
|
int sum, cb;
|
1304
1121
|
int read, ri, ym, ymi, bk0;
|
1305
|
-
int
|
1122
|
+
int[] b2 = new int[pixels.length];
|
1306
1123
|
int yi = 0;
|
1307
1124
|
|
1308
1125
|
buildBlurKernel(r);
|
@@ -1373,9 +1190,9 @@ public class PImage implements PConstants, Cloneable {
|
|
1373
1190
|
protected void blurRGB(float r) {
|
1374
1191
|
int sum, cr, cg, cb; //, k;
|
1375
1192
|
int /*pixel,*/ read, ri, /*roff,*/ ym, ymi, /*riw,*/ bk0;
|
1376
|
-
int
|
1377
|
-
int
|
1378
|
-
int
|
1193
|
+
int[] r2 = new int[pixels.length];
|
1194
|
+
int[] g2 = new int[pixels.length];
|
1195
|
+
int[] b2 = new int[pixels.length];
|
1379
1196
|
int yi = 0;
|
1380
1197
|
|
1381
1198
|
buildBlurKernel(r);
|
@@ -1456,10 +1273,10 @@ public class PImage implements PConstants, Cloneable {
|
|
1456
1273
|
int sum, cr, cg, cb, ca;
|
1457
1274
|
int /*pixel,*/ read, ri, /*roff,*/ ym, ymi, /*riw,*/ bk0;
|
1458
1275
|
int wh = pixels.length;
|
1459
|
-
int
|
1460
|
-
int
|
1461
|
-
int
|
1462
|
-
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];
|
1463
1280
|
int yi = 0;
|
1464
1281
|
|
1465
1282
|
buildBlurKernel(r);
|
@@ -1695,7 +1512,7 @@ public class PImage implements PConstants, Cloneable {
|
|
1695
1512
|
* source pixels to fit the specified target region. No alpha information
|
1696
1513
|
* is used in the process, however if the source image has an alpha channel
|
1697
1514
|
* set, it will be copied as well.
|
1698
|
-
*
|
1515
|
+
*
|
1699
1516
|
* As of release 0149, this function ignores <b>imageMode()</b>.
|
1700
1517
|
*
|
1701
1518
|
* ( end auto-generated )
|
@@ -1799,7 +1616,7 @@ public class PImage implements PConstants, Cloneable {
|
|
1799
1616
|
* necessarily "correct" code. No biggie, most software does. A nitpicker
|
1800
1617
|
* can find numerous "off by 1 division" problems in the blend code where
|
1801
1618
|
* <TT>>>8</TT> or <TT>>>7</TT> is used when strictly speaking
|
1802
|
-
* <TT>/255.0</
|
1619
|
+
* <TT>/255.0</TT> or <TT>/127.0</TT> should have been used.</P>
|
1803
1620
|
* <P>For instance, exclusion (not intended for real-time use) reads
|
1804
1621
|
* <TT>r1 + r2 - ((2 * r1 * r2) / 255)</TT> because <TT>255 == 1.0</TT>
|
1805
1622
|
* not <TT>256 == 1.0</TT>. In other words, <TT>(255*255)>>8</TT> is not
|
@@ -1855,47 +1672,47 @@ public class PImage implements PConstants, Cloneable {
|
|
1855
1672
|
* Blends a region of pixels into the image specified by the <b>img</b>
|
1856
1673
|
* parameter. These copies utilize full alpha channel support and a choice
|
1857
1674
|
* of the following modes to blend the colors of source pixels (A) with the
|
1858
|
-
* ones of pixels in the destination image (B)
|
1859
|
-
*
|
1860
|
-
* BLEND - linear interpolation of colours: C = A*factor + B
|
1861
|
-
*
|
1862
|
-
* ADD - additive blending with white clip: C = min(A*factor + B, 255)
|
1863
|
-
*
|
1675
|
+
* ones of pixels in the destination image (B):
|
1676
|
+
*
|
1677
|
+
* BLEND - linear interpolation of colours: C = A*factor + B
|
1678
|
+
*
|
1679
|
+
* ADD - additive blending with white clip: C = min(A*factor + B, 255)
|
1680
|
+
*
|
1864
1681
|
* SUBTRACT - subtractive blending with black clip: C = max(B - A*factor,
|
1865
|
-
* 0)
|
1866
|
-
*
|
1867
|
-
* DARKEST - only the darkest colour succeeds: C = min(A*factor, B)
|
1868
|
-
*
|
1869
|
-
* LIGHTEST - only the lightest colour succeeds: C = max(A*factor, B)
|
1870
|
-
*
|
1871
|
-
* DIFFERENCE - subtract colors from underlying image
|
1872
|
-
*
|
1873
|
-
* EXCLUSION - similar to DIFFERENCE, but less extreme
|
1874
|
-
*
|
1875
|
-
* MULTIPLY - Multiply the colors, result will always be darker
|
1876
|
-
*
|
1877
|
-
* SCREEN - Opposite multiply, uses inverse values of the colors
|
1878
|
-
*
|
1682
|
+
* 0)
|
1683
|
+
*
|
1684
|
+
* DARKEST - only the darkest colour succeeds: C = min(A*factor, B)
|
1685
|
+
*
|
1686
|
+
* LIGHTEST - only the lightest colour succeeds: C = max(A*factor, B)
|
1687
|
+
*
|
1688
|
+
* DIFFERENCE - subtract colors from underlying image.
|
1689
|
+
*
|
1690
|
+
* EXCLUSION - similar to DIFFERENCE, but less extreme.
|
1691
|
+
*
|
1692
|
+
* MULTIPLY - Multiply the colors, result will always be darker.
|
1693
|
+
*
|
1694
|
+
* SCREEN - Opposite multiply, uses inverse values of the colors.
|
1695
|
+
*
|
1879
1696
|
* OVERLAY - A mix of MULTIPLY and SCREEN. Multiplies dark values,
|
1880
|
-
* and screens light values
|
1881
|
-
*
|
1882
|
-
* HARD_LIGHT - SCREEN when greater than 50% gray, MULTIPLY when lower
|
1883
|
-
*
|
1697
|
+
* and screens light values.
|
1698
|
+
*
|
1699
|
+
* HARD_LIGHT - SCREEN when greater than 50% gray, MULTIPLY when lower.
|
1700
|
+
*
|
1884
1701
|
* SOFT_LIGHT - Mix of DARKEST and LIGHTEST.
|
1885
|
-
* Works like OVERLAY, but not as harsh
|
1886
|
-
*
|
1702
|
+
* Works like OVERLAY, but not as harsh.
|
1703
|
+
*
|
1887
1704
|
* DODGE - Lightens light tones and increases contrast, ignores darks.
|
1888
|
-
* Called "Color Dodge" in Illustrator and Photoshop
|
1889
|
-
*
|
1705
|
+
* Called "Color Dodge" in Illustrator and Photoshop.
|
1706
|
+
*
|
1890
1707
|
* BURN - Darker areas are applied, increasing contrast, ignores lights.
|
1891
|
-
* Called "Color Burn" in Illustrator and Photoshop
|
1892
|
-
*
|
1708
|
+
* Called "Color Burn" in Illustrator and Photoshop.
|
1709
|
+
*
|
1893
1710
|
* All modes use the alpha information (highest byte) of source image
|
1894
1711
|
* pixels as the blending factor. If the source and destination regions are
|
1895
1712
|
* different sizes, the image will be automatically resized to match the
|
1896
1713
|
* destination size. If the <b>srcImg</b> parameter is not used, the
|
1897
|
-
* display window is used as the source image
|
1898
|
-
*
|
1714
|
+
* display window is used as the source image.
|
1715
|
+
*
|
1899
1716
|
* As of release 0149, this function ignores <b>imageMode()</b>.
|
1900
1717
|
*
|
1901
1718
|
* ( end auto-generated )
|
@@ -3010,18 +2827,465 @@ int testFunction(int dst, int src) {
|
|
3010
2827
|
|
3011
2828
|
// FILE I/O
|
3012
2829
|
|
3013
|
-
|
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
|
+
|
2839
|
+
if ((tiff[42] != tiff[102]) || // width/height in both places
|
2840
|
+
(tiff[43] != tiff[103])) {
|
2841
|
+
System.err.println(TIFF_ERROR);
|
2842
|
+
return null;
|
2843
|
+
}
|
2844
|
+
|
2845
|
+
int width =
|
2846
|
+
((tiff[30] & 0xff) << 8) | (tiff[31] & 0xff);
|
2847
|
+
int height =
|
2848
|
+
((tiff[42] & 0xff) << 8) | (tiff[43] & 0xff);
|
2849
|
+
|
2850
|
+
int count =
|
2851
|
+
((tiff[114] & 0xff) << 24) |
|
2852
|
+
((tiff[115] & 0xff) << 16) |
|
2853
|
+
((tiff[116] & 0xff) << 8) |
|
2854
|
+
(tiff[117] & 0xff);
|
2855
|
+
if (count != width * height * 3) {
|
2856
|
+
System.err.println(TIFF_ERROR + " (" + width + ", " + height +")");
|
2857
|
+
return null;
|
2858
|
+
}
|
2859
|
+
|
2860
|
+
// check the rest of the header
|
2861
|
+
for (int i = 0; i < TIFF_HEADER.length; i++) {
|
2862
|
+
if ((i == 30) || (i == 31) || (i == 42) || (i == 43) ||
|
2863
|
+
(i == 102) || (i == 103) ||
|
2864
|
+
(i == 114) || (i == 115) || (i == 116) || (i == 117)) continue;
|
2865
|
+
|
2866
|
+
if (tiff[i] != TIFF_HEADER[i]) {
|
2867
|
+
System.err.println(TIFF_ERROR + " (" + i + ")");
|
2868
|
+
return null;
|
2869
|
+
}
|
2870
|
+
}
|
2871
|
+
|
2872
|
+
PImage outgoing = new PImage(width, height, RGB);
|
2873
|
+
int index = 768;
|
2874
|
+
count /= 3;
|
2875
|
+
for (int i = 0; i < count; i++) {
|
2876
|
+
outgoing.pixels[i] =
|
2877
|
+
0xFF000000 |
|
2878
|
+
(tiff[index++] & 0xff) << 16 |
|
2879
|
+
(tiff[index++] & 0xff) << 8 |
|
2880
|
+
(tiff[index++] & 0xff);
|
2881
|
+
}
|
2882
|
+
return outgoing;
|
2883
|
+
}
|
2884
|
+
|
2885
|
+
protected boolean saveTIFF(OutputStream output) {
|
2886
|
+
// shutting off the warning, people can figure this out themselves
|
2887
|
+
/*
|
2888
|
+
if (format != RGB) {
|
2889
|
+
System.err.println("Warning: only RGB information is saved with " +
|
2890
|
+
".tif files. Use .tga or .png for ARGB images and others.");
|
2891
|
+
}
|
2892
|
+
*/
|
2893
|
+
try {
|
2894
|
+
byte[] tiff = new byte[768];
|
2895
|
+
System.arraycopy(TIFF_HEADER, 0, tiff, 0, TIFF_HEADER.length);
|
2896
|
+
|
2897
|
+
tiff[30] = (byte) ((pixelWidth >> 8) & 0xff);
|
2898
|
+
tiff[31] = (byte) ((pixelWidth) & 0xff);
|
2899
|
+
tiff[42] = tiff[102] = (byte) ((pixelHeight >> 8) & 0xff);
|
2900
|
+
tiff[43] = tiff[103] = (byte) ((pixelHeight) & 0xff);
|
2901
|
+
|
2902
|
+
int count = pixelWidth*pixelHeight*3;
|
2903
|
+
tiff[114] = (byte) ((count >> 24) & 0xff);
|
2904
|
+
tiff[115] = (byte) ((count >> 16) & 0xff);
|
2905
|
+
tiff[116] = (byte) ((count >> 8) & 0xff);
|
2906
|
+
tiff[117] = (byte) ((count) & 0xff);
|
2907
|
+
|
2908
|
+
// spew the header to the disk
|
2909
|
+
output.write(tiff);
|
2910
|
+
|
2911
|
+
for (int i = 0; i < pixels.length; i++) {
|
2912
|
+
output.write((pixels[i] >> 16) & 0xff);
|
2913
|
+
output.write((pixels[i] >> 8) & 0xff);
|
2914
|
+
output.write(pixels[i] & 0xff);
|
2915
|
+
}
|
2916
|
+
output.flush();
|
2917
|
+
return true;
|
2918
|
+
|
2919
|
+
} catch (IOException e) {
|
2920
|
+
}
|
2921
|
+
return false;
|
2922
|
+
}
|
2923
|
+
|
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
|
+
|
3124
|
+
/**
|
3125
|
+
* Creates a Targa32 formatted byte sequence of specified
|
3126
|
+
* pixel buffer using RLE compression.
|
3127
|
+
* <p>
|
3128
|
+
* Also figured out how to avoid parsing the image upside-down
|
3129
|
+
* (there's a header flag to set the image origin to top-left)
|
3130
|
+
* </p>
|
3131
|
+
* Starting with revision 0092, the format setting is taken into account:
|
3132
|
+
* <UL>
|
3133
|
+
* <LI><TT>ALPHA</TT> images written as 8bit grayscale (uses lowest byte)
|
3134
|
+
* <LI><TT>RGB</TT> → 24 bits
|
3135
|
+
* <LI><TT>ARGB</TT> → 32 bits
|
3136
|
+
* </UL>
|
3137
|
+
* All versions are RLE compressed.
|
3138
|
+
*
|
3139
|
+
* Contributed by toxi 8-10 May 2005, based on this RLE
|
3140
|
+
* <A HREF="http://www.wotsit.org/download.asp?f=tga">specification</A>
|
3141
|
+
*/
|
3142
|
+
protected boolean saveTGA(OutputStream output) {
|
3143
|
+
byte[] header = new byte[18];
|
3144
|
+
|
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
|
+
}
|
3165
|
+
// set image dimensions lo-hi byte order
|
3166
|
+
header[12] = (byte) (pixelWidth & 0xff);
|
3167
|
+
header[13] = (byte) (pixelWidth >> 8);
|
3168
|
+
header[14] = (byte) (pixelHeight & 0xff);
|
3169
|
+
header[15] = (byte) (pixelHeight >> 8);
|
3170
|
+
|
3171
|
+
try {
|
3172
|
+
output.write(header);
|
3173
|
+
|
3174
|
+
int maxLen = pixelHeight * pixelWidth;
|
3175
|
+
int index = 0;
|
3176
|
+
int col; //, prevCol;
|
3177
|
+
int[] currChunk = new int[128];
|
3178
|
+
|
3179
|
+
// 8bit image exporter is in separate loop
|
3180
|
+
// to avoid excessive conditionals...
|
3181
|
+
if (format == ALPHA) {
|
3182
|
+
while (index < maxLen) {
|
3183
|
+
boolean isRLE = false;
|
3184
|
+
int rle = 1;
|
3185
|
+
currChunk[0] = col = pixels[index] & 0xff;
|
3186
|
+
while (index + rle < maxLen) {
|
3187
|
+
if (col != (pixels[index + rle]&0xff) || rle == 128) {
|
3188
|
+
isRLE = (rle > 1);
|
3189
|
+
break;
|
3190
|
+
}
|
3191
|
+
rle++;
|
3192
|
+
}
|
3193
|
+
if (isRLE) {
|
3194
|
+
output.write(0x80 | (rle - 1));
|
3195
|
+
output.write(col);
|
3196
|
+
|
3197
|
+
} else {
|
3198
|
+
rle = 1;
|
3199
|
+
while (index + rle < maxLen) {
|
3200
|
+
int cscan = pixels[index + rle] & 0xff;
|
3201
|
+
if ((col != cscan && rle < 128) || rle < 3) {
|
3202
|
+
currChunk[rle] = col = cscan;
|
3203
|
+
} else {
|
3204
|
+
if (col == cscan) rle -= 2;
|
3205
|
+
break;
|
3206
|
+
}
|
3207
|
+
rle++;
|
3208
|
+
}
|
3209
|
+
output.write(rle - 1);
|
3210
|
+
for (int i = 0; i < rle; i++) output.write(currChunk[i]);
|
3211
|
+
}
|
3212
|
+
index += rle;
|
3213
|
+
}
|
3214
|
+
} else { // export 24/32 bit TARGA
|
3215
|
+
while (index < maxLen) {
|
3216
|
+
boolean isRLE = false;
|
3217
|
+
currChunk[0] = col = pixels[index];
|
3218
|
+
int rle = 1;
|
3219
|
+
// try to find repeating bytes (min. len = 2 pixels)
|
3220
|
+
// maximum chunk size is 128 pixels
|
3221
|
+
while (index + rle < maxLen) {
|
3222
|
+
if (col != pixels[index + rle] || rle == 128) {
|
3223
|
+
isRLE = (rle > 1); // set flag for RLE chunk
|
3224
|
+
break;
|
3225
|
+
}
|
3226
|
+
rle++;
|
3227
|
+
}
|
3228
|
+
if (isRLE) {
|
3229
|
+
output.write(128 | (rle - 1));
|
3230
|
+
output.write(col & 0xff);
|
3231
|
+
output.write(col >> 8 & 0xff);
|
3232
|
+
output.write(col >> 16 & 0xff);
|
3233
|
+
if (format == ARGB) output.write(col >>> 24 & 0xff);
|
3234
|
+
|
3235
|
+
} else { // not RLE
|
3236
|
+
rle = 1;
|
3237
|
+
while (index + rle < maxLen) {
|
3238
|
+
if ((col != pixels[index + rle] && rle < 128) || rle < 3) {
|
3239
|
+
currChunk[rle] = col = pixels[index + rle];
|
3240
|
+
} else {
|
3241
|
+
// check if the exit condition was the start of
|
3242
|
+
// a repeating colour
|
3243
|
+
if (col == pixels[index + rle]) rle -= 2;
|
3244
|
+
break;
|
3245
|
+
}
|
3246
|
+
rle++;
|
3247
|
+
}
|
3248
|
+
// write uncompressed chunk
|
3249
|
+
output.write(rle - 1);
|
3250
|
+
if (format == ARGB) {
|
3251
|
+
for (int i = 0; i < rle; i++) {
|
3252
|
+
col = currChunk[i];
|
3253
|
+
output.write(col & 0xff);
|
3254
|
+
output.write(col >> 8 & 0xff);
|
3255
|
+
output.write(col >> 16 & 0xff);
|
3256
|
+
output.write(col >>> 24 & 0xff);
|
3257
|
+
}
|
3258
|
+
} else {
|
3259
|
+
for (int i = 0; i < rle; i++) {
|
3260
|
+
col = currChunk[i];
|
3261
|
+
output.write(col & 0xff);
|
3262
|
+
output.write(col >> 8 & 0xff);
|
3263
|
+
output.write(col >> 16 & 0xff);
|
3264
|
+
}
|
3265
|
+
}
|
3266
|
+
}
|
3267
|
+
index += rle;
|
3268
|
+
}
|
3269
|
+
}
|
3270
|
+
output.flush();
|
3271
|
+
return true;
|
3272
|
+
|
3273
|
+
} catch (IOException e) {
|
3274
|
+
return false;
|
3275
|
+
}
|
3276
|
+
}
|
3277
|
+
|
3014
3278
|
|
3015
3279
|
/**
|
3016
3280
|
* ( begin auto-generated from PImage_save.xml )
|
3017
3281
|
*
|
3018
|
-
* Saves the image into a file.Append a file extension to the name of
|
3019
|
-
the file, to indicate the file format to be used: either TIFF (.tif),
|
3020
|
-
TARGA (.tga), JPEG (.jpg), or PNG (.png). If no extension is included
|
3021
|
-
in the filename, the image will save in TIFF format and .tif will be
|
3022
|
-
added to the name. These files are saved to the sketch's folder, which
|
3023
|
-
may be opened by selecting "Show sketch folder" from the "Sketch" menu.
|
3024
|
-
|
3282
|
+
* Saves the image into a file. Append a file extension to the name of
|
3283
|
+
* the file, to indicate the file format to be used: either TIFF (.tif),
|
3284
|
+
* TARGA (.tga), JPEG (.jpg), or PNG (.png). If no extension is included
|
3285
|
+
* in the filename, the image will save in TIFF format and .tif will be
|
3286
|
+
* added to the name. These files are saved to the sketch's folder, which
|
3287
|
+
* may be opened by selecting "Show sketch folder" from the "Sketch" menu.
|
3288
|
+
* To save an image created within the code, rather
|
3025
3289
|
* than through loading, it's necessary to make the image with the
|
3026
3290
|
* <b>createImage()</b> function so it is aware of the location of the
|
3027
3291
|
* program and can therefore save the file to the right place. See the
|
@@ -3053,23 +3317,61 @@ int testFunction(int dst, int src) {
|
|
3053
3317
|
* require a black and white image. Basic testing produced a zero-length
|
3054
3318
|
* file with no error.
|
3055
3319
|
*
|
3056
|
-
* @return
|
3057
3320
|
* @webref pimage:method
|
3058
3321
|
* @brief Saves the image to a TIFF, TARGA, PNG, or JPEG file
|
3059
3322
|
* @usage application
|
3060
3323
|
* @param filename a sequence of letters and numbers
|
3061
3324
|
*/
|
3062
|
-
|
3063
|
-
|
3064
|
-
|
3065
|
-
|
3066
|
-
|
3067
|
-
|
3068
|
-
|
3069
|
-
|
3070
|
-
|
3071
|
-
|
3072
|
-
|
3073
|
-
|
3074
|
-
|
3325
|
+
public boolean save(String filename) { // ignore
|
3326
|
+
boolean success = false;
|
3327
|
+
|
3328
|
+
if (parent != null) {
|
3329
|
+
// use savePath(), so that the intermediate directories are created
|
3330
|
+
filename = parent.savePath(filename);
|
3331
|
+
|
3332
|
+
} else {
|
3333
|
+
File file = new File(filename);
|
3334
|
+
if (file.isAbsolute()) {
|
3335
|
+
// make sure that the intermediate folders have been created
|
3336
|
+
PApplet.createPath(file);
|
3337
|
+
} else {
|
3338
|
+
String msg =
|
3339
|
+
"PImage.save() requires an absolute path. " +
|
3340
|
+
"Use createImage(), or pass savePath() to save().";
|
3341
|
+
PGraphics.showException(msg);
|
3342
|
+
}
|
3343
|
+
}
|
3344
|
+
|
3345
|
+
// Make sure the pixel data is ready to go
|
3346
|
+
loadPixels();
|
3347
|
+
|
3348
|
+
try {
|
3349
|
+
OutputStream os = null;
|
3350
|
+
|
3351
|
+
if (saveImpl(filename)) {
|
3352
|
+
return true;
|
3353
|
+
}
|
3354
|
+
|
3355
|
+
if (filename.toLowerCase().endsWith(".tga")) {
|
3356
|
+
os = new BufferedOutputStream(new FileOutputStream(filename), 32768);
|
3357
|
+
success = saveTGA(os); //, pixels, width, height, format);
|
3358
|
+
|
3359
|
+
} else {
|
3360
|
+
if (!filename.toLowerCase().endsWith(".tif") &&
|
3361
|
+
!filename.toLowerCase().endsWith(".tiff")) {
|
3362
|
+
// if no .tif extension, add it..
|
3363
|
+
filename += ".tif";
|
3364
|
+
}
|
3365
|
+
os = new BufferedOutputStream(new FileOutputStream(filename), 32768);
|
3366
|
+
success = saveTIFF(os); //, pixels, width, height);
|
3367
|
+
}
|
3368
|
+
os.flush();
|
3369
|
+
os.close();
|
3370
|
+
|
3371
|
+
} catch (IOException e) {
|
3372
|
+
System.err.println("Error while saving image.");
|
3373
|
+
success = false;
|
3374
|
+
}
|
3375
|
+
return success;
|
3376
|
+
}
|
3075
3377
|
}
|