rhodes 3.3.3.beta.1 → 3.3.3.beta.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +3 -0
- data/Manifest.txt +23 -9
- data/Rakefile +13 -2
- data/doc/build.txt +18 -11
- data/doc/device-caps.txt +4 -68
- data/doc/rhom.txt +33 -0
- data/doc/test-log-debug.txt +18 -42
- data/lib/framework/rho/render.rb +1 -1
- data/lib/framework/rho/rho.rb +31 -1
- data/lib/framework/rho/rhocontroller.rb +2 -2
- data/lib/framework/rhodes.rb +1 -1
- data/lib/framework/rhoframework.rb +4 -0
- data/lib/framework/rholang/localization_simplified.rb +1 -1
- data/lib/framework/rhom/rhom_object_factory.rb +22 -1
- data/lib/framework/version.rb +1 -1
- data/lib/rhodes.rb +1 -1
- data/platform/android/Rhodes/AndroidManifest.xml +2 -2
- data/platform/android/Rhodes/jni/include/rhodes/jni/com_rhomobile_rhodes_RhodesService.h +25 -9
- data/platform/android/Rhodes/jni/include/rhodes/jni/com_rhomobile_rhodes_extmanager_RhoExtManagerImpl.h +21 -0
- data/platform/android/Rhodes/jni/src/extmanager.cpp +36 -0
- data/platform/android/Rhodes/jni/src/nativeview.cpp +1 -1
- data/platform/android/Rhodes/jni/src/rhodesapp.cpp +14 -5
- data/platform/android/Rhodes/jni/src/rhodessystem.cpp +5 -0
- data/platform/android/Rhodes/jni/src/signature.cpp +29 -3
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/NativeBar.java +3 -3
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/RhodesActivity.java +4 -0
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/RhodesService.java +42 -7
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/WebView.java +61 -10
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/extmanager/IRhoExtData.java +6 -0
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/extmanager/IRhoExtManager.java +39 -0
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/extmanager/IRhoExtension.java +18 -0
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/extmanager/RhoExtDataImpl.java +18 -0
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/extmanager/RhoExtManagerImpl.java +142 -0
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/extmanager/RhoExtManagerSingleton.java +15 -0
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/mainview/MainView.java +6 -3
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/mainview/SimpleMainView.java +25 -13
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/mainview/SplashScreen.java +15 -9
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/mainview/TabbedMainView.java +15 -5
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/nativeview/RhoNativeViewManager.java +3 -3
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/signature/ImageCapture.java +14 -8
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/signature/Signature.java +218 -51
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/signature/SignatureProperties.java +94 -0
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/signature/SignatureView.java +122 -37
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/webview/GoogleWebView.java +6 -2
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/webview/{WebView.java → IRhoWebView.java} +2 -1
- data/platform/android/Rhodes/src/com/rhomobile/rhodes/webview/RhoWebViewClient.java +4 -0
- data/platform/android/build/RhodesSRC_build.files +8 -1
- data/platform/android/build/android.rake +5 -1
- data/platform/android/build/librhodes_build.files +1 -0
- data/platform/bb/RubyVM/src/com/rho/RhodesApp.java +22 -1
- data/platform/bb/RubyVM/src/com/rho/sync/SyncSource.java +15 -0
- data/platform/bb/RubyVM/src/com/xruby/runtime/lang/RhoSupport.java +4 -0
- data/platform/bb/RubyVM/src/com/xruby/runtime/lang/RubyRuntime.java +4 -2
- data/platform/bb/build/rhodes_build.files +2 -0
- data/platform/bb/rhodes/src/com/rho/RhoRubyHelper.java +1 -1
- data/platform/bb/rhodes/src/com/rho/rubyext/PNGEncoder.java +613 -0
- data/platform/bb/rhodes/src/com/rho/rubyext/SignatureCapture.java +314 -0
- data/platform/bb/rhodes/src/com/rho/rubyext/WebView.java +1 -1
- data/platform/iphone/Classes/AppManager/AppManager.m +11 -0
- data/platform/iphone/Classes/Rhodes.m +1 -1
- data/platform/iphone/Classes/Signature/SignatureDelegate.h +5 -1
- data/platform/iphone/Classes/Signature/SignatureDelegate.m +186 -5
- data/platform/iphone/Classes/Signature/SignatureView.h +12 -0
- data/platform/iphone/Classes/Signature/SignatureView.m +11 -3
- data/platform/iphone/Classes/SimpleMainView.m +4 -0
- data/platform/iphone/Classes/rho/net/NetRequestImpl.m +98 -3
- data/platform/iphone/Info.plist +1 -1
- data/platform/iphone/rbuild/iphone.rake +18 -5
- data/platform/shared/RhoConnectClient/RhoConnectClient.cpp +1 -1
- data/platform/shared/common/ExtManager.h +64 -9
- data/platform/shared/common/RhoSimConf.h +1 -0
- data/platform/shared/common/RhodesApp.cpp +77 -28
- data/platform/shared/common/RhodesApp.h +9 -4
- data/platform/shared/common/RhodesAppBase.cpp +4 -3
- data/platform/shared/common/RhodesAppBase.h +5 -3
- data/platform/shared/net/HttpServer.cpp +4 -4
- data/platform/shared/net/HttpServer.h +2 -2
- data/platform/shared/qt/rhodes/impl/MainWindowImpl.cpp +1 -1
- data/platform/shared/qt/rhodes/main.cpp +1 -1
- data/platform/shared/ruby/ext/rho/rhoruby.c +12 -2
- data/platform/shared/ruby/ext/rho/rhosupport.c +11 -1
- data/platform/shared/ruby/thread_win32.c +2 -1
- data/platform/shared/rubyext/System.cpp +6 -0
- data/platform/shared/sync/SyncSource.cpp +15 -0
- data/platform/wm/RhoLib/RhoLib.vcproj +0 -4
- data/platform/wm/build/build_inf.js +34 -4
- data/platform/wm/build/wm.rake +75 -25
- data/platform/wm/rhodes/AppManager.cpp +14 -3
- data/platform/wm/rhodes/IBrowserEngine.h +7 -0
- data/platform/wm/rhodes/IEBrowserEngine.cpp +43 -0
- data/platform/wm/rhodes/IEBrowserEngine.h +7 -0
- data/platform/wm/rhodes/LogOptionsDlg.cpp +1 -1
- data/platform/wm/rhodes/MainWindow.cpp +92 -7
- data/platform/wm/rhodes/MainWindow.h +28 -1
- data/platform/wm/rhodes/MapView/MapViewManager.cpp +4 -4
- data/platform/wm/rhodes/Rhodes.cpp +149 -10
- data/platform/wm/rhodes/resource.h +5 -1
- data/platform/wm/rhodes/rho/common/ExtManager.cpp +307 -0
- data/platform/wm/rhodes/rho/rubyext/NativeToolbar.cpp +1 -1
- data/platform/wm/rhodes/rho/rubyext/RhoSignature.cpp +1 -1
- data/platform/wm/rhodes/rho/rubyext/RhoSignature.h +1 -1
- data/platform/wm/rhodes/rho/rubyext/SystemImpl.cpp +14 -2
- data/platform/wm/rhodes/rho/rubyext/WebView.cpp +6 -3
- data/platform/wm/rhodes/rhodes.vcproj +5 -1
- data/platform/wm/rhodes/simulator/MainWindowQt.cpp +22 -1
- data/platform/wm/rhodes/simulator/MainWindowQt.h +4 -0
- data/platform/wp7/RhoRubyExtGen/RhoWebView.cs +1 -1
- data/platform/wp7/RhoRubyLib/Initializers.Generated.cs +1 -1
- data/platform/wp7/RhoRubyLib/common/RhodesApp.cs +33 -38
- data/platform/wp7/RhoRubyLib/net/HttpServer.cs +134 -29
- data/platform/wp7/RhoRubyLib/rubyext/RhoWebView.cs +12 -2
- data/platform/wp7/RhoRubyLib/sync/SyncSource.cs +17 -1
- data/platform/wp7/RhoRubyLib/views/RhoTabHeader.xaml +3 -3
- data/platform/wp7/RhoRubyLib/views/RhoView.xaml.cs +48 -8
- data/rakefile.rb +13 -2
- data/res/build-tools/iphonesim/build/Release/iphonesim_43 +0 -0
- data/res/build-tools/iphonesim/iphonesim.xcodeproj/project.pbxproj +158 -0
- data/res/generators/rhogen.rb +33 -28
- data/res/generators/templates/application/app/layout.erb +6 -5
- data/res/generators/templates/application/public/css/android.css +21 -315
- data/res/generators/templates/application/public/css/iphone.css +1 -499
- data/res/generators/templates/application/public/css/jqmobile-patch.css +18 -5
- data/res/generators/templates/application/public/css/windows_phone7.css +378 -0
- data/res/generators/templates/application/public/jqmobile/images/icons-18-black.png +0 -0
- data/res/generators/templates/application/public/jqmobile/images/icons-36-black.png +0 -0
- data/res/generators/templates/application/public/jqmobile/{jquery.mobile-1.0.css → jquery.mobile-1.0.1.css} +33 -11
- data/res/generators/templates/application/public/jqmobile/{jquery.mobile-1.0.js → jquery.mobile-1.0.1.js} +249 -125
- data/res/generators/templates/application/public/jqmobile/jquery.mobile-1.0.1.min.css +2 -0
- data/res/generators/templates/application/public/jqmobile/jquery.mobile-1.0.1.min.js +177 -0
- data/res/generators/templates/application/public/jqmobile/{jquery.mobile.structure-1.0.css → jquery.mobile.structure-1.0.1.css} +33 -11
- data/res/generators/templates/application/public/jqmobile/jquery.mobile.structure-1.0.1.min.css +2 -0
- data/res/generators/templates/application/public/jquery/jquery.json-2.3.js +193 -0
- data/res/generators/templates/application/public/jquery/jquery.json-2.3.min.js +23 -0
- data/res/generators/templates/application/public/js/jquery-wp7-patch.js +68 -20
- data/spec/phone_spec/app/Case/case.rb +22 -0
- data/spec/phone_spec/app/Customer/customer.rb +16 -0
- data/spec/phone_spec/app/spec/rhom_object_spec.rb +108 -11
- data/spec/phone_spec/app/spec/syncengine_spec.rb +43 -1
- data/spec/phone_spec/build.yml +2 -1
- data/version +1 -1
- metadata +27 -13
- data/platform/shared/common/ExtManager.cpp +0 -103
- data/res/generators/templates/application/public/jqmobile/jquery-mobile-iphone.css +0 -9
- data/res/generators/templates/application/public/jqmobile/jquery.mobile-1.0.min.css +0 -2
- data/res/generators/templates/application/public/jqmobile/jquery.mobile-1.0.min.js +0 -172
- data/res/generators/templates/application/public/jqmobile/jquery.mobile.structure-1.0.min.css +0 -2
@@ -1741,7 +1741,11 @@ namespace "run" do
|
|
1741
1741
|
io.each do |line|
|
1742
1742
|
#puts line
|
1743
1743
|
|
1744
|
-
|
1744
|
+
if line.class.method_defined? "valid_encoding?"
|
1745
|
+
end_spec = !Jake.process_spec_output(line) if line.valid_encoding?
|
1746
|
+
else
|
1747
|
+
end_spec = !Jake.process_spec_output(line)
|
1748
|
+
end
|
1745
1749
|
break if end_spec
|
1746
1750
|
end
|
1747
1751
|
|
@@ -349,4 +349,25 @@ public class RhodesApp
|
|
349
349
|
return false;
|
350
350
|
}
|
351
351
|
return true;
|
352
|
-
}
|
352
|
+
}
|
353
|
+
|
354
|
+
public void callSignatureCallback( String strCallbackUrl, String strSignaturePath, String strError, boolean bCancel ) throws Exception
|
355
|
+
{
|
356
|
+
strCallbackUrl = canonicalizeRhoUrl(strCallbackUrl);
|
357
|
+
String strBody;
|
358
|
+
if ( bCancel || strError.length() > 0 )
|
359
|
+
{
|
360
|
+
if ( bCancel )
|
361
|
+
strBody = "status=cancel&message=User canceled operation.";
|
362
|
+
else
|
363
|
+
strBody = "status=error&message=" + strError;
|
364
|
+
}else
|
365
|
+
strBody = "status=ok&signature_uri=db%2Fdb-files%2F" + strSignaturePath;
|
366
|
+
|
367
|
+
strBody += "&rho_callback=1";
|
368
|
+
|
369
|
+
IRhoRubyHelper helper = RhoClassFactory.createRhoRubyHelper();
|
370
|
+
helper.postUrlNoWait(strCallbackUrl,strBody);
|
371
|
+
}
|
372
|
+
}
|
373
|
+
|
@@ -950,6 +950,14 @@ public class SyncSource
|
|
950
950
|
for( ; !attrIter.isEnd(); attrIter.next() )
|
951
951
|
{
|
952
952
|
CAttrValue oAttrValue = new CAttrValue(attrIter.getCurKey(),attrIter.getCurString());
|
953
|
+
|
954
|
+
String strFreezedProps = getSync().getSourceOptions().getProperty(getID(), "freezed");
|
955
|
+
if ( strFreezedProps.length() > 0 && strFreezedProps.indexOf(oAttrValue.m_strAttrib) < 0 )
|
956
|
+
{
|
957
|
+
LOG.INFO("Skip Non-exist property : " + oAttrValue.m_strAttrib + ". For model : " + getName());
|
958
|
+
continue;
|
959
|
+
}
|
960
|
+
|
953
961
|
if ( !processBlob(strCmd,strObject,oAttrValue) )
|
954
962
|
break;
|
955
963
|
|
@@ -1139,6 +1147,13 @@ public class SyncSource
|
|
1139
1147
|
|
1140
1148
|
if ( strCmd.compareTo("insert") == 0 )
|
1141
1149
|
{
|
1150
|
+
String strFreezedProps = getSync().getSourceOptions().getProperty(getID(), "freezed");
|
1151
|
+
if ( strFreezedProps.length() > 0 && strFreezedProps.indexOf(oAttrValue.m_strAttrib) < 0 )
|
1152
|
+
{
|
1153
|
+
LOG.INFO("Skip Non-exist property : " + oAttrValue.m_strAttrib + ". For model : " + getName());
|
1154
|
+
return;
|
1155
|
+
}
|
1156
|
+
|
1142
1157
|
if ( !processBlob(strCmd,strObject,oAttrValue) )
|
1143
1158
|
return;
|
1144
1159
|
|
@@ -29,6 +29,10 @@ public class RhoSupport {
|
|
29
29
|
protected RubyValue run(RubyValue receiver, RubyBlock block ){
|
30
30
|
return RhoGetCurrentDir(receiver);}
|
31
31
|
});
|
32
|
+
RubyRuntime.KernelModule.defineModuleMethod( "__rhoGetRuntimeDir", new RubyNoArgMethod(){
|
33
|
+
protected RubyValue run(RubyValue receiver, RubyBlock block ){
|
34
|
+
return RhoGetCurrentDir(receiver);}
|
35
|
+
});
|
32
36
|
RubyRuntime.KernelModule.defineModuleMethod( "__load_with_reflection__", new RubyOneArgMethod(){
|
33
37
|
protected RubyValue run(RubyValue receiver, RubyValue arg, RubyBlock block ){
|
34
38
|
return loadWithReflection(receiver, arg, block);}
|
@@ -102,7 +102,7 @@ public class RubyRuntime
|
|
102
102
|
public static RubyModule JSONClass;
|
103
103
|
public static RubyClass CameraClass;
|
104
104
|
public static RubyClass RhoBluetoothClass;
|
105
|
-
public static
|
105
|
+
public static RubyModule WebViewClass;
|
106
106
|
public static RubyClass RhoConfClass;
|
107
107
|
public static RubyClass AlertClass;
|
108
108
|
public static RubyClass DateTimePickerClass;
|
@@ -115,6 +115,7 @@ public class RubyRuntime
|
|
115
115
|
public static RubyClass TopSelfClass;
|
116
116
|
public static RubyModule MapViewClass;
|
117
117
|
public static RubyClass XMLParserClass;
|
118
|
+
public static RubyModule SignatureCaptureClass;
|
118
119
|
//RHO
|
119
120
|
|
120
121
|
public static /*final*/ RubyValue TOP_LEVEL_SELF_VALUE;
|
@@ -315,7 +316,7 @@ public class RubyRuntime
|
|
315
316
|
JSONClass = rhoModule.defineModule("JSON" );//, RubyRuntime.ObjectClass);
|
316
317
|
CameraClass = RubyAPI.defineClass("Camera", RubyRuntime.ObjectClass);
|
317
318
|
RhoBluetoothClass = RubyAPI.defineClass("RhoBluetooth", RubyRuntime.ObjectClass);
|
318
|
-
WebViewClass = RubyAPI.
|
319
|
+
WebViewClass = RubyAPI.defineModule("WebView" );//, RubyRuntime.ObjectClass);
|
319
320
|
RhoConfClass = RubyAPI.defineClass("RhoConf", RubyRuntime.ObjectClass);
|
320
321
|
AlertClass = RubyAPI.defineClass("Alert", RubyRuntime.ObjectClass);
|
321
322
|
DateTimePickerClass = RubyAPI.defineClass("DateTimePicker", RubyRuntime.ObjectClass);
|
@@ -332,6 +333,7 @@ public class RubyRuntime
|
|
332
333
|
RubyModule rexmlModule = RubyAPI.defineModule("REXML");
|
333
334
|
RubyModule parsersModule = rexmlModule.defineModule("Parsers");
|
334
335
|
XMLParserClass = parsersModule.defineClass("BaseParser", RubyRuntime.ObjectClass);
|
336
|
+
SignatureCaptureClass = rhoModule.defineModule("SignatureCapture");
|
335
337
|
|
336
338
|
// RhoPhonebook.initMethods(PhonebookClass);
|
337
339
|
|
@@ -6,6 +6,8 @@ platform/bb/rhodes/src/com/rho/rubyext/XMLParser.java
|
|
6
6
|
platform/bb/rhodes/src/com/rho/rubyext/Alert.java
|
7
7
|
platform/bb/rhodes/src/com/rho/rubyext/RhoPhonebook.java
|
8
8
|
platform/bb/rhodes/src/com/rho/rubyext/RhoCalendar.java
|
9
|
+
platform/bb/rhodes/src/com/rho/rubyext/SignatureCapture.java
|
10
|
+
platform/bb/rhodes/src/com/rho/rubyext/PNGEncoder.java
|
9
11
|
platform/bb/rhodes/src/com/rho/net/BaseSocket.java
|
10
12
|
platform/bb/rhodes/src/com/rho/net/bb/BBHttpConnection.java
|
11
13
|
platform/bb/rhodes/src/com/rho/net/bb/NativeBBHttpConnection.java
|
@@ -88,7 +88,7 @@ public class RhoRubyHelper implements IRhoRubyHelper
|
|
88
88
|
GeoLocation.initMethods(RubyRuntime.GeoLocationClass);
|
89
89
|
com.rho.rubyext.System.initMethods(RubyRuntime.SystemClass);
|
90
90
|
com.rho.rubyext.XMLParser.initMethods(RubyRuntime.XMLParserClass);
|
91
|
-
|
91
|
+
com.rho.rubyext.SignatureCapture.initMethods(RubyRuntime.SignatureCaptureClass);
|
92
92
|
}
|
93
93
|
|
94
94
|
public RubyProgram createMainObject() throws Exception
|
@@ -0,0 +1,613 @@
|
|
1
|
+
package com.rho.rubyext;
|
2
|
+
|
3
|
+
import java.io.ByteArrayOutputStream;
|
4
|
+
import java.io.IOException;
|
5
|
+
|
6
|
+
import net.rim.device.api.compress.ZLibOutputStream;
|
7
|
+
import net.rim.device.api.system.Bitmap;
|
8
|
+
import net.rim.device.api.util.CRC32;
|
9
|
+
|
10
|
+
/**
|
11
|
+
* PNGEncoder takes a Java Image object and creates a byte string which can be saved as a PNG file.
|
12
|
+
* The Image is presumed to use the DirectColorModel.
|
13
|
+
*
|
14
|
+
* <p>Thanks to Jay Denny at KeyPoint Software
|
15
|
+
* http://www.keypoint.com/
|
16
|
+
* who let me develop this code on company time.</p>
|
17
|
+
*
|
18
|
+
* <p>You may contact me with (probably very-much-needed) improvements,
|
19
|
+
* comments, and bug fixes at:</p>
|
20
|
+
*
|
21
|
+
* <p><code>david@catcode.com</code></p>
|
22
|
+
*
|
23
|
+
* <p>This library is free software; you can redistribute it and/or
|
24
|
+
* modify it under the terms of the GNU Lesser General Public
|
25
|
+
* License as published by the Free Software Foundation; either
|
26
|
+
* version 2.1 of the License, or (at your option) any later version.</p>
|
27
|
+
*
|
28
|
+
* <p>This library is distributed in the hope that it will be useful,
|
29
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
30
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
31
|
+
* Lesser General Public License for more details.</p>
|
32
|
+
*
|
33
|
+
* <p>You should have received a copy of the GNU Lesser General Public
|
34
|
+
* License along with this library; if not, write to the Free Software
|
35
|
+
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
36
|
+
* A copy of the GNU LGPL may be found at
|
37
|
+
* <code>http://www.gnu.org/copyleft/lesser.html</code></p>
|
38
|
+
*
|
39
|
+
* @author J. David Eisenberg
|
40
|
+
* @version 1.5, 19 Oct 2003
|
41
|
+
*
|
42
|
+
* CHANGES:
|
43
|
+
* --------
|
44
|
+
* 19-Nov-2002 : CODING STYLE CHANGES ONLY (by David Gilbert for Object Refinery Limited);
|
45
|
+
* 19-Sep-2003 : Fix for platforms using EBCDIC (contributed by Paulo Soares);
|
46
|
+
* 19-Oct-2003 : Change private fields to protected fields so that
|
47
|
+
* PNGEncoderB can inherit them (JDE)
|
48
|
+
* Fixed bug with calculation of nRows
|
49
|
+
* 08-Apr-2008 : Ported to BlackBerry (by Richard Puckett II)
|
50
|
+
*/
|
51
|
+
|
52
|
+
public class PNGEncoder {
|
53
|
+
|
54
|
+
/** Constant specifying that alpha channel should be encoded. */
|
55
|
+
public static final boolean ENCODE_ALPHA = true;
|
56
|
+
|
57
|
+
/** Constant specifying that alpha channel should not be encoded. */
|
58
|
+
public static final boolean NO_ALPHA = false;
|
59
|
+
|
60
|
+
/** Constants for filter (NONE) */
|
61
|
+
public static final int FILTER_NONE = 0;
|
62
|
+
|
63
|
+
/** Constants for filter (SUB) */
|
64
|
+
public static final int FILTER_SUB = 1;
|
65
|
+
|
66
|
+
/** Constants for filter (UP) */
|
67
|
+
public static final int FILTER_UP = 2;
|
68
|
+
|
69
|
+
/** Constants for filter (LAST) */
|
70
|
+
public static final int FILTER_LAST = 2;
|
71
|
+
|
72
|
+
/** IHDR tag. */
|
73
|
+
protected static final byte IHDR[] = {73, 72, 68, 82};
|
74
|
+
|
75
|
+
/** IDAT tag. */
|
76
|
+
protected static final byte IDAT[] = {73, 68, 65, 84};
|
77
|
+
|
78
|
+
/** IEND tag. */
|
79
|
+
protected static final byte IEND[] = {73, 69, 78, 68};
|
80
|
+
|
81
|
+
/** The png bytes. */
|
82
|
+
protected byte[] pngBytes;
|
83
|
+
|
84
|
+
/** The prior row. */
|
85
|
+
protected byte[] priorRow;
|
86
|
+
|
87
|
+
/** The left bytes. */
|
88
|
+
protected byte[] leftBytes;
|
89
|
+
|
90
|
+
/** The image. */
|
91
|
+
protected Bitmap image;
|
92
|
+
|
93
|
+
/** The width. */
|
94
|
+
protected int width, height;
|
95
|
+
|
96
|
+
/** The byte position. */
|
97
|
+
protected int bytePos, maxPos;
|
98
|
+
|
99
|
+
/** The CRC value. */
|
100
|
+
protected int crcValue;
|
101
|
+
|
102
|
+
/** Encode alpha? */
|
103
|
+
protected boolean encodeAlpha;
|
104
|
+
|
105
|
+
/** The filter type. */
|
106
|
+
protected int filter;
|
107
|
+
|
108
|
+
/** The bytes-per-pixel. */
|
109
|
+
protected int bytesPerPixel;
|
110
|
+
|
111
|
+
/** The compression level. */
|
112
|
+
protected int compressionLevel;
|
113
|
+
|
114
|
+
/**
|
115
|
+
* Class constructor
|
116
|
+
*/
|
117
|
+
public PNGEncoder() {
|
118
|
+
this(null, false, FILTER_NONE, 0);
|
119
|
+
}
|
120
|
+
|
121
|
+
/**
|
122
|
+
* Class constructor specifying Image to encode, with no alpha channel encoding.
|
123
|
+
*
|
124
|
+
* @param image A Java Image object which uses the DirectColorModel
|
125
|
+
*/
|
126
|
+
public PNGEncoder(Bitmap image) {
|
127
|
+
this(image, false, FILTER_NONE, 0);
|
128
|
+
}
|
129
|
+
|
130
|
+
/**
|
131
|
+
* Class constructor specifying Image to encode, and whether to encode alpha.
|
132
|
+
*
|
133
|
+
* @param image A Java Image object which uses the DirectColorModel
|
134
|
+
* @param encodeAlpha Encode the alpha channel? false=no; true=yes
|
135
|
+
*/
|
136
|
+
public PNGEncoder(Bitmap image, boolean encodeAlpha) {
|
137
|
+
this(image, encodeAlpha, FILTER_NONE, 0);
|
138
|
+
}
|
139
|
+
|
140
|
+
/**
|
141
|
+
* Class constructor specifying Image to encode, whether to encode alpha, and filter to use.
|
142
|
+
*
|
143
|
+
* @param image A Java Image object which uses the DirectColorModel
|
144
|
+
* @param encodeAlpha Encode the alpha channel? false=no; true=yes
|
145
|
+
* @param whichFilter 0=none, 1=sub, 2=up
|
146
|
+
*/
|
147
|
+
public PNGEncoder(Bitmap image, boolean encodeAlpha, int whichFilter) {
|
148
|
+
this(image, encodeAlpha, whichFilter, 0);
|
149
|
+
}
|
150
|
+
|
151
|
+
|
152
|
+
/**
|
153
|
+
* Class constructor specifying Image source to encode, whether to encode alpha, filter to use,
|
154
|
+
* and compression level.
|
155
|
+
*
|
156
|
+
* @param image A Java Image object
|
157
|
+
* @param encodeAlpha Encode the alpha channel? false=no; true=yes
|
158
|
+
* @param whichFilter 0=none, 1=sub, 2=up
|
159
|
+
* @param compLevel 0..9
|
160
|
+
*/
|
161
|
+
public PNGEncoder(Bitmap image, boolean encodeAlpha, int whichFilter, int compLevel) {
|
162
|
+
this.image = image;
|
163
|
+
this.encodeAlpha = encodeAlpha;
|
164
|
+
setFilter(whichFilter);
|
165
|
+
if (compLevel >= 0 && compLevel <= 9) {
|
166
|
+
this.compressionLevel = compLevel;
|
167
|
+
}
|
168
|
+
}
|
169
|
+
|
170
|
+
/**
|
171
|
+
* Set the image to be encoded
|
172
|
+
*
|
173
|
+
* @param image A Java Image object which uses the DirectColorModel
|
174
|
+
*/
|
175
|
+
public void setImage(Bitmap image) {
|
176
|
+
this.image = image;
|
177
|
+
pngBytes = null;
|
178
|
+
}
|
179
|
+
|
180
|
+
/**
|
181
|
+
* Creates an array of bytes that is the PNG equivalent of the current image, specifying
|
182
|
+
* whether to encode alpha or not.
|
183
|
+
*
|
184
|
+
* @param encodeAlpha boolean false=no alpha, true=encode alpha
|
185
|
+
* @return an array of bytes, or null if there was a problem
|
186
|
+
*/
|
187
|
+
public byte[] encode(boolean encodeAlpha) throws IOException {
|
188
|
+
byte[] pngIdBytes = {-119, 80, 78, 71, 13, 10, 26, 10};
|
189
|
+
|
190
|
+
if (image == null) {
|
191
|
+
return null;
|
192
|
+
}
|
193
|
+
width = image.getWidth();
|
194
|
+
height = image.getHeight();
|
195
|
+
|
196
|
+
/*
|
197
|
+
* start with an array that is big enough to hold all the pixels
|
198
|
+
* (plus filter bytes), and an extra 200 bytes for header info
|
199
|
+
*/
|
200
|
+
pngBytes = new byte[((width + 1) * height * 3) + 200];
|
201
|
+
|
202
|
+
/*
|
203
|
+
* keep track of largest byte written to the array
|
204
|
+
*/
|
205
|
+
maxPos = 0;
|
206
|
+
|
207
|
+
bytePos = writeBytes(pngIdBytes, 0);
|
208
|
+
|
209
|
+
writeHeader();
|
210
|
+
|
211
|
+
if (writeImageData()) {
|
212
|
+
writeEnd();
|
213
|
+
pngBytes = resizeByteArray(pngBytes, maxPos);
|
214
|
+
}
|
215
|
+
else {
|
216
|
+
pngBytes = null;
|
217
|
+
}
|
218
|
+
return pngBytes;
|
219
|
+
}
|
220
|
+
|
221
|
+
/**
|
222
|
+
* Creates an array of bytes that is the PNG equivalent of the current image.
|
223
|
+
* Alpha encoding is determined by its setting in the constructor.
|
224
|
+
*
|
225
|
+
* @return an array of bytes, or null if there was a problem
|
226
|
+
*/
|
227
|
+
public byte[] encode() throws IOException {
|
228
|
+
return encode(encodeAlpha);
|
229
|
+
}
|
230
|
+
|
231
|
+
/**
|
232
|
+
* Set the alpha encoding on or off.
|
233
|
+
*
|
234
|
+
* @param encodeAlpha false=no, true=yes
|
235
|
+
*/
|
236
|
+
public void setEncodeAlpha(boolean encodeAlpha) {
|
237
|
+
this.encodeAlpha = encodeAlpha;
|
238
|
+
}
|
239
|
+
|
240
|
+
/**
|
241
|
+
* Retrieve alpha encoding status.
|
242
|
+
*
|
243
|
+
* @return boolean false=no, true=yes
|
244
|
+
*/
|
245
|
+
public boolean getEncodeAlpha() {
|
246
|
+
return encodeAlpha;
|
247
|
+
}
|
248
|
+
|
249
|
+
/**
|
250
|
+
* Set the filter to use
|
251
|
+
*
|
252
|
+
* @param whichFilter from constant list
|
253
|
+
*/
|
254
|
+
public void setFilter(int whichFilter) {
|
255
|
+
this.filter = FILTER_NONE;
|
256
|
+
if (whichFilter <= FILTER_LAST) {
|
257
|
+
this.filter = whichFilter;
|
258
|
+
}
|
259
|
+
}
|
260
|
+
|
261
|
+
/**
|
262
|
+
* Retrieve filtering scheme
|
263
|
+
*
|
264
|
+
* @return int (see constant list)
|
265
|
+
*/
|
266
|
+
public int getFilter() {
|
267
|
+
return filter;
|
268
|
+
}
|
269
|
+
|
270
|
+
/**
|
271
|
+
* Set the compression level to use
|
272
|
+
*
|
273
|
+
* @param level 0 through 9
|
274
|
+
*/
|
275
|
+
public void setCompressionLevel(int level) {
|
276
|
+
if (level >= 0 && level <= 9) {
|
277
|
+
this.compressionLevel = level;
|
278
|
+
}
|
279
|
+
}
|
280
|
+
|
281
|
+
/**
|
282
|
+
* Retrieve compression level
|
283
|
+
*
|
284
|
+
* @return int in range 0-9
|
285
|
+
*/
|
286
|
+
public int getCompressionLevel() {
|
287
|
+
return compressionLevel;
|
288
|
+
}
|
289
|
+
|
290
|
+
/**
|
291
|
+
* Increase or decrease the length of a byte array.
|
292
|
+
*
|
293
|
+
* @param array The original array.
|
294
|
+
* @param newLength The length you wish the new array to have.
|
295
|
+
* @return Array of newly desired length. If shorter than the
|
296
|
+
* original, the trailing elements are truncated.
|
297
|
+
*/
|
298
|
+
protected byte[] resizeByteArray(byte[] array, int newLength) {
|
299
|
+
byte[] newArray = new byte[newLength];
|
300
|
+
int oldLength = array.length;
|
301
|
+
|
302
|
+
java.lang.System.arraycopy(array, 0, newArray, 0, Math.min(oldLength, newLength));
|
303
|
+
return newArray;
|
304
|
+
}
|
305
|
+
|
306
|
+
/**
|
307
|
+
* Write an array of bytes into the pngBytes array.
|
308
|
+
* Note: This routine has the side effect of updating
|
309
|
+
* maxPos, the largest element written in the array.
|
310
|
+
* The array is resized by 1000 bytes or the length
|
311
|
+
* of the data to be written, whichever is larger.
|
312
|
+
*
|
313
|
+
* @param data The data to be written into pngBytes.
|
314
|
+
* @param offset The starting point to write to.
|
315
|
+
* @return The next place to be written to in the pngBytes array.
|
316
|
+
*/
|
317
|
+
protected int writeBytes(byte[] data, int offset) {
|
318
|
+
maxPos = Math.max(maxPos, offset + data.length);
|
319
|
+
if (data.length + offset > pngBytes.length) {
|
320
|
+
pngBytes = resizeByteArray(pngBytes, pngBytes.length + Math.max(1000, data.length));
|
321
|
+
}
|
322
|
+
java.lang.System.arraycopy(data, 0, pngBytes, offset, data.length);
|
323
|
+
return offset + data.length;
|
324
|
+
}
|
325
|
+
|
326
|
+
/**
|
327
|
+
* Write an array of bytes into the pngBytes array, specifying number of bytes to write.
|
328
|
+
* Note: This routine has the side effect of updating
|
329
|
+
* maxPos, the largest element written in the array.
|
330
|
+
* The array is resized by 1000 bytes or the length
|
331
|
+
* of the data to be written, whichever is larger.
|
332
|
+
*
|
333
|
+
* @param data The data to be written into pngBytes.
|
334
|
+
* @param nBytes The number of bytes to be written.
|
335
|
+
* @param offset The starting point to write to.
|
336
|
+
* @return The next place to be written to in the pngBytes array.
|
337
|
+
*/
|
338
|
+
protected int writeBytes(byte[] data, int nBytes, int offset) {
|
339
|
+
maxPos = Math.max(maxPos, offset + nBytes);
|
340
|
+
if (nBytes + offset > pngBytes.length) {
|
341
|
+
pngBytes = resizeByteArray(pngBytes, pngBytes.length + Math.max(1000, nBytes));
|
342
|
+
}
|
343
|
+
java.lang.System.arraycopy(data, 0, pngBytes, offset, nBytes);
|
344
|
+
return offset + nBytes;
|
345
|
+
}
|
346
|
+
|
347
|
+
/**
|
348
|
+
* Write a two-byte integer into the pngBytes array at a given position.
|
349
|
+
*
|
350
|
+
* @param n The integer to be written into pngBytes.
|
351
|
+
* @param offset The starting point to write to.
|
352
|
+
* @return The next place to be written to in the pngBytes array.
|
353
|
+
*/
|
354
|
+
protected int writeInt2(int n, int offset) {
|
355
|
+
byte[] temp = {(byte) ((n >> 8) & 0xff), (byte) (n & 0xff)};
|
356
|
+
return writeBytes(temp, offset);
|
357
|
+
}
|
358
|
+
|
359
|
+
/**
|
360
|
+
* Write a four-byte integer into the pngBytes array at a given position.
|
361
|
+
*
|
362
|
+
* @param n The integer to be written into pngBytes.
|
363
|
+
* @param offset The starting point to write to.
|
364
|
+
* @return The next place to be written to in the pngBytes array.
|
365
|
+
*/
|
366
|
+
protected int writeInt4(int n, int offset) {
|
367
|
+
byte[] temp = {(byte) ((n >> 24) & 0xff),
|
368
|
+
(byte) ((n >> 16) & 0xff),
|
369
|
+
(byte) ((n >> 8) & 0xff),
|
370
|
+
(byte) (n & 0xff)};
|
371
|
+
return writeBytes(temp, offset);
|
372
|
+
}
|
373
|
+
|
374
|
+
/**
|
375
|
+
* Write a single byte into the pngBytes array at a given position.
|
376
|
+
*
|
377
|
+
* @param b The integer to be written into pngBytes.
|
378
|
+
* @param offset The starting point to write to.
|
379
|
+
* @return The next place to be written to in the pngBytes array.
|
380
|
+
*/
|
381
|
+
protected int writeByte(int b, int offset) {
|
382
|
+
byte[] temp = {(byte) b};
|
383
|
+
return writeBytes(temp, offset);
|
384
|
+
}
|
385
|
+
|
386
|
+
/**
|
387
|
+
* Write a PNG "IHDR" chunk into the pngBytes array.
|
388
|
+
*/
|
389
|
+
protected void writeHeader() {
|
390
|
+
int startPos;
|
391
|
+
|
392
|
+
startPos = bytePos = writeInt4(13, bytePos);
|
393
|
+
bytePos = writeBytes(IHDR, bytePos);
|
394
|
+
width = image.getWidth();
|
395
|
+
height = image.getHeight();
|
396
|
+
bytePos = writeInt4(width, bytePos);
|
397
|
+
bytePos = writeInt4(height, bytePos);
|
398
|
+
bytePos = writeByte(8, bytePos); // bit depth
|
399
|
+
bytePos = writeByte((encodeAlpha) ? 6 : 2, bytePos); // direct model
|
400
|
+
bytePos = writeByte(0, bytePos); // compression method
|
401
|
+
bytePos = writeByte(0, bytePos); // filter method
|
402
|
+
bytePos = writeByte(0, bytePos); // no interlace
|
403
|
+
crcValue = CRC32.update(CRC32.INITIAL_VALUE, pngBytes, startPos, bytePos - startPos);
|
404
|
+
bytePos = writeInt4(crcValue, bytePos);
|
405
|
+
}
|
406
|
+
|
407
|
+
/**
|
408
|
+
* Perform "sub" filtering on the given row.
|
409
|
+
* Uses temporary array leftBytes to store the original values
|
410
|
+
* of the previous pixels. The array is 16 bytes long, which
|
411
|
+
* will easily hold two-byte samples plus two-byte alpha.
|
412
|
+
*
|
413
|
+
* @param pixels The array holding the scan lines being built
|
414
|
+
* @param startPos Starting position within pixels of bytes to be filtered.
|
415
|
+
* @param width Width of a scanline in pixels.
|
416
|
+
*/
|
417
|
+
protected void filterSub(byte[] pixels, int startPos, int width) {
|
418
|
+
int i;
|
419
|
+
int offset = bytesPerPixel;
|
420
|
+
int actualStart = startPos + offset;
|
421
|
+
int nBytes = width * bytesPerPixel;
|
422
|
+
int leftInsert = offset;
|
423
|
+
int leftExtract = 0;
|
424
|
+
|
425
|
+
for (i = actualStart; i < startPos + nBytes; i++) {
|
426
|
+
leftBytes[leftInsert] = pixels[i];
|
427
|
+
pixels[i] = (byte) ((pixels[i] - leftBytes[leftExtract]) % 256);
|
428
|
+
leftInsert = (leftInsert + 1) % 0x0f;
|
429
|
+
leftExtract = (leftExtract + 1) % 0x0f;
|
430
|
+
}
|
431
|
+
}
|
432
|
+
|
433
|
+
/**
|
434
|
+
* Perform "up" filtering on the given row.
|
435
|
+
* Side effect: refills the prior row with current row
|
436
|
+
*
|
437
|
+
* @param pixels The array holding the scan lines being built
|
438
|
+
* @param startPos Starting position within pixels of bytes to be filtered.
|
439
|
+
* @param width Width of a scanline in pixels.
|
440
|
+
*/
|
441
|
+
protected void filterUp(byte[] pixels, int startPos, int width) {
|
442
|
+
int i, nBytes;
|
443
|
+
byte currentByte;
|
444
|
+
|
445
|
+
nBytes = width * bytesPerPixel;
|
446
|
+
|
447
|
+
for (i = 0; i < nBytes; i++) {
|
448
|
+
currentByte = pixels[startPos + i];
|
449
|
+
pixels[startPos + i] = (byte) ((pixels[startPos + i] - priorRow[i]) % 256);
|
450
|
+
priorRow[i] = currentByte;
|
451
|
+
}
|
452
|
+
}
|
453
|
+
|
454
|
+
// protected int[] blur(int[] src, int width, int height) {
|
455
|
+
// int[] blurred = new int[width * height];
|
456
|
+
// int scanPos = 0; // where we are in the scan lines
|
457
|
+
//
|
458
|
+
// int boxw = 2;
|
459
|
+
// double mul = 1.0 / (double) (boxw * 2 + 1);
|
460
|
+
// System.out.println("mul = " + mul);
|
461
|
+
//
|
462
|
+
// for (int y = 0; y < height; y++) {
|
463
|
+
// int redChannel = 0;
|
464
|
+
// int greenChannel = 0;
|
465
|
+
// int blueChannel = 0;
|
466
|
+
//
|
467
|
+
// for (int x = 0; x < boxw; x++) {
|
468
|
+
// redChannel += (src[scanPos] >> 16) & 0xff;
|
469
|
+
// greenChannel += (src[scanPos] >> 8) & 0xff;
|
470
|
+
// blueChannel += src[scanPos] & 0xff;
|
471
|
+
// }
|
472
|
+
// System.out.println("Primed redChannel (" + scanPos + ") = " + redChannel);
|
473
|
+
// System.out.println("Primed greenChannel = " + greenChannel);
|
474
|
+
// System.out.println("Primed blueChannel = " + blueChannel);
|
475
|
+
//
|
476
|
+
// for (int x = 0; x < width; x++) {
|
477
|
+
// if (x > boxw) {
|
478
|
+
// redChannel -= (src[scanPos - boxw - 1] >> 16) & 0xff;
|
479
|
+
// greenChannel -= (src[scanPos - boxw - 1] >> 8) & 0xff;
|
480
|
+
// blueChannel -= src[scanPos - boxw - 1] & 0xff;
|
481
|
+
// }
|
482
|
+
//
|
483
|
+
// if (x + boxw < width) {
|
484
|
+
// redChannel += (src[scanPos + boxw] >> 16) & 0xff;
|
485
|
+
// greenChannel += (src[scanPos + boxw] >> 8) & 0xff;
|
486
|
+
// blueChannel += src[scanPos + boxw] & 0xff;
|
487
|
+
// }
|
488
|
+
//
|
489
|
+
// blurred[scanPos] |= (new Double(redChannel / (boxw + 1)).byteValue() << 16);
|
490
|
+
// blurred[scanPos] |= (new Double(greenChannel / (boxw + 1)).byteValue() << 8);
|
491
|
+
// blurred[scanPos] |= new Double(blueChannel / (boxw + 1)).byteValue();
|
492
|
+
//
|
493
|
+
// if (encodeAlpha) {
|
494
|
+
// blurred[scanPos] |= (src[scanPos] & 0xff000000);
|
495
|
+
// }
|
496
|
+
//
|
497
|
+
// scanPos++;
|
498
|
+
// }
|
499
|
+
// }
|
500
|
+
//
|
501
|
+
// return blurred;
|
502
|
+
// }
|
503
|
+
|
504
|
+
/**
|
505
|
+
* Write the image data into the pngBytes array.
|
506
|
+
* This will write one or more PNG "IDAT" chunks. In order
|
507
|
+
* to conserve memory, this method grabs as many rows as will
|
508
|
+
* fit into 32K bytes, or the whole image; whichever is less.
|
509
|
+
*
|
510
|
+
*
|
511
|
+
* @return true if no errors; false if error grabbing pixels
|
512
|
+
*/
|
513
|
+
protected boolean writeImageData() throws IOException {
|
514
|
+
int rowsLeft = height; // number of rows remaining to write
|
515
|
+
int startRow = 0; // starting row to process this time through
|
516
|
+
int nRows; // how many rows to grab at a time
|
517
|
+
|
518
|
+
byte[] scanLines; // the scan lines to be compressed
|
519
|
+
int scanPos; // where we are in the scan lines
|
520
|
+
int startPos; // where this line's actual pixels start (used for filtering)
|
521
|
+
|
522
|
+
byte[] compressedLines; // the resultant compressed lines
|
523
|
+
int nCompressed; // how big is the compressed area?
|
524
|
+
|
525
|
+
bytesPerPixel = (encodeAlpha) ? 4 : 3;
|
526
|
+
|
527
|
+
ByteArrayOutputStream outBytes = new ByteArrayOutputStream(1024);
|
528
|
+
|
529
|
+
ZLibOutputStream compBytes = new ZLibOutputStream(outBytes);
|
530
|
+
|
531
|
+
while (rowsLeft > 0) {
|
532
|
+
nRows = Math.min(32767 / (width * (bytesPerPixel + 1)), rowsLeft);
|
533
|
+
nRows = Math.max( nRows, 1 );
|
534
|
+
|
535
|
+
int[] pixels = new int[width * nRows];
|
536
|
+
|
537
|
+
image.getARGB(pixels, 0, width, 0, startRow, width, nRows);
|
538
|
+
|
539
|
+
/*
|
540
|
+
* Create a data chunk. scanLines adds "nRows" for
|
541
|
+
* the filter bytes.
|
542
|
+
*/
|
543
|
+
scanLines = new byte[width * nRows * bytesPerPixel + nRows];
|
544
|
+
|
545
|
+
if (filter == FILTER_SUB) {
|
546
|
+
leftBytes = new byte[16];
|
547
|
+
}
|
548
|
+
if (filter == FILTER_UP) {
|
549
|
+
priorRow = new byte[width * bytesPerPixel];
|
550
|
+
}
|
551
|
+
|
552
|
+
scanPos = 0;
|
553
|
+
startPos = 1;
|
554
|
+
for (int i = 0; i < width * nRows; i++) {
|
555
|
+
if (i % width == 0) {
|
556
|
+
scanLines[scanPos++] = (byte) filter;
|
557
|
+
startPos = scanPos;
|
558
|
+
}
|
559
|
+
scanLines[scanPos++] = (byte) ((pixels[i] >> 16) & 0xff);
|
560
|
+
scanLines[scanPos++] = (byte) ((pixels[i] >> 8) & 0xff);
|
561
|
+
scanLines[scanPos++] = (byte) ((pixels[i]) & 0xff);
|
562
|
+
if (encodeAlpha) {
|
563
|
+
scanLines[scanPos++] = (byte) ((pixels[i] >> 24) & 0xff);
|
564
|
+
}
|
565
|
+
if ((i % width == width - 1) && (filter != FILTER_NONE)) {
|
566
|
+
if (filter == FILTER_SUB) {
|
567
|
+
filterSub(scanLines, startPos, width);
|
568
|
+
}
|
569
|
+
if (filter == FILTER_UP) {
|
570
|
+
filterUp(scanLines, startPos, width);
|
571
|
+
}
|
572
|
+
}
|
573
|
+
}
|
574
|
+
|
575
|
+
/*
|
576
|
+
* Write these lines to the output area
|
577
|
+
*/
|
578
|
+
compBytes.write(scanLines, 0, scanPos);
|
579
|
+
|
580
|
+
startRow += nRows;
|
581
|
+
rowsLeft -= nRows;
|
582
|
+
}
|
583
|
+
compBytes.close();
|
584
|
+
|
585
|
+
/*
|
586
|
+
* Write the compressed bytes
|
587
|
+
*/
|
588
|
+
compressedLines = outBytes.toByteArray();
|
589
|
+
nCompressed = compressedLines.length;
|
590
|
+
|
591
|
+
bytePos = writeInt4(nCompressed, bytePos);
|
592
|
+
bytePos = writeBytes(IDAT, bytePos);
|
593
|
+
crcValue = CRC32.update(CRC32.INITIAL_VALUE, IDAT);
|
594
|
+
|
595
|
+
bytePos = writeBytes(compressedLines, nCompressed, bytePos);
|
596
|
+
crcValue = CRC32.update(crcValue, compressedLines, 0, nCompressed);
|
597
|
+
|
598
|
+
bytePos = writeInt4(crcValue, bytePos);
|
599
|
+
return true;
|
600
|
+
}
|
601
|
+
|
602
|
+
/**
|
603
|
+
* Write a PNG "IEND" chunk into the pngBytes array.
|
604
|
+
*/
|
605
|
+
protected void writeEnd() {
|
606
|
+
bytePos = writeInt4(0, bytePos);
|
607
|
+
bytePos = writeBytes(IEND, bytePos);
|
608
|
+
crcValue = CRC32.update(CRC32.INITIAL_VALUE, IEND);
|
609
|
+
|
610
|
+
bytePos = writeInt4(crcValue, bytePos);
|
611
|
+
}
|
612
|
+
|
613
|
+
}
|