text: const MARKERS = [0xFFC0, 0xFFC1, 0xFFC2, 0xFFC3, 0xFFC5, 0xFFC6, 0xFFC7,
    0xFFC8, 0xFFC9, 0xFFCA, 0xFFCB, 0xFFCC, 0xFFCD, 0xFFCE, 0xFFCF];
  
  const COLOR_SPACE_MAP = {
    1: 'DeviceGray',
    3: 'DeviceRGB',
    4: 'DeviceCMYK'
  }
  
  class JPEG {
    constructor(data, label) {
      let marker;
      this.data = data;
      this.label = label;
      if (this.data.readUInt16BE(0) !== 0xFFD8) {
        throw "SOI not found in JPEG";
      }
            
      let pos = 2;
      while (pos < this.data.length) {
        marker = this.data.readUInt16BE(pos);
        pos += 2;
        if (MARKERS.includes(marker)) { break; }
        pos += this.data.readUInt16BE(pos);
      }
  
      if (!MARKERS.includes(marker)) { throw "Invalid JPEG."; }
      pos += 2;
  
      this.bits = this.data[pos++];
      this.height = this.data.readUInt16BE(pos);
      pos += 2;
  
      this.width = this.data.readUInt16BE(pos);
      pos += 2;
  
      const channels = this.data[pos++];
      this.colorSpace = COLOR_SPACE_MAP[channels];
      
      this.obj = null;
    }
      
    embed(document) {
      if (this.obj) { return; }
    
      this.obj = document.ref({
        Type: 'XObject',
        Subtype: 'Image',
        BitsPerComponent: this.bits,
        Width: this.width,
        Height: this.height,
        ColorSpace: this.colorSpace,
        Filter: 'DCTDecode'
      });
      
      // add extra decode params for CMYK images. By swapping the
      // min and max values from the default, we invert the colors. See
      // section 4.8.4 of the spec.  
      if (this.colorSpace === 'DeviceCMYK') {
        this.obj.data['Decode'] = [1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0];
      }
      
      this.obj.end(this.data);
    
      // free memory
      return this.data = null;
    }
  };
      
  export default JPEG;
  