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