Revision: 20076
          http://sourceforge.net/p/jmol/code/20076
Author:   hansonr
Date:     2014-10-15 02:27:06 +0000 (Wed, 15 Oct 2014)
Log Message:
-----------
Jmol.___JmolVersion="14.3.8_2014.10.14"

new feature: transparent GIF using WRITE GIFT "xxx.gif"
new feature: GIF images use dithering to approximate full palette.
new feature: capture "file.gif" 10 transparent   -- but does not work

Modified Paths:
--------------
    trunk/Jmol/src/javajs/img/GifEncoder.java
    trunk/Jmol/src/org/jmol/script/T.java
    trunk/Jmol/src/org/jmol/scriptext/CmdExt.java
    trunk/Jmol/src/org/jmol/viewer/JC.java
    trunk/Jmol/src/org/jmol/viewer/Jmol.properties

Modified: trunk/Jmol/src/javajs/img/GifEncoder.java
===================================================================
--- trunk/Jmol/src/javajs/img/GifEncoder.java   2014-10-14 13:59:43 UTC (rev 
20075)
+++ trunk/Jmol/src/javajs/img/GifEncoder.java   2014-10-15 02:27:06 UTC (rev 
20076)
@@ -141,9 +141,10 @@
     AdaptiveColorCollection(int rgb, int index) {
       //this.rgb = rgb;
       this.index = index;
-      if (rgb >= 0)
+      if (rgb >= 0 || rgb == transparentColor)
         transparentIndex = index;
     }
