/// <summary>
/// Encodes the specified content.
/// </summary>
/// <param name="content">The content.</param>
/// <param name="ecLevel">The ec level.</param>
/// <param name="hints">The hints.</param>
/// <returns></returns>
public static QRCode encode(String content,
ErrorCorrectionLevel ecLevel,
IDictionary <EncodeHintType, object> hints)
{
// Determine what character encoding has been specified by the caller, if any
#if !SILVERLIGHT || WINDOWS_PHONE
String encoding = hints == null || !hints.ContainsKey(EncodeHintType.CHARACTER_SET) ? null : (String)hints[EncodeHintType.CHARACTER_SET];
if (encoding == null)
{
encoding = DEFAULT_BYTE_MODE_ENCODING;
}
bool generateECI = !DEFAULT_BYTE_MODE_ENCODING.Equals(encoding);
#else
// Silverlight supports only UTF-8 and UTF-16 out-of-the-box
const string encoding = "UTF-8";
// caller of the method can only control if the ECI segment should be written
// character set is fixed to UTF-8; but some scanners doesn't like the ECI segment
bool generateECI = (hints != null && hints.ContainsKey(EncodeHintType.CHARACTER_SET));
#endif
// Pick an encoding mode appropriate for the content. Note that this will not attempt to use
// multiple modes / segments even if that were more efficient. Twould be nice.
Mode mode = chooseMode(content, encoding);
// This will store the header information, like mode and
// length, as well as "header" segments like an ECI segment.
BitArray headerBits = new BitArray();
// Append ECI segment if applicable
if (mode == Mode.BYTE && generateECI)
{
CharacterSetECI eci = CharacterSetECI.getCharacterSetECIByName(encoding);
if (eci != null)
{
var eciIsExplicitDisabled = (hints != null && hints.ContainsKey(EncodeHintType.DISABLE_ECI) && hints[EncodeHintType.DISABLE_ECI] != null && Convert.ToBoolean(hints[EncodeHintType.DISABLE_ECI].ToString()));
if (!eciIsExplicitDisabled)
{
appendECI(eci, headerBits);
}
}
}
// (With ECI in place,) Write the mode marker
appendModeInfo(mode, headerBits);
// Collect data within the main segment, separately, to count its size if needed. Don't add it to
// main payload yet.
BitArray dataBits = new BitArray();
appendBytes(content, mode, dataBits, encoding);
// Hard part: need to know version to know how many bits length takes. But need to know how many
// bits it takes to know version. First we take a guess at version by assuming version will be
// the minimum, 1:
int provisionalBitsNeeded = headerBits.Size
+ mode.getCharacterCountBits(Version.getVersionForNumber(1))
+ dataBits.Size;
Version provisionalVersion = chooseVersion(provisionalBitsNeeded, ecLevel);
// Use that guess to calculate the right version. I am still not sure this works in 100% of cases.
int bitsNeeded = headerBits.Size
+ mode.getCharacterCountBits(provisionalVersion)
+ dataBits.Size;
Version version = chooseVersion(bitsNeeded, ecLevel);
BitArray headerAndDataBits = new BitArray();
headerAndDataBits.appendBitArray(headerBits);
// Find "length" of main segment and write it
int numLetters = mode == Mode.BYTE ? dataBits.SizeInBytes : content.Length;
appendLengthInfo(numLetters, version, mode, headerAndDataBits);
// Put data together into the overall payload
headerAndDataBits.appendBitArray(dataBits);
Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel);
int numDataBytes = version.TotalCodewords - ecBlocks.TotalECCodewords;
// Terminate the bits properly.
terminateBits(numDataBytes, headerAndDataBits);
// Interleave data bits with error correction code.
BitArray finalBits = interleaveWithECBytes(headerAndDataBits,
version.TotalCodewords,
numDataBytes,
ecBlocks.NumBlocks);
QRCode qrCode = new QRCode
{
ECLevel = ecLevel,
Mode = mode,
Version = version
};
// Choose the mask pattern and set to "qrCode".
int dimension = version.DimensionForVersion;
ByteMatrix matrix = new ByteMatrix(dimension, dimension);
int maskPattern = chooseMaskPattern(finalBits, ecLevel, version, matrix);
qrCode.MaskPattern = maskPattern;
// Build the matrix and set it to "qrCode".
MatrixUtil.buildMatrix(finalBits, ecLevel, version, maskPattern, matrix);
qrCode.Matrix = matrix;
return(qrCode);
}