浏览代码

wip, server-side image-generator app

Alexander Rose 5 年之前
父节点
当前提交
fdb22361de
共有 3 个文件被更改,包括 153 次插入3 次删除
  1. 12 1
      README.md
  2. 6 2
      package.json
  3. 135 0
      src/apps/image-generator/index.ts

+ 12 - 1
README.md

@@ -115,7 +115,18 @@ Run the image
 
 To see all available commands, use ``node build/model-server/preprocess -h``.
 
-## Editor
+## Development
+
+### Intallation
+
+If node complains about a missine acorn peer dependency, run the following commands
+
+    npm update acorn --depth 20
+    npm dedupe
+
+If the `gl` package does not compile on node 12 (there are currently no pre-built binaries) revert back to node 10.
+
+### Editor
 
 To get syntax highlighting for the shader files add the following to Visual Code's settings files
 

+ 6 - 2
package.json

@@ -79,13 +79,15 @@
     "@types/benchmark": "^1.0.31",
     "@types/compression": "0.0.36",
     "@types/express": "^4.16.1",
+    "@types/gl": "^4.1.0",
     "@types/jest": "^24.0.12",
     "@types/node": "^12.0.1",
     "@types/node-fetch": "^2.3.3",
+    "@types/pngjs": "^3.3.2",
     "@types/react": "^16.8.17",
     "@types/react-dom": "^16.8.4",
-    "@types/webgl2": "0.0.4",
     "@types/swagger-ui-dist": "3.0.0",
+    "@types/webgl2": "0.0.4",
     "benchmark": "^2.1.4",
     "circular-dependency-plugin": "^5.0.2",
     "concurrently": "^4.1.0",
@@ -93,7 +95,7 @@
     "css-loader": "^2.1.1",
     "extra-watch-webpack-plugin": "^1.0.3",
     "file-loader": "^3.0.1",
-    "graphql-code-generator": "^0.18.1",
+    "graphql-code-generator": "^0.18.2",
     "graphql-codegen-time": "^0.18.1",
     "graphql-codegen-typescript-template": "^0.18.1",
     "jest": "^24.8.0",
@@ -116,9 +118,11 @@
     "argparse": "^1.0.10",
     "compression": "^1.7.4",
     "express": "^4.16.4",
+    "gl": "^4.2.2",
     "graphql": "^14.3.0",
     "immutable": "^3.8.2",
     "node-fetch": "^2.5.0",
+    "pngjs": "^3.4.0",
     "react": "^16.8.6",
     "react-dom": "^16.8.6",
     "rxjs": "^6.5.2",

+ 135 - 0
src/apps/image-generator/index.ts

@@ -0,0 +1,135 @@
+/**
+ * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import * as argparse from 'argparse'
+import createContext = require('gl')
+import fs = require('fs')
+import { PNG } from 'pngjs'
+import { Canvas3D, Canvas3DParams } from 'mol-canvas3d/canvas3d';
+import InputObserver from 'mol-util/input/input-observer';
+import { ColorTheme } from 'mol-theme/color';
+import { SizeTheme } from 'mol-theme/size';
+import { CartoonRepresentationProvider } from 'mol-repr/structure/representation/cartoon';
+import CIF, { CifFrame } from 'mol-io/reader/cif'
+import { trajectoryFromMmCIF } from 'mol-model-formats/structure/mmcif';
+import { Model, Structure } from 'mol-model/structure';
+import { ajaxGet } from 'mol-util/data-source';
+import { ColorNames } from 'mol-util/color/tables';
+
+const width = 1024
+const height = 768
+const gl = createContext(width, height, {
+    alpha: false,
+    antialias: true,
+    depth: true,
+    preserveDrawingBuffer: true
+})
+
+const input = InputObserver.create()
+const canvas3d = Canvas3D.create(gl, input, {
+    multiSample: 'on',
+    sampleLevel: 3,
+    renderer: {
+        ...Canvas3DParams.renderer.defaultValue,
+        lightIntensity: 0,
+        ambientIntensity: 1,
+        backgroundColor: ColorNames.white
+    },
+    postprocessing: {
+        ...Canvas3DParams.postprocessing.defaultValue,
+        occlusionEnable: true,
+        outlineEnable: true
+    }
+})
+canvas3d.animate()
+
+const reprCtx = {
+    wegbl: canvas3d.webgl,
+    colorThemeRegistry: ColorTheme.createRegistry(),
+    sizeThemeRegistry: SizeTheme.createRegistry()
+}
+function getCartoonRepr() {
+    return CartoonRepresentationProvider.factory(reprCtx, CartoonRepresentationProvider.getParams)
+}
+
+async function parseCif(data: string|Uint8Array) {
+    const comp = CIF.parse(data);
+    const parsed = await comp.run();
+    if (parsed.isError) throw parsed;
+    return parsed.result;
+}
+
+async function downloadCif(url: string, isBinary: boolean) {
+    const data = await ajaxGet({ url, type: isBinary ? 'binary' : 'string' }).run();
+    return parseCif(data);
+}
+
+async function downloadFromPdb(pdb: string) {
+    const parsed = await downloadCif(`https://files.rcsb.org/download/${pdb}.cif`, false);
+    // const parsed = await downloadCif(`https://webchem.ncbr.muni.cz/ModelServer/static/bcif/${pdb}`, true);
+    return parsed.blocks[0];
+}
+
+async function getModels(frame: CifFrame) {
+    return await trajectoryFromMmCIF(frame).run();
+}
+
+async function getStructure(model: Model) {
+    return Structure.ofModel(model);
+}
+
+async function run(id: string, out: string) {
+    try {
+        const cif = await downloadFromPdb(id)
+        const models = await getModels(cif)
+        const structure = await getStructure(models[0])
+
+        const cartoonRepr = getCartoonRepr()
+        cartoonRepr.setTheme({
+            color: reprCtx.colorThemeRegistry.create('sequence-id', { structure }),
+            size: reprCtx.sizeThemeRegistry.create('uniform', { structure })
+        })
+        await cartoonRepr.createOrUpdate({ ...CartoonRepresentationProvider.defaultValues, quality: 'auto' }, structure).run()
+
+        canvas3d.add(cartoonRepr)
+        canvas3d.resetCamera()
+    } catch (e) {
+        console.log(e)
+        process.exit(1)
+    }
+
+    setTimeout(() => {
+        const pixelData = canvas3d.getPixelData('draw')
+        const png = new PNG({ width, height })
+        png.data = Buffer.from(pixelData.array)
+        png.pack().pipe(fs.createWriteStream(out)).on('finish', () => {
+            process.exit()
+        })
+    }, 2000)
+}
+
+//
+
+const parser = new argparse.ArgumentParser({
+    addHelp: true,
+    description: 'render image as PNG (work in progress)'
+});
+parser.addArgument([ '--id', '-i' ], {
+    required: true,
+    help: 'PDB ID'
+});
+parser.addArgument([ '--out', '-o' ], {
+    required: true,
+    help: 'image output path'
+});
+
+interface Args {
+    id: string
+    out: string
+}
+const args: Args = parser.parseArgs();
+
+run(args.id, args.out)