diff --git a/__tests__/WebAnnotation.test.js b/__tests__/WebAnnotation.test.js
index 0e4baa8c3885e1ae568647cebf3f8bf72632f680..ee08252a386eac1bf4d26c2fb1f9b8462b0ad3c9 100644
--- a/__tests__/WebAnnotation.test.js
+++ b/__tests__/WebAnnotation.test.js
@@ -3,7 +3,9 @@ import WebAnnotation from '../src/WebAnnotation';
 /** */
 function createSubject(args = {}) {
   return new WebAnnotation({
-    body: 'body',
+    body: {
+      value: 'body',
+    },
     canvasId: 'canvasId',
     fragsel: { t: '5,10', xywh: 'xywh' },
     id: 'id',
@@ -17,11 +19,16 @@ describe('WebAnnotation', () => {
   let subject = createSubject();
   describe('constructor', () => {
     it('sets instance accessors', () => {
-      ['body', 'canvasId', 'id', 'svg'].forEach((prop) => {
+      ['canvasId', 'id', 'svg'].forEach((prop) => {
         expect(subject[prop]).toBe(prop);
       });
       expect(subject.fragsel).toStrictEqual({ t: '5,10', xywh: 'xywh' });
     });
+    it('sets instance accessors for body', () => {
+      ['body'].forEach((prop) => {
+        expect(subject[prop].value).toBe(prop);
+      });
+    });
   });
   describe('target', () => {
     it('with svg and xywh', () => {
@@ -109,20 +116,34 @@ describe('WebAnnotation', () => {
       ]);
     });
     it('with text only', () => {
-      subject = createSubject({ tags: null });
+      subject = createSubject({ image: null, tags: null });
       expect(subject.createBody()).toEqual({
         type: 'TextualBody',
         value: 'body',
       });
     });
     it('with tags only', () => {
-      subject = createSubject({ body: null });
+      subject = createSubject({ body: null, image: null });
       expect(subject.createBody()).toEqual({
         purpose: 'tagging',
         type: 'TextualBody',
         value: 'tags',
       });
     });
+    it('with image and text', () => {
+      subject = createSubject({ body: {value: 'hello'}, image: {url: 'http://example.photo/pic.jpg' }, tags: null });
+      expect(subject.createBody()).toEqual([
+        {
+          type: 'TextualBody',
+          value: 'hello',
+        },
+        {
+          type: 'Image',
+          format: 'image/jpg',
+          id: 'http://example.photo/pic.jpg',
+        },
+      ]);
+    });
   });
   describe('toJson', () => {
     it('generates a WebAnnotation', () => {
diff --git a/src/AnnotationCreation.js b/src/AnnotationCreation.js
index ba428ddb855a4c5365fed643d1689966fbde63f5..471f18f258e9bc764e45d541ee5f0b55ab74d7df 100644
--- a/src/AnnotationCreation.js
+++ b/src/AnnotationCreation.js
@@ -19,6 +19,14 @@ import StrokeColorIcon from '@material-ui/icons/BorderColor';
 import LineWeightIcon from '@material-ui/icons/LineWeight';
 import ArrowDropDownIcon from '@material-ui/icons/ArrowDropDown';
 import FormatShapesIcon from '@material-ui/icons/FormatShapes';
+import InsertPhotoIcon from '@material-ui/icons/InsertPhoto';
+import Dialog from '@material-ui/core/Dialog';
+import DialogTitle from '@material-ui/core/DialogTitle';
+import DialogContent from '@material-ui/core/DialogContent';
+import DialogActions from '@material-ui/core/DialogActions';
+import TextField from '@material-ui/core/TextField';
+import Checkbox from '@material-ui/core/Checkbox';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
 import { SketchPicker } from 'react-color';
 import { v4 as uuid } from 'uuid';
 import { withStyles } from '@material-ui/core/styles';
@@ -55,25 +63,52 @@ function geomFromAnnoTarget(annotarget) {
 
 /** */
 class AnnotationCreation extends Component {
+  /** */
+  static checkURL(url) {
+    const expression = /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)/;
+    const regex = new RegExp(expression);
+
+    return url.match(regex);
+  }
+
+  /** */
+  static loadImg(url) {
+    return new Promise((resolve, reject) => {
+      const img = new Image();
+      img.src = url;
+
+      img.onload = () => resolve({ height: img.height, width: img.width });
+      img.onerror = reject;
+    });
+  }
+
   /** */
   constructor(props) {
     super(props);
 
     const annoState = {};
+    annoState.image = false;
+
     if (props.annotation) {
       //
       // annotation body
       if (Array.isArray(props.annotation.body)) {
         annoState.tags = [];
         props.annotation.body.forEach((body) => {
-          if (body.purpose === 'tagging') {
+          if (body.purpose === 'tagging' && body.type === 'TextualBody') {
             annoState.tags.push(body.value);
-          } else {
-            annoState.annoBody = body.value;
+          } else if (body.type === 'TextualBody') {
+            annoState.textBody = body.value;
+          } else if (body.type === 'Image') {
+            // annoState.textBody = body.value; // why text body here ???
+            annoState.image = body;
           }
         });
-      } else {
-        annoState.annoBody = props.annotation.body.value;
+      } else if (props.annotation.body.type === 'TextualBody') {
+        annoState.textBody = props.annotation.body.value;
+      } else if (props.annotation.body.type === 'Image') {
+        // annoState.textBody = props.annotation.body.value; // why text body here ???
+        annoState.image = props.annotation.body;
       }
       //
       // drawing position
@@ -102,6 +137,7 @@ class AnnotationCreation extends Component {
       activeTool: 'cursor',
       closedMode: 'closed',
       currentColorType: false,
+      colorPopoverOpen: false,
       fillColor: null,
       strokeColor: '#00BFFF',
       strokeWidth: 3,
@@ -115,19 +151,45 @@ class AnnotationCreation extends Component {
     this.state = {
       ...toolState,
       ...timeState,
-      annoBody: '',
-      colorPopoverOpen: false,
+      textBody: '',
+      activeTool: 'cursor',
+      closedMode: 'closed',
+      currentColorType: false,
+      fillColor: null,
       lineWeightPopoverOpen: false,
+      openAddImgDialog: false,
       popoverAnchorEl: null,
       popoverLineWeightAnchorEl: null,
       svg: null,
       textEditorStateBustingKey: 0,
+      imgConstrain: false,
+      imgHeight: {
+        lastSubmittedValue: '',
+        srcValue: '',
+        validity: 0,
+        value: '',
+      },
+      imgUrl: {
+        lastSubmittedValue: '',
+        validity: 0,
+        value: '',
+      },
+      imgWidth: {
+        lastSubmittedValue: '',
+        srcValue: '',
+        validity: 0,
+        value: '',
+      },
       xywh: null,
       ...annoState,
     };
 
     this.submitForm = this.submitForm.bind(this);
-    this.updateBody = this.updateBody.bind(this);
+    // this.updateBody = this.updateBody.bind(this);
+    this.updateTextBody = this.updateTextBody.bind(this);
+    this.getImgDimensions = this.getImgDimensions.bind(this);
+    this.setImgWidth = this.setImgWidth.bind(this);
+    this.setImgHeight = this.setImgHeight.bind(this);
     this.updateTstart = this.updateTstart.bind(this);
     this.updateTend = this.updateTend.bind(this);
     this.setTstartNow = this.setTstartNow.bind(this);
@@ -143,6 +205,79 @@ class AnnotationCreation extends Component {
     this.handleCloseLineWeight = this.handleCloseLineWeight.bind(this);
     this.closeChooseColor = this.closeChooseColor.bind(this);
     this.updateStrokeColor = this.updateStrokeColor.bind(this);
+    this.isConstrained = this.isConstrained.bind(this);
+    this.handleConstrainCheck = this.handleConstrainCheck.bind(this);
+    this.handleImgDialogChange = this.handleImgDialogChange.bind(this);
+    this.handleImgDialogSubmit = this.handleImgDialogSubmit.bind(this);
+  }
+
+  /** */
+  handleImgDialogChange(open) {
+    const { imgHeight, imgWidth, imgUrl } = this.state;
+
+    this.setState({
+      imgHeight: {
+        ...imgHeight,
+        validity: 1,
+        value: imgHeight.lastSubmittedValue,
+      },
+      imgUrl: {
+        ...imgUrl,
+        validity: 1,
+        value: imgUrl.lastSubmittedValue,
+      },
+      imgWidth: {
+        ...imgWidth,
+        validity: 1,
+        value: imgWidth.lastSubmittedValue,
+      },
+      openAddImgDialog: open,
+    });
+  }
+
+  /** */
+  handleConstrainCheck(event) {
+    const value = event.target.checked;
+
+    this.setState({
+      imgConstrain: value,
+    });
+  }
+
+  /** */
+  handleImgDialogSubmit() {
+    let open = true;
+    const { imgUrl, imgHeight, imgWidth } = this.state;
+
+    const urlValidity = AnnotationCreation.checkURL(imgUrl.value) ? 1 : 2;
+    const widthValidity = imgWidth.value > 0 ? 1 : 2;
+    const heightValidity = imgHeight.value > 0 ? 1 : 2;
+    if (urlValidity === 1 && widthValidity === 1 && heightValidity === 1) {
+      open = false;
+    }
+
+    this.setState({
+      image: { id: imgUrl.value },
+      imgHeight: {
+        ...imgHeight,
+        lastSubmittedValue: heightValidity === 1 ? imgHeight.value : imgHeight.lastSubmittedValue,
+        validity: heightValidity,
+        value: imgHeight.value,
+      },
+      imgUrl: {
+        ...imgUrl,
+        lastSubmittedValue: urlValidity === 1 ? imgUrl.value : imgUrl.lastSubmittedValue,
+        validity: urlValidity,
+        value: imgUrl.value,
+      },
+      imgWidth: {
+        ...imgWidth,
+        lastSubmittedValue: widthValidity === 1 ? imgWidth.value : imgWidth.lastSubmittedValue,
+        validity: widthValidity,
+        value: imgWidth.value,
+      },
+      openAddImgDialog: open,
+    });
   }
 
   /** */
@@ -202,6 +337,106 @@ class AnnotationCreation extends Component {
     }
   }
 
+  /** */
+  async getImgDimensions(url) {
+    const { imgHeight, imgWidth, imgUrl } = this.state;
+    const urlValidity = AnnotationCreation.checkURL(url) ? 1 : 2;
+
+    try {
+      const dimensions = await AnnotationCreation.loadImg(url);
+
+      this.setState({
+        imgHeight: {
+          ...imgHeight,
+          srcValue: dimensions.height || '',
+          value: dimensions.height || '',
+        },
+        imgUrl: {
+          ...imgUrl,
+          validity: 1,
+          value: url,
+        },
+        imgWidth: {
+          ...imgWidth,
+          srcValue: dimensions.width || '',
+          value: dimensions.width || '',
+        },
+      });
+    } catch (e) {
+      this.setState({
+        imgUrl: {
+          ...imgUrl,
+          validity: urlValidity,
+          value: url,
+        },
+      });
+    }
+  }
+
+  /** */
+  setImgWidth(value) {
+    const { imgWidth } = this.state;
+    this.setState({
+      imgWidth: {
+        ...imgWidth,
+        value,
+      },
+    });
+  }
+
+  /** */
+  setImgUrl(value) {
+    const { imgUrl } = this.state;
+    this.setState({
+      imgUrl: {
+        ...imgUrl,
+        value,
+      },
+    });
+  }
+
+  /** */
+  setImgHeight(value) {
+    const { imgHeight } = this.state;
+    this.setState({
+      imgHeight: {
+        ...imgHeight,
+        value,
+      },
+    });
+  }
+
+  /** */
+  isConstrained(event) { // adjust other dimension in proportion to inputted dimension
+    const { imgConstrain, imgWidth, imgHeight } = this.state;
+    const ratio = imgWidth.srcValue / imgHeight.srcValue;
+
+    if (imgConstrain) {
+      if (event.target.id === 'width' && imgWidth.srcValue !== '') {
+        // set height to be the same as width if width is less than 0
+        const height = imgWidth.value > 0 ? imgWidth.value * (1 / ratio) : imgWidth.value;
+        this.setState({
+          imgHeight: {
+            ...imgHeight,
+            validity: 1,
+            value: height,
+          },
+        });
+      } else if (event.target.id === 'height' && imgHeight.srcValue !== '') {
+        // set width to be the same as height if height is less than 0
+        const width = imgHeight.value > 0 ? imgHeight.value * ratio : imgHeight.value;
+
+        this.setState({
+          imgWidth: {
+            ...imgWidth,
+            validity: 1,
+            value: width,
+          },
+        });
+      }
+    }
+  }
+
   /** */
   openChooseColor(e) {
     this.setState({
@@ -243,20 +478,38 @@ class AnnotationCreation extends Component {
       annotation, canvases, receiveAnnotation, config,
     } = this.props;
     const {
-      annoBody, tags, xywh, svg, tstart, tend, textEditorStateBustingKey,
+      textBody, image, imgWidth, imgHeight, imgUrl, tags, xywh, svg,
+      imgConstrain, tstart, tend, textEditorStateBustingKey,
     } = this.state;
     const t = (tstart && tend) ? `${tstart},${tend}` : null;
+    const annoBody = { value: (!textBody.length && t) ? `${secondsToHMS(tstart)} -> ${secondsToHMS(tend)}` : textBody };
+
+    let imgBody;
+    if (imgWidth.validity === 1 && imgHeight.validity === 1 && imgUrl.validity === 1) {
+      imgBody = {
+        constrain: imgConstrain,
+        h: imgHeight.value,
+        url: imgUrl.value,
+        w: imgWidth.value,
+      };
+    } else {
+      imgBody = image;
+    }
+
     canvases.forEach((canvas) => {
       const storageAdapter = config.annotation.adapter(canvas.id);
+
       const anno = new WebAnnotation({
-        body: (!annoBody.length && t) ? `${secondsToHMS(tstart)} -> ${secondsToHMS(tend)}` : annoBody,
+        body: annoBody,
         canvasId: canvas.id,
         fragsel: { t, xywh },
         id: (annotation && annotation.id) || `${uuid()}`,
+        image: imgBody,
         manifestId: canvas.options.resource.id,
         svg,
         tags,
       }).toJson();
+
       if (annotation) {
         storageAdapter.update(anno).then((annoPage) => {
           receiveAnnotation(canvas.id, storageAdapter.annotationPageId, annoPage);
@@ -269,9 +522,10 @@ class AnnotationCreation extends Component {
     });
 
     this.setState({
-      annoBody: '',
+      image: false,
       svg: null,
       tend: null,
+      textBody: '',
       textEditorStateBustingKey: textEditorStateBustingKey + 1,
       tstart: null,
       xywh: null,
@@ -293,8 +547,8 @@ class AnnotationCreation extends Component {
   }
 
   /** */
-  updateBody(annoBody) {
-    this.setState({ annoBody });
+  updateTextBody(textBody) {
+    this.setState({ textBody });
   }
 
   /** */
@@ -311,9 +565,10 @@ class AnnotationCreation extends Component {
     } = this.props;
 
     const {
-      activeTool, colorPopoverOpen, currentColorType, fillColor, popoverAnchorEl, strokeColor,
-      popoverLineWeightAnchorEl, lineWeightPopoverOpen, strokeWidth, closedMode, annoBody, svg,
-      tstart, tend, textEditorStateBustingKey,
+      activeTool, colorPopoverOpen, currentColorType, fillColor, openAddImgDialog, popoverAnchorEl,
+      strokeColor, popoverLineWeightAnchorEl, lineWeightPopoverOpen, strokeWidth, closedMode,
+      textBody, imgUrl, imgWidth, imgHeight, imgConstrain, svg, tstart, tend,
+      textEditorStateBustingKey, image,
     } = this.state;
 
     const mediaIsVideo = typeof VideosReferences.get(windowId) !== 'undefined';
@@ -326,6 +581,7 @@ class AnnotationCreation extends Component {
       >
         <AnnotationDrawing
           activeTool={activeTool}
+          annotation={annotation}
           fillColor={fillColor}
           strokeColor={strokeColor}
           strokeWidth={strokeWidth}
@@ -440,7 +696,6 @@ class AnnotationCreation extends Component {
                   )
                   : null
               }
-
             </Grid>
           </Grid>
           <Grid container>
@@ -464,7 +719,7 @@ class AnnotationCreation extends Component {
 
               <Grid item xs={12}>
                 <Typography variant="overline">
-                  <ToggleButton value="true" title="Go to start time" size="small" onClick={this.seekToTend} className={classes.timecontrolsbutton}>
+                  <ToggleButton value="true" title="Go to end time" size="small" onClick={this.seekToTend} className={classes.timecontrolsbutton}>
                     <LastPage />
                   </ToggleButton>
                   End
@@ -481,14 +736,93 @@ class AnnotationCreation extends Component {
             )}
             <Grid item xs={12}>
               <Typography variant="overline">
-                Content
+                Image Content
+              </Typography>
+            </Grid>
+            <Grid item xs={12} style={{ marginBottom: 10 }}>
+              <ToggleButton value="image-icon" aria-label="insert an image" onClick={() => this.handleImgDialogChange(true)}>
+                { image === false && <InsertPhotoIcon /> }
+                { image !== false && <img src={image.id} width="100" height="auto" alt="no trad" /> }
+              </ToggleButton>
+            </Grid>
+            <Dialog open={openAddImgDialog} fullWidth onClose={() => this.handleImgDialogChange(false)} aria-labelledby="form-dialog-title">
+              <DialogTitle id="form-dialog-title" disableTypography>
+                <Typography variant="h2">Insert image</Typography>
+              </DialogTitle>
+              <DialogContent>
+                <DialogTitle id="form-dialog-subtitle-1" style={{ paddingLeft: 0 }} disableTypography>
+                  <Typography variant="h5">Image source</Typography>
+                </DialogTitle>
+                <TextField
+                  value={imgUrl.value}
+                  onChange={(e) => this.setImgUrl(e.target.value)}
+                  onBlur={(e) => this.getImgDimensions(e.target.value)}
+                  error={imgUrl.validity === 2}
+                  helperText={imgUrl.validity === 2 ? 'Invalid URL' : ''}
+                  margin="dense"
+                  id="source"
+                  label="Image URL"
+                  type="url"
+                  fullWidth
+                />
+              </DialogContent>
+              <DialogContent>
+                <DialogTitle id="form-dialog-subtitle-2" style={{ paddingLeft: 0 }} disableTypography>
+                  <Typography variant="h5">Image dimensions</Typography>
+                </DialogTitle>
+                <TextField
+                  value={imgWidth.value}
+                  style={{ marginRight: 10, width: 100 }}
+                  onChange={(e) => this.setImgWidth(e.target.value)}
+                  onBlur={(e) => this.isConstrained(e)}
+                  error={imgWidth.validity === 2}
+                  helperText={imgWidth.validity === 2 ? 'Invalid width' : ''}
+                  margin="dense"
+                  id="width"
+                  label="Width"
+                  type="number"
+                  variant="outlined"
+                />
+                <TextField
+                  value={imgHeight.value}
+                  style={{ marginLeft: 10, width: 100 }}
+                  onChange={(e) => this.setImgHeight(e.target.value)}
+                  onBlur={(e) => this.isConstrained(e)}
+                  error={imgHeight.validity === 2}
+                  helperText={imgHeight.validity === 2 ? 'Invalid height' : ''}
+                  margin="dense"
+                  id="height"
+                  label="Height"
+                  type="number"
+                  variant="outlined"
+                />
+                <FormControlLabel
+                  control={(
+                    <Checkbox
+                      checked={imgConstrain}
+                      onChange={(e) => this.handleConstrainCheck(e)}
+                      inputProps={{ 'aria-label': 'primary checkbox' }}
+                      style={{ marginLeft: 30 }}
+                    />
+                  )}
+                  label="Constrain proportions"
+                />
+              </DialogContent>
+              <DialogActions>
+                <Button onClick={() => this.handleImgDialogChange(false)}>Cancel</Button>
+                <Button variant="contained" onClick={this.handleImgDialogSubmit} color="primary">Add</Button>
+              </DialogActions>
+            </Dialog>
+            <Grid item xs={12}>
+              <Typography variant="overline">
+                Text Content
               </Typography>
             </Grid>
             <Grid item xs={12}>
               <TextEditor
                 key={textEditorStateBustingKey}
-                annoHtml={annoBody}
-                updateAnnotationBody={this.updateBody}
+                annoHtml={textBody}
+                updateAnnotationBody={this.updateTextBody}
               />
             </Grid>
           </Grid>
diff --git a/src/WebAnnotation.js b/src/WebAnnotation.js
index 78cd79f5068284f3a03e1d984080bd94d7885231..f43d1f807cd5a13197e91a54e16be1b056a1b551 100644
--- a/src/WebAnnotation.js
+++ b/src/WebAnnotation.js
@@ -2,7 +2,7 @@
 export default class WebAnnotation {
   /** */
   constructor({
-    canvasId, id, fragsel, body, tags, svg, manifestId,
+    canvasId, id, image, fragsel, body, tags, svg, manifestId,
   }) {
     this.id = id;
     this.canvasId = canvasId;
@@ -10,6 +10,7 @@ export default class WebAnnotation {
     this.body = body;
     this.tags = tags;
     this.svg = svg;
+    this.image = image;
     this.manifestId = manifestId;
   }
 
@@ -27,12 +28,23 @@ export default class WebAnnotation {
   /** */
   createBody() {
     let bodies = [];
-    if (this.body) {
-      bodies.push({
+
+    if (this.body && this.body.value !== '') {
+      const textBody = {
         type: 'TextualBody',
-        value: this.body,
-      });
+        value: this.body.value,
+      };
+      bodies.push(textBody);
     }
+
+    // TODO WebAnnot format
+    if (this.image) {
+      const imgBody = { type: 'Image' };
+      Object.assign(imgBody, this.image);
+      imgBody.id = imgBody.url;
+      bodies.push(imgBody);
+    }
+
     if (this.tags) {
       bodies = bodies.concat(this.tags.map((tag) => ({
         purpose: 'tagging',