private void SetCodePageAndFont(SCFL sfcl) { curCodePage = string.Empty; curFontCharSet = string.Empty; MCF1 map1 = aeContainer.GetStructure <MCF1>(); // MCF2 is not supported yet... if (map1 != null) { // Get mapping info with the ID specified in the SCFL field MCF1.MCF1Data mcfData = map1.MappedData.FirstOrDefault(m => m.ID == sfcl.FontId); if (mcfData != null) { // If it already has a code page/font character set specified, use that. if (!string.IsNullOrWhiteSpace(mcfData.CodePageName) && !string.IsNullOrWhiteSpace(mcfData.FontCharacterSetName)) { curCodePage = mcfData.CodePageName; curFontCharSet = mcfData.FontCharacterSetName; } else { // Otherwise, we need to load it from the coded font resource Resource codedFont = afpFile.Resources.OfTypeAndName(Resource.eResourceType.CodedFont, mcfData.CodedFontName); if (codedFont.IsLoaded) { CFI cfi = codedFont.Fields.OfType <CFI>().FirstOrDefault(); if (cfi != null && cfi.FontInfoList.Any()) { curCodePage = cfi.FontInfoList[0].CodePageName; curFontCharSet = cfi.FontInfoList[0].FontCharacterSetName; } } } } } if (!string.IsNullOrWhiteSpace(curFontCharSet)) { curFontCharSetResource = afpFile.Resources.OfTypeAndName(Resource.eResourceType.FontCharacterSet, curFontCharSet); } }
private void RefreshGraphicCharactersCache() { // Do nothing if the images are already cached if (fontCaches.Any()) { return; } curCodePage = ""; curFontCharSet = ""; // On every page, store a unique list of every used code point, as well as associated font information foreach (Container pc in pageContainers) { foreach (PTX ptx in pc.GetStructures <PTX>()) { foreach (PTXControlSequence cs in ptx.ControlSequences) { // Store active code page and coded font if (cs.GetType() == typeof(SCFL)) { // Lookup info from MCF1 data on this page MCF1.MCF1Data mcfData = pc.GetStructure <MCF1>()?.MappedData.First(m => m.ID == ((SCFL)cs).FontId); // If we have a coded font, we need to load that resource. Otherwise, get the values from here if (mcfData != null) { Resource codedFontResource = afpFile.Resources.OfTypeAndName(Resource.eResourceType.CodedFont, mcfData.CodedFontName); CFI resourceCFI = codedFontResource != null && codedFontResource.IsLoaded ? codedFontResource.Fields.OfType <CFI>().FirstOrDefault() : null; if (resourceCFI != null && resourceCFI.FontInfoList.Any()) { // Get the code page and font char set from the resource curCodePage = resourceCFI.FontInfoList[0].CodePageName; curFontCharSet = resourceCFI.FontInfoList[0].FontCharacterSetName; } else { // Store mcf's code page and font char set specifiers curCodePage = mcfData.CodePageName; curFontCharSet = mcfData.FontCharacterSetName; } } } else if (cs.GetType() == typeof(TRN)) { foreach (byte b in cs.Data) { // Add a new font cache item if this exact combo (byte/code page/char set) does not yet exist if (!fontCaches.Any(f => f.CodePoint == b && f.CodePage == curCodePage && f.FontCharSet == curFontCharSet)) { fontCaches.Add(new FontCache(b, curCodePage, curFontCharSet)); } } } } } } // For each byte/code point/font, generate a bitmap by looking up its resource curCodePage = ""; curFontCharSet = ""; Dictionary <byte, string> cpMappings = CodePages.C1252; Resource fontResource = null; Container foc = null; float emInchSize = 0; byte vsc = 0; foreach (FontCache fc in fontCaches.OrderBy(f => f.CodePage).ThenBy(f => f.FontCharSet)) { // Generate new code page mappings if needed if (fc.CodePage != curCodePage) { cpMappings = new Dictionary <byte, string>(); // If the code page is a resource, generate from scratch Resource cp = afpFile.Resources.OfTypeAndName(Resource.eResourceType.CodePage, fc.CodePage); if (cp != null && cp.IsLoaded) { foreach (CPI.Info info in cp.Fields.OfType <CPI>().First().CPIInfos) { cpMappings.Add(info.CodePoints[0], info.GID); } // Is variable space char if the byte equals the one specified by the code page descriptor vsc = cp.Fields.OfType <CPC>().First().VariableSpaceCharacter; } // Else, get by looking up last 4 page digits else { // Get probably name of static field in Code Pages lookups string sectionedCodePage = string.Empty; if (fc.CodePage.Length >= 4) { sectionedCodePage = $"C{fc.CodePage.Substring(fc.CodePage.Length - 4)}"; } // Find the matching lookup method in our code page helper class FieldInfo field = typeof(CodePages).GetField(sectionedCodePage); if (field != null) { cpMappings = (Dictionary <byte, string>)field.GetValue(null); } // Is variable space character if the byte GID equals SP010000 vsc = cpMappings.First(c => c.Value == "SP010000").Key; } curCodePage = fc.CodePage; } // Lookup new font character set if needed if (fc.FontCharSet != curFontCharSet) { fontResource = afpFile.Resources.OfTypeAndName(Resource.eResourceType.FontCharacterSet, fc.FontCharSet); curFontCharSet = fc.FontCharSet; foc = fontResource.Fields[0].LowestLevelContainer; emInchSize = foc.GetStructure <FND>().EmInches; } // Generate a bitmap for this code point by looking up the raster pattern of the FCS by current code page string gid = cpMappings.ContainsKey(fc.CodePoint) ? cpMappings[fc.CodePoint] : string.Empty; if (!string.IsNullOrEmpty(gid) && fontResource != null && fontResource.IsLoaded && afpFile.ParsedFontPatterns.ContainsKey(foc)) { // Get raster pattern info of GID KeyValuePair <FNI.Info, bool[, ]> pattern = afpFile.ParsedFontPatterns[foc].FirstOrDefault(p => p.Key.GCGID == gid); // Build bitmap if (pattern.Key != null) { // Set font and variable space info here fc.FontInfo = pattern.Key; fc.IsVariableSpaceChar = fc.CodePoint == vsc; fc.EmInchSize = emInchSize; Bitmap bmp = new Bitmap(pattern.Value.GetUpperBound(0) + 1, pattern.Value.GetUpperBound(1) + 1); for (int y = 0; y < bmp.Height; y++) { for (int x = 0; x < bmp.Width; x++) { if (pattern.Value[x, y]) { bmp.SetPixel(x, y, Color.Black); // Set to black - we remap colors later } } } // Since we know how many inches 1 em is, we can determine inch width and height of each character float heightInches = emInchSize * ((pattern.Key.AscenderHeight + pattern.Key.DescenderDepth) / 1000f); float dpi = (float)Math.Round(bmp.Height / heightInches); bmp.SetResolution(dpi, dpi); // Assign to font cache fc.Pattern = bmp; } } } }