Open Source Repository

Home /itextpdf/itextpdf-5.1.2 | Repository Home



com/itextpdf/text/pdf/qrcode/Version.java
/*
 * Copyright 2007 ZXing authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.itextpdf.text.pdf.qrcode;

/**
 * See ISO 18004:2006 Annex D
 *
 @author Sean Owen
 @since 5.0.2
 */
public final class Version {

  /**
   * See ISO 18004:2006 Annex D.
   * Element i represents the raw version bits that specify version i + 7
   */
  private static final int[] VERSION_DECODE_INFO = {
      0x07C940x085BC0x09A990x0A4D30x0BBF6,
      0x0C7620x0D8470x0E60D0x0F9280x10B78,
      0x1145D0x12A170x135320x149A60x15683,
      0x168C90x177EC0x18EC40x191E10x1AFAB,
      0x1B08E0x1CC1A0x1D33F0x1ED750x1F250,
      0x209D50x216F00x228BA0x2379F0x24B0B,
      0x2542E0x26A640x275410x28C69
  };

  private static final Version[] VERSIONS = buildVersions();

  private final int versionNumber;
  private final int[] alignmentPatternCenters;
  private final ECBlocks[] ecBlocks;
  private final int totalCodewords;

  private Version(int versionNumber,
                  int[] alignmentPatternCenters,
                  ECBlocks ecBlocks1,
                  ECBlocks ecBlocks2,
                  ECBlocks ecBlocks3,
                  ECBlocks ecBlocks4) {
    this.versionNumber = versionNumber;
    this.alignmentPatternCenters = alignmentPatternCenters;
    this.ecBlocks = new ECBlocks[]{ecBlocks1, ecBlocks2, ecBlocks3, ecBlocks4};
    int total = 0;
    int ecCodewords = ecBlocks1.getECCodewordsPerBlock();
    ECB[] ecbArray = ecBlocks1.getECBlocks();
    for (int i = 0; i < ecbArray.length; i++) {
      ECB ecBlock = ecbArray[i];
      total += ecBlock.getCount() (ecBlock.getDataCodewords() + ecCodewords);
    }
    this.totalCodewords = total;
  }

  public int getVersionNumber() {
    return versionNumber;
  }

  public int[] getAlignmentPatternCenters() {
    return alignmentPatternCenters;
  }

  public int getTotalCodewords() {
    return totalCodewords;
  }

  public int getDimensionForVersion() {
    return 17 * versionNumber;
  }

  public ECBlocks getECBlocksForLevel(ErrorCorrectionLevel ecLevel) {
    return ecBlocks[ecLevel.ordinal()];
  }

