Kaynağa Gözat

wip, server-side image-generator app

Alexander Rose 5 yıl önce
ebeveyn
işleme
fdb22361de
3 değiştirilmiş dosya ile 153 ekleme ve 3 silme
  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``.
 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
 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/benchmark": "^1.0.31",
     "@types/compression": "0.0.36",
     "@types/compression": "0.0.36",
     "@types/express": "^4.16.1",
     "@types/express": "^4.16.1",
+    "@types/gl": "^4.1.0",
     "@types/jest": "^24.0.12",
     "@types/jest": "^24.0.12",
     "@types/node": "^12.0.1",
     "@types/node": "^12.0.1",
     "@types/node-fetch": "^2.3.3",
     "@types/node-fetch": "^2.3.3",
+    "@types/pngjs": "^3.3.2",
     "@types/react": "^16.8.17",
     "@types/react": "^16.8.17",
     "@types/react-dom": "^16.8.4",
     "@types/react-dom": "^16.8.4",
-    "@types/webgl2": "0.0.4",
     "@types/swagger-ui-dist": "3.0.0",
     "@types/swagger-ui-dist": "3.0.0",
+    "@types/webgl2": "0.0.4",
     "benchmark": "^2.1.4",
     "benchmark": "^2.1.4",
     "circular-dependency-plugin": "^5.0.2",
     "circular-dependency-plugin": "^5.0.2",
     "concurrently": "^4.1.0",
     "concurrently": "^4.1.0",
@@ -93,7 +95,7 @@
     "css-loader": "^2.1.1",
     "css-loader": "^2.1.1",
     "extra-watch-webpack-plugin": "^1.0.3",
     "extra-watch-webpack-plugin": "^1.0.3",
     "file-loader": "^3.0.1",
     "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-time": "^0.18.1",
     "graphql-codegen-typescript-template": "^0.18.1",
     "graphql-codegen-typescript-template": "^0.18.1",
     "jest": "^24.8.0",
     "jest": "^24.8.0",
@@ -116,9 +118,11 @@
     "argparse": "^1.0.10",
     "argparse": "^1.0.10",
     "compression": "^1.7.4",
     "compression": "^1.7.4",
     "express": "^4.16.4",
     "express": "^4.16.4",
+    "gl": "^4.2.2",
     "graphql": "^14.3.0",
     "graphql": "^14.3.0",
     "immutable": "^3.8.2",
     "immutable": "^3.8.2",
     "node-fetch": "^2.5.0",
     "node-fetch": "^2.5.0",
+    "pngjs": "^3.4.0",
     "react": "^16.8.6",
     "react": "^16.8.6",
     "react-dom": "^16.8.6",
     "react-dom": "^16.8.6",
     "rxjs": "^6.5.2",
     "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)