
ãã®ãããã¿ã¹ã¯ã®1ã€ã¯ãã¯ãŒãã³ã¹ãã£ã³ã·ãŒãã®æ°åãèªèããããšã§ããã ããã€ãã®ã¯ãŒãã³ãããå ŽåããããããããåçŽããã³æ°Žå¹³ã®äž¡æ¹ã§ã·ãŒãã«é 眮ã§ããããšã«æ³šæãã䟡å€ããããŸãã
ã¯ãŒãã³ã¹ãã£ã³ã§èŠããã®ã¯ãä»ã®ãããžã§ã¯ãã§æ¢ã«ééããCodabarããŒã³ãŒããšéåžžã«äŒŒãŠããŸããã

Codabarã¯ç·åœ¢ããŒã³ãŒãã§ãã åæåã¯ã4ã€ã®è¡ãšãããã®éã®3ã€ã®ã¹ããŒã¹ã®7ã€ã®èŠçŽ ã§ãšã³ã³ãŒããããŸãã ãããã®éã§ãæåã¯è¿œå ã®ã¹ããŒã¹ã§åºåãããŸãã Codabarã¯éå§æåã§å§ãŸããåæ¢æåã§çµãããŸãã éå§èšå·ãŸãã¯åæ¢èšå·ã¯ãååãšããŠABCDèšå·ã§ãã åèïŒ0-9ã-ã$ã
ãããã£ãŠããã®ããŒã³ãŒãã«ã¯ãåæåãè¡ãšã¹ããŒã¹ã®ç¹å®ã®ã·ãŒã±ã³ã¹ã«å¯Ÿå¿ããã¢ã«ãã¡ãããããããŸãã