  /**
   <p>Deduces version information purely from QR Code dimensions.</p>
   *
   @param dimension dimension in modules
   @return {@link Version} for a QR Code of that dimension
   @throws FormatException if dimension is not 1 mod 4
   */
  public static Version getProvisionalVersionForDimension(int dimension) {
    if (dimension % != 1) {
      throw new IllegalArgumentException();
    }
    try {
      return getVersionForNumber((dimension - 17>> 2);
    catch (IllegalArgumentException iae) {
      throw iae;
    }
  }

  public static Version getVersionForNumber(int versionNumber) {
    if (versionNumber < || versionNumber > 40) {
      throw new IllegalArgumentException();
    }
    return VERSIONS[versionNumber - 1];
  }

  static Version decodeVersionInformation(int versionBits) {
    int bestDifference = Integer.MAX_VALUE;
    int bestVersion = 0;
    for (int i = 0; i < VERSION_DECODE_INFO.length; i++) {
      int targetVersion = VERSION_DECODE_INFO[i];
      // Do the version info bits match exactly? done.
      if (targetVersion == versionBits) {
        return getVersionForNumber(i + 7);
      }
      // Otherwise see if this is the closest to a real version info bit string
      // we have seen so far
      int bitsDifference = FormatInformation.numBitsDiffering(versionBits, targetVersion);
      if (bitsDifference < bestDifference) {
        bestVersion = i + 7;
        bestDifference = bitsDifference;
      }
    }
    // We can tolerate up to 3 bits of error since no two version info codewords will
    // differ in less than 4 bits.
    if (bestDifference <= 3) {
      return getVersionForNumber(bestVersion);
    }
    // If we didn't find a close enough match, fail
    return null;
  }

  /**
   * See ISO 18004:2006 Annex E
   */
  BitMatrix buildFunctionPattern() {
    int dimension = getDimensionForVersion();
    BitMatrix bitMatrix = new BitMatrix(dimension);

    // Top left finder pattern + separator + format
    bitMatrix.setRegion(0099);
    // Top right finder pattern + separator + format
    bitMatrix.setRegion(dimension - 8089);
    // Bottom left finder pattern + separator + format
    bitMatrix.setRegion(0, dimension - 898);

    // Alignment patterns
    int max = alignmentPatternCenters.length;
    for (int x = 0; x < max; x++) {
      int i = alignmentPatternCenters[x2;
      for (int y = 0; y < max; y++) {
        if ((x == && (y == || y == max - 1)) || (x == max - && y == 0)) {
          // No alignment patterns near the three finder paterns
          continue;
        }
        bitMatrix.setRegion(alignmentPatternCenters[y2, i, 55);
      }
    }

    // Vertical timing pattern
    bitMatrix.setRegion(691, dimension - 17);
    // Horizontal timing pattern
    bitMatrix.setRegion(96, dimension - 171);

    if (versionNumber > 6) {
      // Version info, top right
      bitMatrix.setRegion(dimension - 11036);
      // Version info, bottom left
      bitMatrix.setRegion(0, dimension - 1163);
    }

    return bitMatrix;
  }

  /**
   <p>Encapsulates a set of error-correction blocks in one symbol version. Most versions will
   * use blocks of differing sizes within one version, so, this encapsulates the parameters for
   * each set of blocks. It also holds the number of error-correction codewords per block since it
   * will be the same across all blocks within one version.</p>
   */
  public static final class ECBlocks {
    private final int ecCodewordsPerBlock;
    private final ECB[] ecBlocks;

    ECBlocks(int ecCodewordsPerBlock, ECB ecBlocks) {
      this.ecCodewordsPerBlock = ecCodewordsPerBlock;
      this.ecBlocks = new ECB[]{ecBlocks};
    }

    ECBlocks(int ecCodewordsPerBlock, ECB ecBlocks1, ECB ecBlocks2) {
      this.ecCodewordsPerBlock = ecCodewordsPerBlock;
      this.ecBlocks = new ECB[]{ecBlocks1, ecBlocks2};
    }

    public int getECCodewordsPerBlock() {
      return ecCodewordsPerBlock;
    }

    public int getNumBlocks() {
      int total = 0;
      for (int i = 0; i < ecBlocks.length; i++) {
        total += ecBlocks[i].getCount();
      }
      return total;
    }

    public int getTotalECCodewords() {
      return ecCodewordsPerBlock * getNumBlocks();
    }

    public ECB[] getECBlocks() {
      return ecBlocks;
    }
  }

  /**
   <p>Encapsualtes the parameters for one error-correction block in one symbol version.
   * This includes the number of data codewords, and the number of times a block with these
   * parameters is used consecutively in the QR code version's format.</p>
   */
  public static final class ECB {
    private final int count;
    private final int dataCodewords;

    ECB(int count, int dataCodewords) {
      this.count = count;
      this.dataCodewords = dataCodewords;
    }

    public int getCount() {
      return count;
    }

    public int getDataCodewords() {
      return dataCodewords;
    }
  }

  public String toString() {
    return String.valueOf(versionNumber);
  }

  /**
   * See ISO 18004:2006 6.5.1 Table 9
   */
  private static Version[] buildVersions() {
    return new Version[]{
        new Version(1new int[]{},
            new ECBlocks(7new ECB(119)),
            new ECBlocks(10new ECB(116)),
            new ECBlocks(13new ECB(113)),
            new ECBlocks(17new ECB(19))),
        new Version(2new int[]{618},
            new ECBlocks(10new ECB(134)),
            new ECBlocks(16new ECB(128)),
            new ECBlocks(22new ECB(122)),
            new ECBlocks(28new ECB(116))),
        new Version(3new int[]{622},
            new ECBlocks(15new ECB(155)),
            new ECBlocks(26new ECB(144)),
            new ECBlocks(18new ECB(217)),
            new ECBlocks(22new ECB(213))),
        new Version(4new int[]{626},
            new ECBlocks(20new ECB(180)),
            new ECBlocks(18new ECB(232)),
            new ECBlocks(26new ECB(224)),
            new ECBlocks(16new ECB(49))),
        new Version(5new int[]{630},
            new ECBlocks(26new ECB(1108)),
            new ECBlocks(24new ECB(243)),
            new ECBlocks(18new ECB(215),
                new ECB(216)),
            new ECBlocks(22new ECB(211),
                new ECB(212))),
        new Version(6new int[]{634},
            new ECBlocks(18new ECB(268)),
            new ECBlocks(16new ECB(427)),
            new ECBlocks(24new ECB(419)),
            new ECBlocks(28new ECB(415))),
        new Version(7new int[]{62238},
            new ECBlocks(20new ECB(278)),
            new ECBlocks(18new ECB(431)),
            new ECBlocks(18new ECB(214),
                new ECB(415)),
            new ECBlocks(26new ECB(413),
                new ECB(114))),
        new Version(8new int[]{62442},
            new ECBlocks(24new ECB(297)),
            new ECBlocks(22new ECB(238),
                new ECB(239)),
            new ECBlocks(22new ECB(418),
                new ECB(219)),
            new ECBlocks(26new ECB(414),
                new ECB(215))),
        new Version(9new int[]{62646},
            new ECBlocks(30new ECB(2116)),
            new ECBlocks(22new ECB(336),
                new ECB(237)),
            new ECBlocks(20new ECB(416),
                new ECB(417)),
            new ECBlocks(24new ECB(412),
                new ECB(413))),
        new Version(10new int[]{62850},
            new ECBlocks(18new ECB(268),
                new ECB(269)),
            new ECBlocks(26new ECB(443),
                new ECB(144)),
            new ECBlocks(24new ECB(619),
                new ECB(220)),
            new ECBlocks(28new ECB(615),
                new ECB(216))),
        new Version(11new int[]{63054},
            new ECBlocks(20new ECB(481)),
            new ECBlocks(30new ECB(150),
                new ECB(451)),
            new ECBlocks(28new ECB(422),
                new ECB(423)),
            new ECBlocks(24new ECB(312),
                new ECB(813))),
        new Version(12new int[]{63258},
            new ECBlocks(24new ECB(292),
                new ECB(293)),
            new ECBlocks(22new ECB(636),
                new ECB(237)),
            new ECBlocks(26new ECB(420),
                new ECB(621)),
            new ECBlocks(28new ECB(714),
                new ECB(415))),
        new Version(13new int[]{63462},
            new ECBlocks(26new ECB(4107)),
            new ECBlocks(22new ECB(837),
                new ECB(138)),
            new ECBlocks(24new ECB(820),
                new ECB(421)),
            new ECBlocks(22new ECB(1211),
                new ECB(412))),
        new Version(14new int[]{6264666},
            new ECBlocks(30new ECB(3115),
                new ECB(1116)),
            new ECBlocks(24new ECB(440),
                new ECB(541)),
            new ECBlocks(20new ECB(1116),
                new ECB(517)),
            new ECBlocks(24new ECB(1112),
                new ECB(513))),
        new Version(15new int[]{6264870},
            new ECBlocks(22new ECB(587),
                new ECB(188)),
            new ECBlocks(24new ECB(541),
                new ECB(542)),
            new ECBlocks(30new ECB(524),
                new ECB(725)),
            new ECBlocks(24new ECB(1112),
                new ECB(713))),
        new Version(16new int[]{6265074},
            new ECBlocks(24new ECB(598),
                new ECB(199)),
            new ECBlocks(28new ECB(745),
                new ECB(346)),
            new ECBlocks(24new ECB(1519),
                new ECB(220)),
            new ECBlocks(30new ECB(315),
                new ECB(1316))),
        new Version(17new int[]{6305478},
            new ECBlocks(28new ECB(1107),
                new ECB(5108)),
            new ECBlocks(28new ECB(1046),
                new ECB(147)),
            new ECBlocks(28new ECB(122),
                new ECB(1523)),
            new ECBlocks(28new ECB(214),
                new ECB(1715))),
        new Version(18new int[]{6305682},
            new ECBlocks(30new ECB(5120),
                new ECB(1121)),
            new ECBlocks(26new ECB(943),
                new ECB(444)),
            new ECBlocks(28new ECB(1722),
                new ECB(123)),
            new ECBlocks(28new ECB(214),
                new ECB(1915))),
        new Version(19new int[]{6305886},
            new ECBlocks(28new ECB(3113),
                new ECB(4114)),
            new ECBlocks(26new ECB(344),
                new ECB(1145)),
            new ECBlocks(26new ECB(1721),
                new ECB(422)),
            new ECBlocks(26new ECB(913),
                new ECB(1614))),
        new Version(20new int[]{6346290},
            new ECBlocks(28new ECB(3107),
                new ECB(5108)),
            new ECBlocks(26new ECB(341),
                new ECB(1342)),
            new ECBlocks(30new ECB(1524),
                new ECB(525)),
            new ECBlocks(28new ECB(1515),
                new ECB(1016))),
        new Version(21new int[]{628507294},
            new ECBlocks(28new ECB(4116),
                new ECB(4117)),
            new ECBlocks(26new ECB(1742)),
            new ECBlocks(28new ECB(1722),
                new ECB(623)),
            new ECBlocks(30new ECB(1916),
                new ECB(617))),
        new Version(22new int[]{626507498},
            new ECBlocks(28new ECB(2111),
                new ECB(7112)),
            new ECBlocks(28new ECB(1746)),
            new ECBlocks(30new ECB(724),
                new ECB(1625)),
            new ECBlocks(24new ECB(3413))),
        new Version(23new int[]{6305474102},
            new ECBlocks(30new ECB(4121),
                new ECB(5122)),
            new ECBlocks(28new ECB(447),
                new ECB(1448)),
            new ECBlocks(30new ECB(1124),
                new ECB(1425)),
            new ECBlocks(30new ECB(1615),
                new ECB(1416))),
        new Version(24new int[]{6285480106},
            new ECBlocks(30new ECB(6117),
                new ECB(4118)),
            new ECBlocks(28new ECB(645),
                new ECB(1446)),
            new ECBlocks(30new ECB(1124),
                new ECB(1625)),
            new ECBlocks(30new ECB(3016),
                new ECB(217))),
        new Version(25new int[]{6325884110},
            new ECBlocks(26new ECB(8106),
                new ECB(4107)),
            new ECBlocks(28new ECB(847),
                new ECB(1348)),
            new ECBlocks(30new ECB(724),
                new ECB(2225)),
            new ECBlocks(30new ECB(2215),
                new ECB(1316))),
        new Version(26new int[]{6305886114},
            new ECBlocks(28new ECB(10114),
                new ECB(2115)),
            new ECBlocks(28new ECB(1946),
                new ECB(447)),
            new ECBlocks(28new ECB(2822),
                new ECB(623)),
            new ECBlocks(30new ECB(3316),
                new ECB(417))),
        new Version(27new int[]{6346290118},
            new ECBlocks(30new ECB(8122),
                new ECB(4123)),
            new ECBlocks(28new ECB(2245),
                new ECB(346)),
            new ECBlocks(30new ECB(823),
                new ECB(2624)),
            new ECBlocks(30new ECB(1215),
                new ECB(2816))),
        new Version(28new int[]{626507498122},
            new ECBlocks(30new ECB(3117),
                new ECB(10118)),
            new ECBlocks(28new ECB(345),
                new ECB(2346)),
            new ECBlocks(30new ECB(424),
                new ECB(3125)),
            new ECBlocks(30new ECB(1115),
                new ECB(3116))),
        new Version(29new int[]{6305478102126},
            new ECBlocks(30new ECB(7116),
                new ECB(7117)),
            new ECBlocks(28new ECB(2145),
                new ECB(746)),
            new ECBlocks(30new ECB(123),
                new ECB(3724)),
            new ECBlocks(30new ECB(1915),
                new ECB(2616))),
        new Version(30new int[]{6265278104130},
            new ECBlocks(30new ECB(5115),
                new ECB(10116)),
            new ECBlocks(28new ECB(1947),
                new ECB(1048)),
            new ECBlocks(30new ECB(1524),
                new ECB(2525)),
            new ECBlocks(30new ECB(2315),
                new ECB(2516))),
        new Version(31new int[]{6305682108134},
            new ECBlocks(30new ECB(13115),
                new ECB(3116)),
            new ECBlocks(28new ECB(246),
                new ECB(2947)),
            new ECBlocks(30new ECB(4224),
                new ECB(125)),
            new ECBlocks(30new ECB(2315),
                new ECB(2816))),
        new Version(32new int[]{6346086112138},
            new ECBlocks(30new ECB(17115)),
            new ECBlocks(28new ECB(1046),
                new ECB(2347)),
            new ECBlocks(30new ECB(1024),
                new ECB(3525)),
            new ECBlocks(30new ECB(1915),
                new ECB(3516))),
        new Version(33new int[]{6305886114142},
            new ECBlocks(30new ECB(17115),
                new ECB(1116)),
            new ECBlocks(28new ECB(1446),
                new ECB(2147)),
            new ECBlocks(30new ECB(2924),
                new ECB(1925)),
            new ECBlocks(30new ECB(1115),
                new ECB(4616))),
        new Version(34new int[]{6346290118146},
            new ECBlocks(30new ECB(13115),
                new ECB(6116)),
            new ECBlocks(28new ECB(1446),
                new ECB(2347)),
            new ECBlocks(30new ECB(4424),
                new ECB(725)),
            new ECBlocks(30new ECB(5916),
                new ECB(117))),
        new Version(35new int[]{6305478102126150},
            new ECBlocks(30new ECB(12121),
                new ECB(7122)),
            new ECBlocks(28new ECB(1247),
                new ECB(2648)),
            new ECBlocks(30new ECB(3924),
                new ECB(1425)),
            new ECBlocks(30new ECB(2215),
                new ECB(4116))),
        new Version(36new int[]{6245076102128154},
            new ECBlocks(30new ECB(6121),
                new ECB(14122)),
            new ECBlocks(28new ECB(647),
                new ECB(3448)),
            new ECBlocks(30new ECB(4624),
                new ECB(1025)),
            new ECBlocks(30new ECB(215),
                new ECB(6416))),
        new Version(37new int[]{6285480106132158},
            new ECBlocks(30new ECB(17122),
                new ECB(4123)),
            new ECBlocks(28new ECB(2946),
                new ECB(1447)),
            new ECBlocks(30new ECB(4924),
                new ECB(1025)),
            new ECBlocks(30new ECB(2415),
                new ECB(4616))),
        new Version(38new int[]{6325884110136162},
            new ECBlocks(30new ECB(4122),
                new ECB(18123)),
            new ECBlocks(28new ECB(1346),
                new ECB(3247)),
            new ECBlocks(30new ECB(4824),
                new ECB(1425)),
            new ECBlocks(30new ECB(4215),
                new ECB(3216))),
        new Version(39new int[]{6265482110138166},
            new ECBlocks(30new ECB(20117),
                new ECB(4118)),
            new ECBlocks(28new ECB(4047),
                new ECB(748)),
            new ECBlocks(30new ECB(4324),
                new ECB(2225)),
            new ECBlocks(30new ECB(1015),
                new ECB(6716))),
        new Version(40new int[]{6305886114142170},
            new ECBlocks(30new ECB(19118),
                new ECB(6119)),
            new ECBlocks(28new ECB(1847),
                new ECB(3148)),
            new ECBlocks(30new ECB(3424),
                new ECB(3425)),
            new ECBlocks(30new ECB(2015),
                new ECB(6116)))
    };
  }

}