如何根据JavaScript中的OpenType规范对CFF2操作数进行编码

时间:2019-01-22 08:46:43

标签: javascript fonts numbers specifications opentype

我正在查看规范,并且想知道如何将他们所说的内容转换为实际代码。这些integersreals的编码方式(更多相关信息here)。

var encodings = {
  // each encoding should return an array of 8-bit values.
  number: function(value){
    if (parseInt(value) !== value) return encodings.real(value)
    if (integer >= -107 && integer <= 107) return encodings.integer1(value)
    if (integer >= 108 && integer <= 1131) return encodings.integer2a(value)
    if (integer >= -1131 && integer <= -108) return encodings.integer2b(value)
    if (integer >= -32768 && integer <= 32767) return encodings.integer3(value)
    return encodings.integer5(value)
  },

  // 1 32 to 246 -107 to +107  b0 – 139
  // 0 8b    
  // 100 ef    
  // -100  27   
  integer1: function(integer){

  },

  // 2 247 to 250  +108 to +1131 (b0 – 247) * 256 + b1 + 108
  integer2a: function(integer){

  },

  // 2 251 to 254  -1131 to -108 -(b0 – 251) * 256 – b1 – 108
  integer2b: function(integer){

  },

  // 3 28  -32768 to +32767  b1 << 8 | b2
  integer3: function(integer){

  },

  // 5 29  -(2^31) to +(2^31 – 1)  b1 << 24 | b2 << 16 | b3 << 8 | b4
  integer5: function(integer){

  },

  // 0 to 9  0 to 9    
  // a . (decimal point)   
  // b E   
  // c E–    
  // d <reserved>    
  // e – (minus)   
  // f end of number
  real: function(real){

  }
}

console.log(encodings.number(0))
console.log(encodings.number(100))
console.log(encodings.number(-100))
console.log(encodings.number(1000))
console.log(encodings.number(10000))
console.log(encodings.number(-10000))
console.log(encodings.number(100000))
console.log(encodings.number(-100000))

// 1000  fa 7c   
// 10000 1c 27 10    
// -10000  1c d8 f0    
// 100000  1d 00 01 86 a0    
// -100000 1d ff fe 79 60

在阅读规范后,我想像这样编码第一个:

  integer1: function(integer){
    return integer - 139
  }

但是,根据他们的示例,这将导致错误的输出。所以我不太了解如何编码它们。想知道是否可以快速了解如何实现它们/如果实现不明显则实现的含义,或者实现是如何从规范中衍生出来的。

这是我用来计算编码值的实际代码的片段:

var api = {
  type: {
    NUMBER: {
      make: function(v) {
        if (v >= -107 && v <= 107) {
          return [v - 139];
        } else if (v >= 108 && v <= 1131) {
          v = v - 108;
          return [(v >> 8), v & 0xFF];
        } else if (v >= -1131 && v <= -108) {
          v = -v - 108;
          return [(v >> 8), v & 0xFF];
        } else if (v >= -32768 && v <= 32767) {
          return api.type.NUMBER16.make(v);
        } else {
          return api.type.NUMBER32.make(v);
        }
      }
    },

    NUMBER16: {
      make: function(v) {
        return [28, (v >> 8) & 0xFF, v & 0xFF];
      }
    },

    NUMBER32: {
      make: function(v) {
        return [29, (v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF];
      }
    },

    REAL: {
      make: function(v) {
        let value = v.toString();

        // Some numbers use an epsilon to encode the value. (e.g. JavaScript will store 0.0000001 as 1e-7)
        // This code converts it back to a number without the epsilon.
        var m = /\.(\d*?)(?:9{5,20}|0{5,20})\d{0,2}(?:e(.+)|$)/.exec(value);
        if (m) {
          var epsilon = parseFloat('1e' + ((m[2] ? +m[2] : 0) + m[1].length));
          value = (Math.round(v * epsilon) / epsilon).toString();
        }

        let nibbles = '';
        for (let i = 0, ii = value.length; i < ii; i += 1) {
          var c = value[i];
          if (c === 'e') {
            nibbles += value[++i] === '-' ? 'c' : 'b';
          } else if (c === '.') {
            nibbles += 'a';
          } else if (c === '-') {
            nibbles += 'e';
          } else {
            nibbles += c;
          }
        }

        nibbles += (nibbles.length & 1) ? 'f' : 'ff';
        var out = [30];
        for (let i = 0, ii = nibbles.length; i < ii; i += 2) {
          out.push(parseInt(nibbles.substr(i, 2), 16));
        }

        return out;
      }
    },

    DICT: {
      make: function(m) {
        let d = [];
        var keys = Object.keys(m);
        var length = keys.length;

        for (let i = 0; i < length; i += 1) {
          // Object.keys() return string keys, but our keys are always numeric.
          var k = keys[i]
          var v = m[k];
          var op = v.op
          // Value comes before the key.
          d = d.concat(api.type.OPERAND.make(v.value, v.type));
          d = d.concat(api.type.OPERATOR.make(op));
        }

        return d;
      }
    },

    OPERATOR: {
      make: function(v) {
        if (v < 1200) {
          return [v];
        } else {
          return [12, v - 1200];
        }
      }
    },

    OPERAND: {
      make: function(v, type) {
        let d = [];
        if (Array.isArray(type)) {
          for (let i = 0; i < type.length; i += 1) {
            d = d.concat(api.type.OPERAND.make(v[i], type[i]))
          }
        } else {
          if (type === 'SID') {
            d = d.concat(api.type.NUMBER.make(v))
          } else if (type === 'offset') {
            d = d.concat(api.type.NUMBER32.make(v))
          } else if (type === 'number') {
            d = d.concat(api.type.NUMBER.make(v))
          } else if (type === 'real') {
            d = d.concat(api.type.REAL.make(v))
          } else if (type === 'DELTA') {
            d = d.concat(api.type.DELTA.make(v))
          } else {
            throw new Error('Unknown operand type ' + type)
          }
        }

        return d;
      }
    }
  }
}

按照规范,我尝试将Number实现更改为看起来更合理,但输出值错误:

NUMBER: {
  make: function(v) {
    if (v >= -107 && v <= 107) {
      return [v - 139];
    } else if (v >= 108 && v <= 1131) {
      // v = v - 108;
      var b0 = v & 0xFF
      var b1 = (v >> 8) & 0xFF
      var v = (b0 - 247) * 256 + (b1 + 108)
      return [(v >> 8), v & 0xFF];
    } else if (v >= -1131 && v <= -108) {
        // v = -v - 108;
        var b0 = v & 0xFF
        var b1 = (v >> 8) & 0xFF
        v = -(b0 - 251) * 256 - b1 - 108
      return [(v >> 8), v & 0xFF];
    } else if (v >= -32768 && v <= 32767) {
      return api.type.NUMBER16.make(v);
    } else {
      return api.type.NUMBER32.make(v);
    }
  }
},

NUMBER16: {
  make: function(v) {
    var b0 = v & 0xFF
    var b1 = (v >> 8) & 0xFF
    var b2 = (v >> 16) & 0xFF
    v = b1 << 8 | b2
    return [28, (v >> 8) & 0xFF, v & 0xFF];
  }
},

NUMBER32: {
  make: function(v) {
    var b0 = v & 0xFF
    var b1 = (v >> 8) & 0xFF
    var b2 = (v >> 16) & 0xFF
    var b3 = (v >> 24) & 0xFF
    var b4 = (v >> 32) & 0xFF
    v = b1 << 24 | b2 << 16 | b3 << 8 | b4
    return [29, (v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF];
  }
}

所以我不确定如何实际计算值。如果事实证明我提供的示例代码中的原始形式是正确的,则您不介意解释如何从规范中获得有用的信息,因为我看不到连接。

0 个答案:

没有答案