private void SaveBitmapsAsFont() { // Open each bitmap, and convert pure black pixels to an array of bools List <CharInfo> charInfos = new List <CharInfo>(); foreach (FileInfo f in new DirectoryInfo(Path.Combine(Environment.CurrentDirectory, "..\\..\\..\\Sample Files\\Barcode Chars")).GetFiles()) { Bitmap png = new Bitmap(f.FullName); char thisChar = f.Name == "Asterisk.png" ? '*' : f.Name[0]; bool[,] boolVals = new bool[png.Width + 1, png.Height]; for (int y = 0; y < png.Height; y++) { for (int x = 0; x < png.Width; x++) { boolVals[x + 1, y] = png.GetPixel(x, y).GetBrightness() < 0.5; } } charInfos.Add(new CharInfo(thisChar, boolVals)); } // Create an AFP font file (BFN, FND, FNC, FNM, FNO, FNP, FNIs, FNGs, EFN) using bool arrays as FNGs BFN newBFN = new BFN("BARCOD39"); FND newFND = new FND("Code 39 Barcode", 172); ushort maxBitsWideIdx = (ushort)(charInfos.Max(c => c.BitWidth) - 1); ushort maxBitsTallIdx = (ushort)(charInfos.Max(c => c.BitHeight) - 1); int totalRasterBytes = charInfos.Sum(c => c.RoundedBitWidth * c.BitHeight); FNC newFNC = new FNC(maxBitsWideIdx, maxBitsTallIdx, totalRasterBytes); uint curFNMIndex = 0; List <FNM.PatternData> fnmPatData = new List <FNM.PatternData>(); foreach (CharInfo c in charInfos) { fnmPatData.Add(new FNM.PatternData((ushort)(c.BitWidth - 1), (ushort)(c.BitHeight - 1), curFNMIndex)); curFNMIndex += (uint)((c.RoundedBitWidth * c.BitHeight) / 8); } FNM newFNM = new FNM(fnmPatData); List <FNO.Info> fnoInfos = new List <FNO.Info>(); ushort maxCharInc = charInfos.Max(c => c.CharIncrement); for (int i = 0; i < 4; i++) { Type eType = typeof(CommonMappings.eRotations); CommonMappings.eRotations curRot = (CommonMappings.eRotations)Enum.Parse(eType, Enum.GetNames(eType)[i]); ushort curBaseline = (i == 0 || i == 2) ? (ushort)1000 : maxCharInc; ushort curCharInc = (i == 0 || i == 2) ? maxCharInc : (ushort)1000; FNO.Info.eControlFlags flags = i == 0 ? 0 : i == 1 ? FNO.Info.eControlFlags.FNI1 : i == 2 ? FNO.Info.eControlFlags.FNI2 : FNO.Info.eControlFlags.FNI3; fnoInfos.Add(new FNO.Info(curRot, (short)curBaseline, curCharInc, 0, curBaseline, flags, 1000, curCharInc, curCharInc, curBaseline, 0)); } FNO newFNO = new FNO(fnoInfos); List <FNP.Info> fnpInfos = new List <FNP.Info>(); for (int i = 0; i < 4; i++) { short curAsc = (short)((i == 0 || i == 2) ? maxCharInc : 1000); fnpInfos.Add(new FNP.Info(1000, 1000, curAsc, 0, 1000, 100)); } FNP newFNP = new FNP(fnpInfos); List <FNI> newFNIs = new List <FNI>(); for (int i = 0; i < 4; i++) { ushort fnmIndex = 0; List <FNI.Info> fniInfos = new List <FNI.Info>(); foreach (CharInfo c in charInfos) { string gid = CodePages.C1140[Converters.EBCDIC.GetBytes(new[] { c.Character })[0]]; ushort curCharInc = (ushort)((i == 0 || i == 2) ? c.CharIncrement : 1000); short curAscHeight = (short)((i == 0 || i == 2) ? 1000 : c.CharIncrement); fniInfos.Add(new FNI.Info(gid, c.CharIncrement, curAscHeight, 0, fnmIndex++, 0, curCharInc, 0, curAscHeight)); } newFNIs.Add(new FNI(fniInfos)); } List <byte> fngBytes = new List <byte>(); foreach (CharInfo c in charInfos) { for (int y = 0; y < c.BitHeight; y++) { for (int x = 0; x < c.BitWidth; x += 8) { int[] curByte = new int[1]; List <bool> bitRow = new List <bool>(); for (int i = 0; i < 8; i++) { if (c.RawBits.GetUpperBound(0) >= x + i) { bitRow.Add(c.RawBits[x + i, y]); } else { bitRow.Add(false); } } if (BitConverter.IsLittleEndian) { bitRow.Reverse(); } new BitArray(bitRow.ToArray()).CopyTo(curByte, 0); fngBytes.Add((byte)curByte[0]); } } } FNG newFNG = new FNG(fngBytes.ToArray()); EFN newEFN = new EFN(newBFN.ObjectName); string path = Path.Combine(Environment.CurrentDirectory, "..\\..\\..\\Sample Files\\FONTS\\FONTTEST"); List <StructuredField> fields = new List <StructuredField>() { newBFN, newFND, newFNC, newFNM, newFNO, newFNP }; fields.AddRange(newFNIs); fields.AddRange(new StructuredField[] { newFNG, newEFN }); List <byte> encoded = new List <byte>(); foreach (StructuredField field in fields) { encoded.Add(0x5A); encoded.AddRange(field.Introducer); encoded.AddRange(field.Data); } File.WriteAllBytes(path, encoded.ToArray()); }
private void ParseFontAndImageData() { // FONT RASTER PATTERNS Dictionary <Container, IReadOnlyDictionary <FNI.Info, bool[, ]> > rasterPatterns = new Dictionary <Container, IReadOnlyDictionary <FNI.Info, bool[, ]> >(); foreach (Container c in Resources.Where(r => r.ResourceType == Resource.eResourceType.FontCharacterSet && r.IsLoaded) .Select(r => r.Fields[0].LowestLevelContainer)) { // If we have a pattern map, gather raster data FNM patternsMap = c.GetStructure <FNM>(); if (patternsMap != null) { FNI firstFNI = c.GetStructure <FNI>(); Dictionary <FNI.Info, bool[, ]> patternsDictionary = new Dictionary <FNI.Info, bool[, ]>(); byte[] allFNGData = c.GetStructures <FNG>().SelectMany(f => f.Data).ToArray(); int indexCounter = 0; for (int i = 0; i < patternsMap.AllPatternData.Count; i++) { // Subtract the next offset (or length of data if at end) by this one to find out how many bytes to take int bytesToTake = (int)((i < patternsMap.AllPatternData.Count - 1 ? patternsMap.AllPatternData[i + 1].DataOffset : (uint)allFNGData.Length) - patternsMap.AllPatternData[i].DataOffset); // Create an empty array of bools from our box width and height // The array sizes are the number of bits in the minimum number of bytes required to support the bit size int numBitsWide = (int)Math.Ceiling((patternsMap.AllPatternData[i].BoxMaxWidthIndex + 1) / 8.0) * 8; int numRows = bytesToTake / (numBitsWide / 8); bool[,] curPattern = new bool[numBitsWide, numRows]; for (int y = 0; y < numRows; y++) { for (int x = 0; x < numBitsWide; x += 8) { byte curByte = allFNGData[indexCounter++]; for (int b = 0; b < 8; b++) { curPattern[x + b, y] = (curByte & (1 << (7 - b))) > 0; } } } // Lookup the GCGID from the first FNI for this pattern patternsDictionary.Add(firstFNI.InfoList.First(fni => fni.FNMIndex == i), curPattern); } rasterPatterns.Add(c, patternsDictionary); } } ParsedFontPatterns = rasterPatterns; // IM IMAGES Dictionary <Container, IReadOnlyList <IMImageCell> > imImages = new Dictionary <Container, IReadOnlyList <IMImageCell> >(); foreach (Container c in Resources .Where(r => r.IsLoaded && (r.ResourceType == Resource.eResourceType.IMImage || (r.ResourceType == Resource.eResourceType.PageSegment && r.Fields[1] is BII))) .Select(r => r.ResourceType == Resource.eResourceType.PageSegment ? r.Fields[1].LowestLevelContainer : r.Fields[0].LowestLevelContainer)) { IID imageDescriptor = c.GetStructure <IID>(); List <IMImageCell> cellList = new List <IMImageCell>(); if (c.GetStructure <ICP>() == null) { // Since there are no cells, create one ICP newCellPos = new ICP(imageDescriptor.XSize, imageDescriptor.YSize); IMImageCell newCell = new IMImageCell(newCellPos, c.GetStructures <IRD>()); cellList.Add(newCell); } else { // Manually parse a list of cells since they don't have their own container for (int i = 0; i < c.Structures.Count; i++) { if (c.Structures[i].GetType() != typeof(ICP)) { continue; } // Get list of IRDs up to the next ICP or end of structures List <IRD> rasterData = new List <IRD>(); for (int r = i + 1; r < c.Structures.Count; r++) { if (c.Structures[r].GetType() != typeof(IRD)) { break; } rasterData.Add((IRD)c.Structures[r]); } cellList.Add(new IMImageCell((ICP)c.Structures[i], rasterData)); } } imImages.Add(c, cellList); } ParsedIMImages = imImages; // IOCA IMAGES Dictionary <Container, IReadOnlyList <ImageInfo> > iocaImages = new Dictionary <Container, IReadOnlyList <ImageInfo> >(); foreach (Container c in Resources .Where(r => r.IsLoaded && (r.ResourceType == Resource.eResourceType.IOCAImage || (r.ResourceType == Resource.eResourceType.PageSegment && r.Fields[1] is BIM))) .Select(r => r.ResourceType == Resource.eResourceType.PageSegment ? r.Fields[1].LowestLevelContainer : r.Fields[0].LowestLevelContainer)) { // Combine all self defining fields from zero or more IPD fields byte[] allIPDData = c.GetStructures <IPD>().SelectMany(f => f.Data).ToArray(); List <ImageSelfDefiningField> SDFs = ImageSelfDefiningField.GetAllSDFs(allIPDData); // Get all images in our self defining field list foreach (Container sc in SDFs.OfType <BeginImageContent>().Select(s => s.LowestLevelContainer)) { List <Container> allContainers = new List <Container>() { sc }; List <ImageInfo> infoList = new List <ImageInfo>(); // Along with ourself, add any tiles to the list of containers if (sc.Structures.Any(s => s.GetType() == typeof(BeginTile))) { allContainers.AddRange(sc.Structures.OfType <BeginTile>().Select(s => s.LowestLevelContainer)); } // For each container, get image and transparency bytes foreach (Container tc in allContainers) { ImageInfo info = new ImageInfo(); info.Data = tc.DirectGetStructures <ImageData>().SelectMany(s => s.Data).ToArray(); // If there are tiles, store offset information if (tc.Structures[0].GetType() == typeof(BeginTile)) { TilePosition tp = tc.GetStructure <TilePosition>(); info.XOffset = tp.XOffset; info.YOffset = tp.YOffset; } // Add transparency data if needed ImageSelfDefiningField BTM = tc.GetStructure <BeginTransparencyMask>(); if (BTM != null) { info.TransparencyMask = BTM.LowestLevelContainer.GetStructures <ImageData>().SelectMany(s => s.Data).ToArray(); } infoList.Add(info); } iocaImages.Add(c, infoList); } } ParsedImages = iocaImages; }