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.
Files changed (146) hide show
  1. data/CHANGELOG +3 -0
  2. data/Manifest.txt +23 -9
  3. data/Rakefile +13 -2
  4. data/doc/build.txt +18 -11
  5. data/doc/device-caps.txt +4 -68
  6. data/doc/rhom.txt +33 -0
  7. data/doc/test-log-debug.txt +18 -42
  8. data/lib/framework/rho/render.rb +1 -1
  9. data/lib/framework/rho/rho.rb +31 -1
  10. data/lib/framework/rho/rhocontroller.rb +2 -2
  11. data/lib/framework/rhodes.rb +1 -1
  12. data/lib/framework/rhoframework.rb +4 -0
  13. data/lib/framework/rholang/localization_simplified.rb +1 -1
  14. data/lib/framework/rhom/rhom_object_factory.rb +22 -1
  15. data/lib/framework/version.rb +1 -1
  16. data/lib/rhodes.rb +1 -1
  17. data/platform/android/Rhodes/AndroidManifest.xml +2 -2
  18. data/platform/android/Rhodes/jni/include/rhodes/jni/com_rhomobile_rhodes_RhodesService.h +25 -9
  19. data/platform/android/Rhodes/jni/include/rhodes/jni/com_rhomobile_rhodes_extmanager_RhoExtManagerImpl.h +21 -0
  20. data/platform/android/Rhodes/jni/src/extmanager.cpp +36 -0
  21. data/platform/android/Rhodes/jni/src/nativeview.cpp +1 -1
  22. data/platform/android/Rhodes/jni/src/rhodesapp.cpp +14 -5
  23. data/platform/android/Rhodes/jni/src/rhodessystem.cpp +5 -0
  24. data/platform/android/Rhodes/jni/src/signature.cpp +29 -3
  25. data/platform/android/Rhodes/src/com/rhomobile/rhodes/NativeBar.java +3 -3
  26. data/platform/android/Rhodes/src/com/rhomobile/rhodes/RhodesActivity.java +4 -0
  27. data/platform/android/Rhodes/src/com/rhomobile/rhodes/RhodesService.java +42 -7
  28. data/platform/android/Rhodes/src/com/rhomobile/rhodes/WebView.java +61 -10
  29. data/platform/android/Rhodes/src/com/rhomobile/rhodes/extmanager/IRhoExtData.java +6 -0
  30. data/platform/android/Rhodes/src/com/rhomobile/rhodes/extmanager/IRhoExtManager.java +39 -0
  31. data/platform/android/Rhodes/src/com/rhomobile/rhodes/extmanager/IRhoExtension.java +18 -0
  32. data/platform/android/Rhodes/src/com/rhomobile/rhodes/extmanager/RhoExtDataImpl.java +18 -0
  33. data/platform/android/Rhodes/src/com/rhomobile/rhodes/extmanager/RhoExtManagerImpl.java +142 -0
  34. data/platform/android/Rhodes/src/com/rhomobile/rhodes/extmanager/RhoExtManagerSingleton.java +15 -0
  35. data/platform/android/Rhodes/src/com/rhomobile/rhodes/mainview/MainView.java +6 -3
  36. data/platform/android/Rhodes/src/com/rhomobile/rhodes/mainview/SimpleMainView.java +25 -13
  37. data/platform/android/Rhodes/src/com/rhomobile/rhodes/mainview/SplashScreen.java +15 -9
  38. data/platform/android/Rhodes/src/com/rhomobile/rhodes/mainview/TabbedMainView.java +15 -5
  39. data/platform/android/Rhodes/src/com/rhomobile/rhodes/nativeview/RhoNativeViewManager.java +3 -3
  40. data/platform/android/Rhodes/src/com/rhomobile/rhodes/signature/ImageCapture.java +14 -8
  41. data/platform/android/Rhodes/src/com/rhomobile/rhodes/signature/Signature.java +218 -51
  42. data/platform/android/Rhodes/src/com/rhomobile/rhodes/signature/SignatureProperties.java +94 -0
  43. data/platform/android/Rhodes/src/com/rhomobile/rhodes/signature/SignatureView.java +122 -37
  44. data/platform/android/Rhodes/src/com/rhomobile/rhodes/webview/GoogleWebView.java +6 -2
  45. data/platform/android/Rhodes/src/com/rhomobile/rhodes/webview/{WebView.java → IRhoWebView.java} +2 -1
  46. data/platform/android/Rhodes/src/com/rhomobile/rhodes/webview/RhoWebViewClient.java +4 -0
  47. data/platform/android/build/RhodesSRC_build.files +8 -1
  48. data/platform/android/build/android.rake +5 -1
  49. data/platform/android/build/librhodes_build.files +1 -0
  50. data/platform/bb/RubyVM/src/com/rho/RhodesApp.java +22 -1
  51. data/platform/bb/RubyVM/src/com/rho/sync/SyncSource.java +15 -0
  52. data/platform/bb/RubyVM/src/com/xruby/runtime/lang/RhoSupport.java +4 -0
  53. data/platform/bb/RubyVM/src/com/xruby/runtime/lang/RubyRuntime.java +4 -2
  54. data/platform/bb/build/rhodes_build.files +2 -0
  55. data/platform/bb/rhodes/src/com/rho/RhoRubyHelper.java +1 -1
  56. data/platform/bb/rhodes/src/com/rho/rubyext/PNGEncoder.java +613 -0
  57. data/platform/bb/rhodes/src/com/rho/rubyext/SignatureCapture.java +314 -0
  58. data/platform/bb/rhodes/src/com/rho/rubyext/WebView.java +1 -1
  59. data/platform/iphone/Classes/AppManager/AppManager.m +11 -0
  60. data/platform/iphone/Classes/Rhodes.m +1 -1
  61. data/platform/iphone/Classes/Signature/SignatureDelegate.h +5 -1
  62. data/platform/iphone/Classes/Signature/SignatureDelegate.m +186 -5
  63. data/platform/iphone/Classes/Signature/SignatureView.h +12 -0
  64. data/platform/iphone/Classes/Signature/SignatureView.m +11 -3
  65. data/platform/iphone/Classes/SimpleMainView.m +4 -0
  66. data/platform/iphone/Classes/rho/net/NetRequestImpl.m +98 -3
  67. data/platform/iphone/Info.plist +1 -1
  68. data/platform/iphone/rbuild/iphone.rake +18 -5
  69. data/platform/shared/RhoConnectClient/RhoConnectClient.cpp +1 -1
  70. data/platform/shared/common/ExtManager.h +64 -9
  71. data/platform/shared/common/RhoSimConf.h +1 -0
  72. data/platform/shared/common/RhodesApp.cpp +77 -28
  73. data/platform/shared/common/RhodesApp.h +9 -4
  74. data/platform/shared/common/RhodesAppBase.cpp +4 -3
  75. data/platform/shared/common/RhodesAppBase.h +5 -3
  76. data/platform/shared/net/HttpServer.cpp +4 -4
  77. data/platform/shared/net/HttpServer.h +2 -2
  78. data/platform/shared/qt/rhodes/impl/MainWindowImpl.cpp +1 -1
  79. data/platform/shared/qt/rhodes/main.cpp +1 -1
  80. data/platform/shared/ruby/ext/rho/rhoruby.c +12 -2
  81. data/platform/shared/ruby/ext/rho/rhosupport.c +11 -1
  82. data/platform/shared/ruby/thread_win32.c +2 -1
  83. data/platform/shared/rubyext/System.cpp +6 -0
  84. data/platform/shared/sync/SyncSource.cpp +15 -0
  85. data/platform/wm/RhoLib/RhoLib.vcproj +0 -4
  86. data/platform/wm/build/build_inf.js +34 -4
  87. data/platform/wm/build/wm.rake +75 -25
  88. data/platform/wm/rhodes/AppManager.cpp +14 -3
  89. data/platform/wm/rhodes/IBrowserEngine.h +7 -0
  90. data/platform/wm/rhodes/IEBrowserEngine.cpp +43 -0
  91. data/platform/wm/rhodes/IEBrowserEngine.h +7 -0
  92. data/platform/wm/rhodes/LogOptionsDlg.cpp +1 -1
  93. data/platform/wm/rhodes/MainWindow.cpp +92 -7
  94. data/platform/wm/rhodes/MainWindow.h +28 -1
  95. data/platform/wm/rhodes/MapView/MapViewManager.cpp +4 -4
  96. data/platform/wm/rhodes/Rhodes.cpp +149 -10
  97. data/platform/wm/rhodes/resource.h +5 -1
  98. data/platform/wm/rhodes/rho/common/ExtManager.cpp +307 -0
  99. data/platform/wm/rhodes/rho/rubyext/NativeToolbar.cpp +1 -1
  100. data/platform/wm/rhodes/rho/rubyext/RhoSignature.cpp +1 -1
  101. data/platform/wm/rhodes/rho/rubyext/RhoSignature.h +1 -1
  102. data/platform/wm/rhodes/rho/rubyext/SystemImpl.cpp +14 -2
  103. data/platform/wm/rhodes/rho/rubyext/WebView.cpp +6 -3
  104. data/platform/wm/rhodes/rhodes.vcproj +5 -1
  105. data/platform/wm/rhodes/simulator/MainWindowQt.cpp +22 -1
  106. data/platform/wm/rhodes/simulator/MainWindowQt.h +4 -0
  107. data/platform/wp7/RhoRubyExtGen/RhoWebView.cs +1 -1
  108. data/platform/wp7/RhoRubyLib/Initializers.Generated.cs +1 -1
  109. data/platform/wp7/RhoRubyLib/common/RhodesApp.cs +33 -38
  110. data/platform/wp7/RhoRubyLib/net/HttpServer.cs +134 -29
  111. data/platform/wp7/RhoRubyLib/rubyext/RhoWebView.cs +12 -2
  112. data/platform/wp7/RhoRubyLib/sync/SyncSource.cs +17 -1
  113. data/platform/wp7/RhoRubyLib/views/RhoTabHeader.xaml +3 -3
  114. data/platform/wp7/RhoRubyLib/views/RhoView.xaml.cs +48 -8
  115. data/rakefile.rb +13 -2
  116. data/res/build-tools/iphonesim/build/Release/iphonesim_43 +0 -0
  117. data/res/build-tools/iphonesim/iphonesim.xcodeproj/project.pbxproj +158 -0
  118. data/res/generators/rhogen.rb +33 -28
  119. data/res/generators/templates/application/app/layout.erb +6 -5
  120. data/res/generators/templates/application/public/css/android.css +21 -315
  121. data/res/generators/templates/application/public/css/iphone.css +1 -499
  122. data/res/generators/templates/application/public/css/jqmobile-patch.css +18 -5
  123. data/res/generators/templates/application/public/css/windows_phone7.css +378 -0
  124. data/res/generators/templates/application/public/jqmobile/images/icons-18-black.png +0 -0
  125. data/res/generators/templates/application/public/jqmobile/images/icons-36-black.png +0 -0
  126. data/res/generators/templates/application/public/jqmobile/{jquery.mobile-1.0.css → jquery.mobile-1.0.1.css} +33 -11
  127. data/res/generators/templates/application/public/jqmobile/{jquery.mobile-1.0.js → jquery.mobile-1.0.1.js} +249 -125
  128. data/res/generators/templates/application/public/jqmobile/jquery.mobile-1.0.1.min.css +2 -0
  129. data/res/generators/templates/application/public/jqmobile/jquery.mobile-1.0.1.min.js +177 -0
  130. data/res/generators/templates/application/public/jqmobile/{jquery.mobile.structure-1.0.css → jquery.mobile.structure-1.0.1.css} +33 -11
  131. data/res/generators/templates/application/public/jqmobile/jquery.mobile.structure-1.0.1.min.css +2 -0
  132. data/res/generators/templates/application/public/jquery/jquery.json-2.3.js +193 -0
  133. data/res/generators/templates/application/public/jquery/jquery.json-2.3.min.js +23 -0
  134. data/res/generators/templates/application/public/js/jquery-wp7-patch.js +68 -20
  135. data/spec/phone_spec/app/Case/case.rb +22 -0
  136. data/spec/phone_spec/app/Customer/customer.rb +16 -0
  137. data/spec/phone_spec/app/spec/rhom_object_spec.rb +108 -11
  138. data/spec/phone_spec/app/spec/syncengine_spec.rb +43 -1
  139. data/spec/phone_spec/build.yml +2 -1
  140. data/version +1 -1
  141. metadata +27 -13
  142. data/platform/shared/common/ExtManager.cpp +0 -103
  143. data/res/generators/templates/application/public/jqmobile/jquery-mobile-iphone.css +0 -9
  144. data/res/generators/templates/application/public/jqmobile/jquery.mobile-1.0.min.css +0 -2
  145. data/res/generators/templates/application/public/jqmobile/jquery.mobile-1.0.min.js +0 -172
  146. 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
- end_spec = !Jake.process_spec_output(line) if line.valid_encoding?
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
 
@@ -27,3 +27,4 @@ platform/android/Rhodes/jni/src/splashscreen.cpp
27
27
  platform/android/Rhodes/jni/src/sslimpl.cpp
28
28
  platform/android/Rhodes/jni/src/webview.cpp
29
29
  platform/android/Rhodes/jni/src/rhocryptimpl.cpp
30
+ platform/android/Rhodes/jni/src/extmanager.cpp
@@ -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 RubyClass WebViewClass;
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.defineClass("WebView", RubyRuntime.ObjectClass);
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
+ }