åçã¯ãå€ã401ããå«ãCodabar'aã®äŸã瀺ããŠããŸãã
Zxing
.NETã§ããŒã³ãŒãã䜿çšããå Žåã 移æ€çã®Zxingã©ã€ãã©ãªã䜿çšããŸã ã ã©ã€ãã©ãªã¯ãQRã³ãŒããPDF 417ãEANãUPCãAztecãããŒã¿ãããªãã¯ã¹ãªã©ãããããçš®é¡ã®1Dããã³2DããŒã³ãŒããçæããã³èªèã§ããŸãã ãããŠæãéèŠãªããšãšããŠã圌女ã¯Codabarãšã®é£æºæ¹æ³ãç¥ã£ãŠããŸãã éåžžãZxingã©ã€ãã©ãªã䜿çšããŠãåé¡ã¯çºçãããããŸããŸãªãã©ãããã©ãŒã ã§äœ¿çšããŸããã ããããããŒã³ãŒãZxingã¯ããã«èªèã§ããŸããã§ããã ãã¹ãŠãããã»ã©åçŽã§ã¯ãªãããšãå€æããŸãã...æ éã«èª¿ã¹ãŠã¿ããšã顧客ã³ãŒãã¯ãCodabarã«éåžžã«äŒŒãŠããŸããããŸã ç°ãªã£ãŠããããšãããããŸããã
- ä»ã®éå§èšå·ãšåæ¢èšå·ããããŸãã
- åæ å ±ã·ã³ãã«ã¯ãæšæºã®7èŠçŽ ïŒ4è¡ãš3ã¹ããŒã¹ïŒã§ã¯ãªãã9ïŒ5è¡ã4ã¹ããŒã¹ïŒã§æ§æãããŠããŸãã
- éå§èšå·ãšåæ¢èšå·ã7èŠçŽ ã§ã¯ãªãã3ïŒ2è¡ã1ã¹ããŒã¹ïŒã§æ§æãããŠããŸãã
ããããããã®åœ¢åŒããæšæºãã§ããã詳现ãªèª¬æãšæ å ±ã¯èŠã€ãããŸããã§ããã ãã®ã³ãŒãã®èªèãèªååããããã®ã©ã€ãã©ãªå®è£ ããããããããŸããããããããèŠã€ããã®ã¯å¹žéã§ã¯ãããŸããã§ãã...ãã®çµæãZxingã§ã®äœæ¥ãç¶ç¶ãã以äžãå®è¡ããããšã«ããŸããïŒãœãŒã¹ã³ãŒããååŸããç¬èªã®ããŒãºã«åãããŠèªèã¢ã«ãŽãªãºã ãå€æŽããŸãã
ã¢ã«ãŽãªãºã
Zxingã§ã¯ãç¹å®ã®ã³ãŒãïŒCodabarReader.csãªã©ïŒã®èªèããžãã¯ãå®è£ ããåã¯ã©ã¹ã«ã¯ãOneDReader.csã¯ã©ã¹ã§å®£èšãããç¬èªã®æœè±¡decodeRowã¡ãœããã®å®è£ ããããŸãã
override public List<Result> decodeRow(int rowNumber, BitArray row, Hashtable hints)
å ¥åã¯ãç»åã®è¡çªå·ãšãè¡ã®ãã¯ã»ã«å€ãå«ãå®éã®é åã§ãïŒæã-æããïŒã
次ã«ãsetCountersïŒBitArray rowïŒã¡ãœããã䜿çšããŠã次ã®ã¢ã«ãŽãªãºã ã«åŸã£ãŠint [] countersé åãéå§ãããŸããæããã¯ã»ã«ããéå§ããè¡é åã§çœããã¯ã»ã«ã«ééãããŸã§é åã®æåã®èŠçŽ ãå¢å ãå§ããŸãã ãã®åŸãcountersé åã®2çªç®ã®èŠçŽ ãžã®é·ç§»ãè¡ãããé»ããã¯ã»ã«ãçŸãããŸã§å¢åãããŸãã ãããŠãè¡æ«ãŸã§ç¶ããŸãã ãã®çµæãã«ãŠã³ã¿ãŒé åã¯æ¬¡ã®ããã«ãªããŸãã
15 7 10 3 4 8 16 ...
ã€ãŸãã15åã®é»ãã¯ã»ã«ã7åã®çœã10åã®é»ã3åã®çœãªã©ã§ãã ïŒãã®å®è£ ã®æåã®èŠçŽ ã¯é»ããã¯ã»ã«ã«å¯Ÿå¿ããŠããŸãïŒã
次ã«ãéå§æåã«å¯Ÿå¿ããã·ãŒã±ã³ã¹ãæ¢ããŸãïŒãã®äŸã§ã¯ãæåãAãã§ãå ã®Codabarã§ã¯æåãAãããBãããCãããDãã®ããããã§ãïŒã findStartPatternã¡ãœããïŒout int charOffsetãint globalOffsetïŒã䜿çšããŠæ€çŽ¢ããŸãã ççŸãèŠã€ãããŸã§ãglobalOffsetã®å€ãå¢ããïŒç»åè¡ã®çŸåšã®äœçœ®ã決å®ããŸãïŒãcountersé åã®æ¬¡ã®æåã«é²ã¿ãŸãã findStartPatternã¡ãœããã¯ãã¡ãœãããåŒã³åºããŸãã
int toNarrowWidePattern(int position, int offset)
ããã¯ãcountersé åã®çŸåšã®èŠçŽ ã®æ°ãšæåã®é·ãïŒéå§æåãŸãã¯åæ¢æåã®å Žåã¯3ãæ®ãã®æåã®å Žåã¯9ïŒãåããŸãã æåãèŠã€ãããªãå Žåã¯-1ãè¿ããŸãã æåãèŠã€ãã£ãå ŽåãCHARACTER_ENCODINGSé åã®ãã®äœçœ®ãè¿ããŸãã
ã¢ã«ãã¡ããã
ã³ãŒãã®ã¢ã«ãã¡ãããã¯ã次ã®ãã£ãŒã«ãã«ãã£ãŠæ±ºå®ãããŸãã
- char [] ALPHABET_STRING-ã³ãŒãã§äœ¿çšããããã¹ãŠã®æåãå«ãŸããŸãã
- int [] CHARACTER_ENCODINGS-ã³ãŒãã®åæåã®ã³ãŒãã·ãŒã±ã³ã¹ç¹æ§ãå®çŸ©ããæ°åãå«ãŸããŸãã
CHARACTER_ENCODINGSé åã«ä¿åãããŠããå€ãšãäžè¬çã«Codabarãã©ã®ããã«ãšã³ã³ãŒãããããã«ã€ããŠã®ããã€ãã®èšèã ããšãã°ãæ°å€ã0ãã¯ã次ã®äžé£ã®ã¹ãã©ã€ããšã¹ããŒã¹ã«ãã£ãŠãšã³ã³ãŒããããŸãã