+      
     void addRgb(int rgb, int count) {
       this.count += count;
       b += (rgb & 0xFF) * count;
@@ -166,6 +167,7 @@
   private boolean looping;
   private Map<String, Object> params;
   private int byteCount;
+  int transparentColor;
 
   /**
    * we allow for animated GIF by being able to re-enter
@@ -176,6 +178,9 @@
   @Override
   protected void setParams(Map<String, Object> params) {
     this.params = params;
+     Integer ic = (Integer) params.get("transparentColor");
+     if (ic != null)
+       transparentColor = ic.intValue();
     interlaced = (Boolean.TRUE == params.get("interlaced"));
     if (interlaced || !params.containsKey("captureMode"))
       return;
@@ -280,10 +285,8 @@
     ColorVector colorVector = new ColorVector();
     Map<Integer, ColorItem> ciHash = new Hashtable<Integer, ColorItem>();
     int nColors = 0;
-    Integer key;
     int ptTransparent = -1;
-    
-    for (int pt = 0, row = 0, transparentRgb = -1; row < height; ++row) {
+    out: for (int pt = 0, row = 0, transparentRgb = -1; row < height; ++row) {
       for (int col = 0; col < width; ++col, pt++) {
         int rgb = pixels[pt];
         boolean isTransparent = (rgb >= 0);
@@ -298,26 +301,107 @@
             pixels[pt] = rgb = transparentRgb;
           }
         }
-        ColorItem item = ciHash.get(key = Integer.valueOf(rgb));
-        if (item == null) {
-          item = new ColorItem(rgb, 1);
-          ciHash.put(key, item);
-          colorVector.addLast(item);
-          nColors++;
-        } else {
-          item.count++;
+        if ((nColors = addColor(colorVector, ciHash, rgb, nColors)) > 250) {
+          colorVector = ditherPixels();
+          break out;
         }
       }
     }
     ciHash = null;
-   
+    colorVector.sort();
     if (logging)
       System.out.println("# total image colors = " + nColors);
     // sort by frequency
-    colorVector.sort();
     return colorVector;
   }
 
+  private int addColor(ColorVector colorVector, Map<Integer, ColorItem> ciHash,
+                       int rgb, int nColors) {
+    Integer key = Integer.valueOf(rgb);
+    ColorItem item = ciHash.get(key);
+    if (item == null) {
+      item = new ColorItem(rgb, 1);
+      ciHash.put(key, item);
+      colorVector.addLast(item);
+      nColors++;
+    } else {
+      item.count++;
+    }
+    return nColors;
+  }
+
+  private ColorVector ditherPixels() {
+    ColorVector colorVector = new ColorVector();
+    Map<Integer, ColorItem> ciHash = new Hashtable<Integer, ColorItem>();
+    int nColors = 0;
+    int[] sb = toByteARGB(pixels);
+    int w4 = width * 4;
+    int r1 = 25;
+    int r2 = 2 * r1 + 1;
+    for (int i = 0; i < height; ++i) {
+      for (int j = 0; j < width; ++j) {
+        for (int k = 0; k < 3; k++) {
+          int ci = 4 * (i * width + j) + k + 1;
+          int cc = sb[ci];
+          int rc = Math.round((cc + r1) / r2) * r2;
+          int err = cc - rc;
+          sb[ci] = rc;
+          if (j + 1 < width)
+            sb[ci + 4] += (err * 7) >> 4;
+          if (i + 1 == height)
+            continue;
+          if (j > 0)
+            sb[ci + w4 - 4] += (err * 3) >> 4;
+          sb[ci + w4] += (err * 5) >> 4;
+          if (j + 1 < width)
+            sb[ci + w4 + 4] += (err * 1) >> 4;
+        }
+      }
+    }
+    pixels = toIntARGB(sb);
+    for (int i = 0, pt = 0; i < height; ++i) {
+      for (int j = 0; j < width; ++j, pt++) {
+        nColors = addColor(colorVector, ciHash, pixels[pt], nColors);
+      }
+    }
+    System.out.println("GIF dithered to " + nColors + " colors");
+    return colorVector;
+  }
+
+  static int[] toIntARGB(int[] imgData) {
+    /*
+     * red=imgData.data[0];
+     * green=imgData.data[1];
+     * blue=imgData.data[2];
+     * alpha=imgData.data[3];
+     */
+    int n = imgData.length / 4;
+    int[] iData = new int[n];
+    for (int i = 0, j = 0; i < n;) {
+      iData[i++] = (imgData[j++] << 24) | (imgData[j++] << 16) | imgData[j++] 
<< 8 | imgData[j++];
+    }
+    return iData;
+  }      
+  
+  static int[] toByteARGB(int[] argbs) {
+    /*
+     * red=imgData.data[0];
+     * green=imgData.data[1];
+     * blue=imgData.data[2];
+     * alpha=imgData.data[3];
+     */
+    int n = argbs.length * 4;
+    int[] iData = new int[n];
+    for (int i = 0, j = 0; i < n; j++) {
+      iData[i++] = (argbs[j] >> 24) & 0xFF;
+      iData[i++] = (argbs[j] >> 16) & 0xFF;
+      iData[i++] = (argbs[j] >> 8) & 0xFF;
+      iData[i++] = argbs[j] & 0xFF;      
+    }
+    return iData;
+  }      
+  
+
   /**
    * reduce GIF color collection to 256 or fewer by grouping shadings;
    * create an initial color hash that is only to the final colors.
@@ -352,7 +436,7 @@
     ColorItem item = colorVector.get(nMax);
     ht.put(Integer.valueOf(item.rgb),
         item.acc = new AdaptiveColorCollection(item.rgb, index++));
-    if (logging)
+    //if (logging)
       System.out.println("# GIF colors = " + ht.size());
     return ht;
   }

Modified: trunk/Jmol/src/org/jmol/script/T.java
===================================================================
--- trunk/Jmol/src/org/jmol/script/T.java       2014-10-14 13:59:43 UTC (rev 
20075)
+++ trunk/Jmol/src/org/jmol/script/T.java       2014-10-15 02:27:06 UTC (rev 
20076)
@@ -2125,6 +2125,7 @@
         "trajectory",
         "trajectories",
         "translucent",
+        "transparent",
         "triangles",
         "trim",
         "type",
@@ -3143,6 +3144,7 @@
         trajectory,                         // "trajectory"
         -1,                                 // "trajectories"
         translucent,                        // "translucent"
+        -1,                                 // "transparent"
         triangles,                          // "triangles"
         trim,                               // "trim"
         type,                               // "type"

Modified: trunk/Jmol/src/org/jmol/scriptext/CmdExt.java
===================================================================
--- trunk/Jmol/src/org/jmol/scriptext/CmdExt.java       2014-10-14 13:59:43 UTC 
(rev 20075)
+++ trunk/Jmol/src/org/jmol/scriptext/CmdExt.java       2014-10-15 02:27:06 UTC 
(rev 20076)
@@ -479,23 +479,28 @@
     }
     float endTime = 10; // ten seconds by default
     int mode = 0;
+    boolean isTransparent = false;
     String fileName = "";
     Map<String, Object> params = vwr.captureParams;
     boolean looping = !vwr.am.animationReplayMode.name().equals("ONCE");
-    int tok = tokAt(1);
+    int i = 1;
+    int tok = tokAt(i);
     switch (tok) {
     case T.nada:
       mode = T.end;
       break;
     case T.string:
-      fileName = e.optParameterAsString(1);
+      fileName = e.optParameterAsString(i++);
       if (fileName.length() == 0) {
         mode = T.end;
         break;
       }
-      if (!fileName.endsWith(".gif"))
+      if (fileName.toLowerCase().endsWith(".gift")) {
+        isTransparent = true;
+        fileName = fileName.substring(0,  fileName.length() - 1);
+      }
+      if (!fileName.toLowerCase().endsWith(".gif"))
         fileName += ".gif";
-      int i = 2;
       boolean isRock = false;
       switch (tokAt(i)) {
       case T.rock:
@@ -507,7 +512,7 @@
         looping = true;
         i = 3;
         if (isRock) {
-          if (tokAt(3) != T.integer)
+          if (tokAt(i) != T.integer)
             axis = e.optParameterAsString(i++).toLowerCase();
           s = "rotate Y 10 10;rotate Y -10 -10;rotate Y -10 -10;rotate Y 10 
10";
           s = PT.rep(s, "10", "" + (tokAt(i) == T.nada ? 5 : 
intParameter(i++)));
@@ -522,12 +527,12 @@
           axis = "y";
         boolean wf = vwr.g.waitForMoveTo;
         s = "set waitformoveto true;" + PT.rep(s, "Y", axis) + ";set 
waitformoveto " + wf;
-        s = "capture " + PT.esc(fileName) + " -1;" + s + ";capture;";
+        s = "capture " + PT.esc(fileName) + (isTransparent ? " transparent" : 
"") + " -1;" + s + ";capture;";
         e.cmdScript(0, null, s);
         return;
       case T.decimal:
       case T.integer:
-        endTime = floatParameter(2);
+        endTime = floatParameter(i++);
         if (endTime < 0)
           looping = true;
         break;
@@ -555,7 +560,10 @@
     }
     if (chk || params == null)
       return;
-    params.put("type", "GIF");
+    params.put  ("type", "GIF");
+    if (isTransparent || tokAt(i) == T.translucent)
+      params.put("transparentColor",
+          Integer.valueOf(vwr.getBackgroundArgb()));
     params.put("fileName", fileName);
     params.put("quality", Integer.valueOf(-1));
     params.put( 
@@ -6125,7 +6133,7 @@
             ScriptError.ERROR_writeWhat,
             
"COORDS|FILE|FUNCTIONS|HISTORY|IMAGE|INLINE|ISOSURFACE|JMOL|MENU|MO|POINTGROUP|QUATERNION
 [w,x,y,z] [derivative]"
                 + "|RAMACHANDRAN|SPT|STATE|VAR x|ZIP|ZIPALL  CLIPBOARD",
-            
"CML|GIF|JPG|JPG64|JMOL|JVXL|MESH|MOL|PDB|PMESH|PNG|PNGJ|PNGT|PPM|PQR|SDF|CD|JSON|V2000|V3000|SPT|XJVXL|XYZ|XYZRN|XYZVIB|ZIP"
+            
"CML|GIF|GIFT|JPG|JPG64|JMOL|JVXL|MESH|MOL|PDB|PMESH|PNG|PNGJ|PNGT|PPM|PQR|SDF|CD|JSON|V2000|V3000|SPT|XJVXL|XYZ|XYZRN|XYZVIB|ZIP"
                 + driverList.toUpperCase().replace(';', '|'));
       if (chk)
         return "";
@@ -6348,6 +6356,11 @@
         params = new Hashtable<String, Object>();
         if (fileName != null)
           params.put("fileName", fileName);
+        if (type.equals("GIFT")) {
+          params.put("transparentColor",
+              Integer.valueOf(vwr.getBackgroundArgb()));
+          type = "GIF";
+        }
         params.put("type", type);
         if (bytes instanceof String && quality == Integer.MIN_VALUE)
           params.put("text", bytes);

Modified: trunk/Jmol/src/org/jmol/viewer/JC.java
===================================================================
--- trunk/Jmol/src/org/jmol/viewer/JC.java      2014-10-14 13:59:43 UTC (rev 
20075)
+++ trunk/Jmol/src/org/jmol/viewer/JC.java      2014-10-15 02:27:06 UTC (rev 
20076)
@@ -1691,7 +1691,7 @@
 
   public static final String SCRIPT_COMPLETED = "Script completed";
   public static final String JPEG_EXTENSIONS = ";jpg;jpeg;jpg64;jpeg64;";
-  public final static String IMAGE_TYPES = JPEG_EXTENSIONS + 
"gif;pdf;ppm;png;pngj;pngt;";
+  public final static String IMAGE_TYPES = JPEG_EXTENSIONS + 
"gif;gift;pdf;ppm;png;pngj;pngt;";
   public static final String IMAGE_OR_SCENE = IMAGE_TYPES + "scene;";
 
   public static boolean isScriptType(String fname) {

Modified: trunk/Jmol/src/org/jmol/viewer/Jmol.properties
===================================================================
--- trunk/Jmol/src/org/jmol/viewer/Jmol.properties      2014-10-14 13:59:43 UTC 
(rev 20075)
+++ trunk/Jmol/src/org/jmol/viewer/Jmol.properties      2014-10-15 02:27:06 UTC 
(rev 20076)
@@ -17,6 +17,10 @@
 
 Jmol.___JmolVersion="14.3.8_2014.10.14"
 
+new feature: transparent GIF using WRITE GIFT "xxx.gif"
+new feature: GIF images use dithering to approximate full palette.
+new feature: capture "file.gif" 10 transparent   -- but does not work
+
 bug fix: Legendre for U not implemented in msCIF reader - preliminary
 bug fix: Legendre for D,U in Jana2006 reader not implemented - preliminary
 

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.


------------------------------------------------------------------------------
Comprehensive Server Monitoring with Site24x7.
Monitor 10 servers for $9/Month.
Get alerted through email, SMS, voice calls or mobile push notifications.
Take corrective actions from your mobile device.
http://p.sf.net/sfu/Zoho
_______________________________________________
Jmol-commits mailing list
Jmol-commits@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jmol-commits

Reply via email to