ããã¯æ¬¡ã®ããã«èšè¿°ãããŸãïŒ101010011ïŒããŒã³ãŒããšã³ã³ãŒãã£ã³ã°ïŒã åäžã®0/1ã¯çãã¹ããŒã¹/ã¹ããªããããšã³ã³ãŒãããããã«00/11ã¯é·ãã¹ããŒã¹/ã¹ããªããããšã³ã³ãŒãããŸãã ããã«ããã®ã·ãŒã±ã³ã¹ã¯ã³ãŒã0000011ïŒå¹ ã®ãšã³ã³ãŒãïŒããŸãã¯16é²åœ¢åŒïŒ0x03ã«å€æãããŸãã ã€ãŸã åäžã®æåã¯ãŒãã§ãäºéã®æåã¯1ã§æžã蟌ãŸããŸãã ãã®å Žåãåæåã¯7æåã§ã¯ãªã9æåã§ãšã³ã³ãŒããããŸãããããžã¿ã«ã³ãŒããäœæããããžãã¯ã¯åãã§ãã
ã¯ãŒãã³ã®äŸãå匷ããã®ã«æéãè²»ããå¿ èŠããããŸããã ããŒã³ãŒãã泚ææ·±ãèŠãŠãç¹å®ã®æåã«å¯Ÿå¿ããã·ãŒã±ã³ã¹ãæžããŸããã çµæã¯ç§ãã¡èªèº«ã®ã¢ã«ãã¡ãããã§ãïŒ
private const String ALPHABET_STRING = "0123456789AE"; static int[] CHARACTER_ENCODINGS = { 0x014, 0x101, 0x041, 0x140, 0x011, 0x110, 0x050, 0x005, 0x104, 0x044, // 0-9 0x000, 0x004, // AE};
ãããã£ãŠãã³ãŒããåŠçããããã»ã¹ã¯æ¬¡ã®ãšããã§ããéå§æåãèŠã€ãããšããã«ãåãtoNarrowWidePatternã¡ãœããã䜿çšããŠæ å ±ãæ¢ããŸãã ã·ãŒã±ã³ã¹ã®é·ãã¯åºå®ãããŠããŸãã ç¹å®ã®ã¹ãããã§ãã·ã³ãã«ãåæ¢ã·ã³ãã«ãã©ããã確èªããå¿ èŠããããŸãã ã¯ãã®å Žåãçµæãçæããcountersé åã®æ¬¡ã®èŠçŽ ã«ç§»åããŠãæååå ã®ããŒã³ãŒãã®æ€çŽ¢ãç¶ããŸãã
ãã®çµæã1è¡ãã¹ãã£ã³ãããšã1ã€ä»¥äžã®ã³ãŒãããããŸãïŒãŸãã¯ãããŸããïŒããããã®ã³ãŒãã¯ãçµæã®ã°ããŒãã«é åã«æ ŒçŽãããŸãã ãããŠãç»åã®æ¬¡ã®è¡ã«é²ã¿ãŸãã
4ã€ã®äœçœ®ãã¹ãŠã«ã³ãŒããååšãããã©ããããã¥ã¡ã³ãããã§ãã¯ããå¿ èŠãããå Žåã¯ãç»åãæèšåãã«90床å転ããæ©èœãè¿œå ãããŸããã Zxingã©ã€ãã©ãªã§ã¯ãåŠçãããç»åã¯BinaryBitmapã¯ã©ã¹ã«å«ãŸããŠããããã®ã¯ã©ã¹ã«ã¯rotateCounterClockwiseïŒïŒã¡ãœããããããŸãã ç»åã®å転ã¯ç°¡åã§ãã
ãããã£ãŠãå°ãèããŠäœæ¥ããåŸãæ°ããã³ãŒã圢åŒã«åãããŠã©ã€ãã©ãªãå€æŽããããšãã§ããŸããã æ°ã«ãã人ãã³ãŒãã¯ããã«ãããŸã
é衚瀺ã®ããã¹ã
using System; using System.Collections; using System.Collections.Generic; using System.Text; using BitArray = ETR.REBT.BarcodeReader.common.BitArray; namespace ETR.REBT.BarcodeReader.oned { public sealed class MyCodeReader : OneDReader { // These values are critical for determining how permissive the decoding // will be. All stripe sizes must be within the window these define, as // compared to the average stripe size. private static readonly int MAX_ACCEPTABLE = (int)(PATTERN_MATCH_RESULT_SCALE_FACTOR * 2.0f); private static readonly int PADDING = (int)(PATTERN_MATCH_RESULT_SCALE_FACTOR * 1.5f); private static readonly int STARTEND_LENGTH = 3; private static readonly int SYMBOL_LENGTH = 9; private static readonly int DATA_LENGTH = 15; // 15 symbols + 2 start/stop symbols private static readonly int All_LENGHT = (16 + DATA_LENGTH * SYMBOL_LENGTH + 2 * STARTEND_LENGTH); private const String ALPHABET_STRING = "0123456789AE"; internal static readonly char[] ALPHABET = ALPHABET_STRING.ToCharArray(); /** * These represent the encodings of characters, as patterns of wide and narrow bars. The 7 least-significant bits of * each int correspond to the pattern of wide and narrow, with 1s representing "wide" and 0s representing narrow. */ internal static int[] CHARACTER_ENCODINGS = { 0x014, 0x101, 0x041, 0x140, 0x011, 0x110, 0x050, 0x005, 0x104, 0x044, // 0-9 0x000, 0x004, // AE }; // minimal number of characters that should be present (inclusing start and stop characters) // under normal circumstances this should be set to 3, but can be set higher // as a last-ditch attempt to reduce false positives. private const int MIN_CHARACTER_LENGTH = 3; // Start and end patterns private static readonly char[] START_ENCODING = { 'A' }; private static readonly char[] END_ENCODING = { 'E' }; private static readonly char[] DATA_ENCODING = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; // some codabar generator allow the codabar string to be closed by every // character. This will cause lots of false positives! // some industries use a checksum standard but this is not part of the original codabar standard // for more information see : http://www.mecsw.com/specs/codabar.html // Keep some instance variables to avoid reallocations private readonly StringBuilder decodeRowResult; private int[] counters; private int counterLength; public MyCodeReader() { decodeRowResult = new StringBuilder(40); counters = new int[500]; counterLength = 0; } override public List<Result> decodeRow(int rowNumber, BitArray row, Hashtable hints) { List<Result> returnList = null; if (!setCounters(row)) return null; int globalOffset = 0; while (globalOffset < counterLength) { int startSymbolPos = -1; int startOffset = findStartPattern(out startSymbolPos, globalOffset); if (startOffset < 0) return returnList; // we can't find start char in the whole row -> so, exit decodeRowResult.Length = 0; decodeRowResult.Append((char)startSymbolPos); int nextStart = startOffset; nextStart += (STARTEND_LENGTH + 1/*space between symbols*/); bool findNextStart = false; do { int charOffset = toNarrowWidePattern(nextStart, SYMBOL_LENGTH); if (charOffset == -1 || !arrayContains(DATA_ENCODING, ALPHABET[charOffset])) { findNextStart = true; break; } decodeRowResult.Append((char)charOffset); nextStart += (SYMBOL_LENGTH + 1); // Stop as soon as length of data symbols equals to corresponding number if (decodeRowResult.Length == DATA_LENGTH + 1/*start symbol*/) { int endOffset = toNarrowWidePattern(nextStart, STARTEND_LENGTH); if (endOffset == -1 || !arrayContains(END_ENCODING, ALPHABET[endOffset])) { findNextStart = true; break; } globalOffset = nextStart + STARTEND_LENGTH; decodeRowResult.Append((char)endOffset); break; } } while (nextStart < counterLength); // no fixed end pattern so keep on reading while data is available if (findNextStart) { globalOffset = ++startOffset; continue; } if (!validatePattern()) { globalOffset = ++startOffset; continue; } // remove stop/start characters character decodeRowResult.Remove(decodeRowResult.Length - 1, 1); decodeRowResult.Remove(0, 1); int runningCount = 0; for (int i = 0; i < startOffset; i++) { runningCount += counters[i]; } float left = (float)runningCount; for (int i = startOffset; i < nextStart - 1; i++) { runningCount += counters[i]; } float right = (float)runningCount; Result result = new Result( decodeRowResult.ToString(), null, new ResultPoint[] { new ResultPoint(left, (float) rowNumber), new ResultPoint(right, (float) rowNumber) }, BarcodeFormat.CODABAR); if (returnList == null) returnList = new List<Result>(); returnList.Add(result); } return returnList; } private bool validatePattern() { if (decodeRowResult.Length != DATA_LENGTH + 2) { return false; } // Translate character table offsets to actual characters. for (int i = 0; i < decodeRowResult.Length; i++) { decodeRowResult[i] = ALPHABET[decodeRowResult[i]]; } // Ensure a valid start character char startchar = decodeRowResult[0]; if (!arrayContains(START_ENCODING, startchar)) { return false; } // Ensure a valid end character char endchar = decodeRowResult[decodeRowResult.Length - 1]; if (!arrayContains(END_ENCODING, endchar)) { return false; } // Ensure a valid data symbols for (int i = 1; i < decodeRowResult.Length - 1; i++) { if (!arrayContains(DATA_ENCODING, decodeRowResult[i])) { return false; } } return true; } /// <summary> /// Records the size of all runs of white and black pixels, starting with white. /// This is just like recordPattern, except it records all the counters, and /// uses our builtin "counters" member for storage. /// </summary> /// <param name="row">row to count from</param> private bool setCounters(BitArray row) { counterLength = 0; // Start from the first white bit. int i = row.getNextUnset(0); int end = row.Size; if (i >= end) { return false; } bool isWhite = true; int count = 0; for (; i < end; i++) { if (row[i] ^ isWhite) { // that is, exactly one is true count++; } else { counterAppend(count); count = 1; isWhite = !isWhite; } } counterAppend(count); return true; } private void counterAppend(int e) { counters[counterLength] = e; counterLength++; if (counterLength >= counters.Length) { int[] temp = new int[counterLength * 2]; Array.Copy(counters, 0, temp, 0, counterLength); counters = temp; } } private int findStartPattern(out int charOffset, int globalOffset) { charOffset = -1; // // Assume that first (i = 0) set of pixels is white, // so we start find symbols from second set (i = 1). // And next we step over white set ('i += 2'). // for (int i = 1 + globalOffset; i < counterLength; i += 2) { if (counters[i - 1] < counters[i] * 5) // before start char must be a long space continue; charOffset = toNarrowWidePattern(i, 3); if (charOffset != -1 && arrayContains(START_ENCODING, ALPHABET[charOffset])) { return i; } } return -1; } internal static bool arrayContains(char[] array, char key) { if (array != null) { foreach (char c in array) { if (c == key) { return true; } } } return false; } // Assumes that counters[position] is a bar. private int toNarrowWidePattern(int position, int offset) { int end = position + offset; if (end >= counterLength) return -1; // First element is for bars, second is for spaces. int[] maxes = { 0, 0 }; int[] mins = { Int32.MaxValue, Int32.MaxValue }; int[] thresholds = { 0, 0 }; for (int i = 0; i < 2; i++) { for (int j = position + i; j < end; j += 2) { if (counters[j] < mins[i]) { mins[i] = counters[j]; } if (counters[j] > maxes[i]) { maxes[i] = counters[j]; } } double tr = ((double)mins[i] + (double)maxes[i]) / 2; thresholds[i] = (int)Math.Ceiling(tr); } // There are no big spaces in the barcode -> only small spaces thresholds[1] = Int32.MaxValue; // For start and end symbols defined empirically threshold equals to 5 if (offset == STARTEND_LENGTH) thresholds[0] = 5; int bitmask = 1 << offset; int pattern = 0; for (int i = 0; i < offset; i++) { int barOrSpace = i & 1; bitmask >>= 1; if (counters[position + i] >= thresholds[barOrSpace]) { pattern |= bitmask; } } for (int i = 0; i < CHARACTER_ENCODINGS.Length; i++) { if (CHARACTER_ENCODINGS[i] == pattern) { return i; } } return -1; } } }
ãæé©åãZxing
ãã®ãããããŒãžäžã®1ã€ä»¥äžã®ã³ãŒããèªèã§ããŸããã ããããç§ãã¡ã®åé¡ã¯ããã§çµãããŸããã§ããã æ¡ä»¶ã«å¿ããŠãè€æ°ã®ã³ãŒãã䜿çšã§ããã»ããã·ãŒãã®4ã€ã®ç°ãªãäœçœ®ãã¹ãã£ã³ããå¿ èŠããããããã¢ã«ãŽãªãºã ã¯å€§å¹ ã«ãé ãããªããŸããã ããã«æãäžããŠã次ã®æ©èœãçºèŠãããŸããã
Zxingã¯ãç»åã«åºã¥ããŠRGBLuminanceSourceã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ãäœæããŸãã å ã®ç»åã®åãã¯ã»ã«ã®æããã«é¢ããæ å ±ãå«ããã€ãã®é åããããŸãã 次ã«ããã®æ å ±ãšãããå€ã«åºã¥ããŠããããããããååŸãããŸãã
以äžã¯ãRGBLuminanceSourceã¯ã©ã¹ã®ã³ã³ã¹ãã©ã¯ã¿ãŒã®ã³ãŒãéšåã®äŸã§ãã
Color c; for (int y = 0; y < height; y++) { int offset = y * width; for (int x = 0; x < width; x++) { c = bitmap.GetPixel(x, y); var r = ColorUtility.GetRValue(c); var g = ColorUtility.GetGValue(c); var b = ColorUtility.GetBValue(c); luminances[offset + x] = (byte)(0.3 * r + 0.59 * g + 0.11 * b + 0.01); } }
ã€ãŸãããµã€ã¯ã«ã§ã¯ãé ããããããã.GetPixelïŒxãyïŒãç»åã®åãã¯ã»ã«ã«äœ¿çšãããŸãïŒ è§£å床ã200x300ãã¯ã»ã«ïŒãŸãã¯ããã«è¿ãïŒã®å°ããªç»åã®å Žåããã®ã¢ãããŒãã¯éåžžã«é©åã§ãããé 延ã¯çºçããŸããïŒååãšããŠ1ã€ã®ã³ãŒãããèªèãããªãå ŽåïŒã ãã ãããã®å Žåãç»åã®è§£å床ã¯é«ãïŒæ倧3000 x 5000ãã¯ã»ã«ïŒãããã«æ¹åãªãã·ã§ã³ã®æ°ãä¹ç®ããå€ãã®ããŒãžã®åŠçãä¹ç®ããå¿ èŠããããŸãã ããã¯ãã¹ãŠã蚱容ã§ããªãé 延ã«ã€ãªãããŸãã ããšãã°ãäžèšã®è§£å床ã®1ããŒãžã§ã¯ãRGBLuminanceSourceã¯ã©ã¹ã®ãªããžã§ã¯ãã8ç§ã§äœæãããŸããããããã¯ãã¡ããéåžžã«é·ãã§ãã
ãã®ã³ãŒããããã«å€æŽããGetPixelãå¿ããŠãã¹ãã£ã³ã«åãæããå¿ èŠããããŸããã
bmp = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, bitmap.PixelFormat); for (var y = 0; y < bmp.Height; y++) { var row = (byte*)bmp.Scan0 + (y * bmp.Stride); int offset = y * width; for (var x = 0; x < bmp.Width; x++) { var b = row[(x * pixelSize)]; var g = row[(x * pixelSize) + 1]; var r = row[(x * pixelSize) + 2]; luminances[offset + x] = (byte)(0.3 * r + 0.59 * g + 0.11 * b + 0.01); } }
ãã®ã¹ãããã«ãããã¢ã«ãŽãªãºã ãå€§å¹ ã«å éããã蚱容å¯èœãªåŠçæéãåŸãããšãã§ããŸããã
PDFã§äœæ¥ãã
åè¿°ã®ããã«ãã¯ãŒãã³ã¹ãã£ã³ã¯ç»åãã¡ã€ã«ã®åœ¢åŒãŸãã¯PDFããã¥ã¡ã³ãã§è¡ãããšãã§ããŸãã pdfããŒãžãç»åã«å€æããããã«ãitextsharpã©ã€ãã©ãªã䜿çšããŸãã ã
ãã®ã©ã€ãã©ãªãæäœããããã®ã¡ã€ã³ã¯ã©ã¹ã¯PdfReaderã§ãã ãã®ã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ã¯ãããšãã°æ¬¡ã®ããã«ããŠååŸã§ããŸãã
ãã¿ãã¬ã®äžã§ã³ãŒããæ¢ããŸãã
é衚瀺ã®ããã¹ã
ãã®åŸãã³ãŒãã§äœ¿çšã§ããŸãã
ãã®é¢æ°ã䜿çšããŠãPDFããã¥ã¡ã³ãããŒãžã§ç»åãæ€çŽ¢ããŸã
ImageRenderInfoã¯ã©ã¹ã®ãªããžã§ã¯ãããBitmapåã®ãªããžã§ã¯ããååŸããŸã
ImageDecoder.Decodeã¡ãœããã¯ãç»åå ã®ã³ãŒããæ€çŽ¢ããããžãã¯ãå®è£ ããŸãã
var reader = new PdfReader(filePath)
ãã®åŸãã³ãŒãã§äœ¿çšã§ããŸãã
for (var pageNumber = 1; pageNumber <= reader.NumberOfPages; pageNumber++) { var page = reader.GetPageN(pageNumber); List<ImageRenderInfo> images; try { images = FindImageInPDFDictionary(page); } catch (Exception) { // PDF continue; } finally { reader.ReleasePage(pageNumber); } foreach (var img in images) { var image = RenderImage(img); var result = ImageDecoder.Decode(image, allRotations); if (result != null && result.Count > 0) { // , } } }
ãã®é¢æ°ã䜿çšããŠãPDFããã¥ã¡ã³ãããŒãžã§ç»åãæ€çŽ¢ããŸã
private static List<ImageRenderInfo> FindImageInPDFDictionary(PdfDictionary pg) { var result = new List<ImageRenderInfo>(); var res = (PdfDictionary)PdfReader.GetPdfObject(pg.Get(PdfName.RESOURCES)); var xobj = (PdfDictionary)PdfReader.GetPdfObject(res.Get(PdfName.XOBJECT)); if (xobj == null) return null; foreach (var name in xobj.Keys) { var obj = xobj.Get(name); if (!obj.IsIndirect()) continue; var tg = (PdfDictionary)PdfReader.GetPdfObject(obj); var type = (PdfName)PdfReader.GetPdfObject(tg.Get(PdfName.SUBTYPE)); if (PdfName.IMAGE.Equals(type)) { var width = float.Parse(tg.Get(PdfName.WIDTH).ToString()); var height = float.Parse(tg.Get(PdfName.HEIGHT).ToString()); if (width > ImageDecoder.MinimalSideResolution || height >= ImageDecoder.MinimalSideResolution) { var imgRi = ImageRenderInfo.CreateForXObject(new Matrix(width, height), (PRIndirectReference)obj, tg); result.Add(imgRi); } } if (PdfName.FORM.Equals(type)) { result.AddRange(FindImageInPDFDictionary(tg)); } if (PdfName.GROUP.Equals(type)) { result.AddRange(FindImageInPDFDictionary(tg)); } } return result; }
ImageRenderInfoã¯ã©ã¹ã®ãªããžã§ã¯ãããBitmapåã®ãªããžã§ã¯ããååŸããŸã
private static Bitmap RenderImage(ImageRenderInfo renderInfo) { try { var image = renderInfo.GetImage(); using (var dotnetImg = image.GetDrawingImage()) { if (dotnetImg != null) { using (var ms = new MemoryStream()) { dotnetImg.Save(ms, ImageFormat.Png); return new Bitmap(dotnetImg); } } } } catch (Exception) { } return null; }
ImageDecoder.Decodeã¡ãœããã¯ãç»åå ã®ã³ãŒããæ€çŽ¢ããããžãã¯ãå®è£ ããŸãã
äžçã«ã¯ä»ãå€ãã®çš®é¡ã®ããŒã³ãŒãããããŸãã ãããã®ã»ãšãã©ã®èªèãšçæã¯ãéçºè ãå©çšã§ããã©ã€ãã©ãªã«å®è£ ãããŠããŸãã ãã ããå ã®ã¿ã€ãã®ããŒã³ãŒãã«ã€ãŸãããšãããã«èªèã§ããªããªãããšããããŸãã
ãããŠãæ éã«ãã¢ãªã³ã°ããé©åã«èšèšããããªãŒãã³ãœãŒã¹ã©ã€ãã©ãªã䜿çšããæ¹æ³ã¯ãããã«çµæãåŸãã®ã«åœ¹ç«ã¡ãŸãã