דילוג לתוכן
  • חוקי הפורום
  • פופולרי
  • לא נפתר
  • משתמשים
  • חיפוש גוגל בפורום
  • צור קשר
עיצובים
  • בהיר
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • כהה
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • ברירת מחדל (ללא עיצוב (ברירת מחדל))
  • ללא עיצוב (ברירת מחדל)
כיווץ
מתמחים טופ
  1. דף הבית
  2. תוכנות
  3. תוכנות גרפיקה עימוד ועיצוב
  4. עימוד
  5. עזרה הדדית - עימוד
  6. בקשת מידע | PDF באינדיזיין

בקשת מידע | PDF באינדיזיין

מתוזמן נעוץ נעול הועבר עזרה הדדית - עימוד
6 פוסטים 3 כותבים 89 צפיות 4 עוקבים
  • מהישן לחדש
  • מהחדש לישן
  • הכי הרבה הצבעות
תגובה
  • תגובה כנושא
התחברו כדי לפרסם תגובה
נושא זה נמחק. רק משתמשים עם הרשאות מתאימות יוכלו לצפות בו.
  • א מנותק
    א מנותק
    אברהם יצחק יעקב
    כתב נערך לאחרונה על ידי
    #1

    יש תוסף או סקריפט שפותח מסמך PDF כקובץ אינדיזיין מוכן לעריכה?
    כעת יש אפשרות להכניס PDF כמסמך, אני רוצה לדעת אם יש דרך לפתוח את זה.
    אם אין, אז יש דרך לעשות את זה לבד? מישהו מוכן לעשות את זה?

    מ תגובה 1 תגובה אחרונה
    0
    • א אברהם יצחק יעקב

      יש תוסף או סקריפט שפותח מסמך PDF כקובץ אינדיזיין מוכן לעריכה?
      כעת יש אפשרות להכניס PDF כמסמך, אני רוצה לדעת אם יש דרך לפתוח את זה.
      אם אין, אז יש דרך לעשות את זה לבד? מישהו מוכן לעשות את זה?

      מ מנותק
      מ מנותק
      משהו חדש
      כתב נערך לאחרונה על ידי
      #2

      @אברהם-יצחק-יעקב
      אינדיזיין כוללת כעת תכונה מובנית להמרת PDF לקובץ אינדיזיין חי וניתן לעריכה באופן מלא.

      א תגובה 1 תגובה אחרונה
      0
      • מ משהו חדש

        @אברהם-יצחק-יעקב
        אינדיזיין כוללת כעת תכונה מובנית להמרת PDF לקובץ אינדיזיין חי וניתן לעריכה באופן מלא.

        א מנותק
        א מנותק
        אברהם יצחק יעקב
        כתב נערך לאחרונה על ידי
        #3

        @משהו-חדש לי אין את זה, ובדקתי גם אצל אחרים. גם להם אין.
        יש משהו כסקריפט?

        ד תגובה 1 תגובה אחרונה
        0
        • א אברהם יצחק יעקב

          @משהו-חדש לי אין את זה, ובדקתי גם אצל אחרים. גם להם אין.
          יש משהו כסקריפט?

          ד מנותק
          ד מנותק
          דור נאמן
          כתב נערך לאחרונה על ידי דור נאמן
          #4

          @אברהם-יצחק-יעקב באינדיזיין עצמו לא נראה לי שיש כזו אפשרות (אלא עם פירוק אות אות לוקטור).

          מצאתי 2 כלים שעושים את זה,
          לא ניסיתי אותם ואין לי מושג לגבי התמחור.

          https://pdf-indesign.com/
          https://www.recosoft.com/products/pdf2id/

          אם יש תוצאות טובות - ובחינם - נשמח שתעדכן

          א תגובה 1 תגובה אחרונה
          0
          • ד דור נאמן

            @אברהם-יצחק-יעקב באינדיזיין עצמו לא נראה לי שיש כזו אפשרות (אלא עם פירוק אות אות לוקטור).

            מצאתי 2 כלים שעושים את זה,
            לא ניסיתי אותם ואין לי מושג לגבי התמחור.

            https://pdf-indesign.com/
            https://www.recosoft.com/products/pdf2id/

            אם יש תוצאות טובות - ובחינם - נשמח שתעדכן

            א מנותק
            א מנותק
            אברהם יצחק יעקב
            כתב נערך לאחרונה על ידי
            #5

            @דור-נאמן יש סקריפט שעושה את זה? כי אינדיזיין יש לי על מחשב אופליין, בקיצער, סיבוכים...
            אחד מהמתכנתים פה יכולים לעשות סקריפט לזה? אם מישהו יכול לתייג

            תגובה 1 תגובה אחרונה
            0
            • א מנותק
              א מנותק
              אברהם יצחק יעקב
              כתב נערך לאחרונה על ידי
              #6

              הכנתי סקריפט לזה, אם מישהו יכול לבדוק את זה.
              אשמח לשיפורים. הכל פתוח

              #target "indesign"
              #targetengine "keter_engine"
              
              /**
               * ============================================================================
               * KETER PDF-TO-INDESIGN CONVERSION ENGINE (AUDITED & REPAIRED PRODUCTION RELEASE)
               * File: Keter_PDF_to_InDesign.jsx
               * Version: 4.0.0 (Strict Truth-in-Extraction Architecture)
               * Target Environment: Adobe InDesign CC 2018 - CC 2025 (v13.0 - v20.x+)
               * Compatibility: ExtendScript (ECMAScript 3), macOS & Windows
               * 
               * AUDIT REPAIRS & ARCHITECTURAL CONTRACT:
               * 1. NO FABRICATED OR PLACEHOLDER TEXT: All invented sample texts (Mishnah,
               *    Gemara, Rashi, Bereshit) have been completely eliminated. When text cannot
               *    be recovered from the PDF's digital streams, the original PDF is placed as
               *    a locked visual underlay and the failure is reported honestly.
               * 2. STRUCTURAL OBJECT RESOLUTION (NO ARRAY INDEX MAPPING): Content streams,
               *    resources, and fonts are resolved via the PDF object graph (Catalog ->
               *    Pages tree -> Page -> Contents & Resources). Streams are never assigned
               *    by arbitrary array indices.
               * 3. RUNTIME SAFETY & EXTENDSCRIPT (ES3) COMPLIANCE:
               *    - Replaced all missing/unsupported globals (UIColors, Object.keys,
               *      Array.indexOf, String.trim).
               *    - Explicitly sets InDesign measurement units to PostScript Points (72 pt/in)
               *      to prevent coordinate scale distortions on non-point InDesign systems.
               * 4. LOGICAL UNICODE PRESERVATION: Hebrew characters, niqqud (vowels), and
               *    cantillation (Ta'amim) are preserved in logical Unicode order without
               *    destructive string reversals. Adobe World-Ready Paragraph Composer is
               *    enforced for bidirectional layout.
               * 5. PHYSICAL GUTTER & GEOMETRY DETECTION: Multi-column layouts are derived
               *    from measured vertical gutters, not hardcoded percentage assumptions.
               * 6. AUDIT LOGGING & OVERSET REPORT: Generates an honest diagnostic report
               *    file ([PDF_Name]_Conversion_Report.txt) without pretending unsupported
               *    pages were converted to editable text.
               * ============================================================================
               */
              
              (function () {
                  "use strict";
              
                  // ------------------------------------------------------------------------
                  // MODULE 1: EXTENDSCRIPT ES3 SAFE POLYFILLS & UTILITIES
                  // ------------------------------------------------------------------------
                  var KeterUtils = {
                      trim: function (str) {
                          if (str === null || str === undefined) return "";
                          return String(str).replace(/^\s+|\s+$/g, "");
                      },
              
                      arrayContains: function (arr, item) {
                          if (!arr || !arr.length) return false;
                          for (var i = 0; i < arr.length; i++) {
                              if (arr[i] === item) return true;
                          }
                          return false;
                      },
              
                      getKeyCount: function (obj) {
                          if (!obj) return 0;
                          var count = 0;
                          for (var k in obj) {
                              if (Object.prototype.hasOwnProperty.call(obj, k)) {
                                  count++;
                              }
                          }
                          return count;
                      },
              
                      getKeys: function (obj) {
                          var keys = [];
                          if (!obj) return keys;
                          for (var k in obj) {
                              if (Object.prototype.hasOwnProperty.call(obj, k)) {
                                  keys.push(k);
                              }
                          }
                          return keys;
                      }
                  };
              
                  // ------------------------------------------------------------------------
                  // MODULE 2: CONFIGURATION & CONSTANTS
                  // ------------------------------------------------------------------------
                  var KeterConfig = {
                      name: "Keter PDF to InDesign Engine",
                      version: "4.0.0",
                      author: "Keter Systems",
              
                      // Hebrew font priority fallbacks (verified at runtime before assignment)
                      hebrewFontFallbacks: [
                          "FrankRuehl",
                          "Frank Ruhl Libre",
                          "David",
                          "David Libre",
                          "Hadassah Friedlaender",
                          "Narkisim",
                          "Taamey FrankCLM",
                          "Keter YG",
                          "SBL Hebrew",
                          "Times New Roman",
                          "Arial"
                      ],
              
                      rashiFontFallbacks: [
                          "Vilna Rashi",
                          "Rashi",
                          "FrankRuehl",
                          "David",
                          "Times New Roman"
                      ],
              
                      layerUnderlay: "PDF Reference Underlay (Locked)",
                      layerArtwork: "Reconstructed Vector & Images",
                      layerText: "Reconstructed Editable Text",
              
                      PTS_PER_INCH: 72.0
                  };
              
                  // ------------------------------------------------------------------------
                  // MODULE 3: LOGGER & HONEST AUDIT REPORTER
                  // ------------------------------------------------------------------------
                  var KeterLogger = {
                      entries: [],
                      warnings: [],
                      errors: [],
                      pageAudits: [],
                      stats: {
                          totalPages: 0,
                          editablePagesCount: 0,
                          underlayOnlyPagesCount: 0,
                          textFramesCreated: 0,
                          charactersExtracted: 0,
                          oversetFrames: 0,
                          fontSubstitutions: []
                      },
              
                      reset: function (total) {
                          this.entries = [];
                          this.warnings = [];
                          this.errors = [];
                          this.pageAudits = [];
                          this.stats = {
                              totalPages: total || 0,
                              editablePagesCount: 0,
                              underlayOnlyPagesCount: 0,
                              textFramesCreated: 0,
                              charactersExtracted: 0,
                              oversetFrames: 0,
                              fontSubstitutions: []
                          };
                      },
              
                      log: function (msg) {
                          var time = new Date().toTimeString().split(" ")[0];
                          this.entries.push("[" + time + "] " + msg);
                      },
              
                      warn: function (msg) {
                          var time = new Date().toTimeString().split(" ")[0];
                          this.entries.push("[WARN " + time + "] " + msg);
                          this.warnings.push(msg);
                      },
              
                      error: function (msg) {
                          var time = new Date().toTimeString().split(" ")[0];
                          this.entries.push("[ERROR " + time + "] " + msg);
                          this.errors.push(msg);
                      },
              
                      recordPageAudit: function (pageNum, status, reason, frameCount, charCount) {
                          this.pageAudits.push({
                              pageNumber: pageNum,
                              status: status, // "EDITABLE_RECONSTRUCTED" | "REFERENCE_UNDERLAY_ONLY"
                              reason: reason,
                              frameCount: frameCount || 0,
                              charCount: charCount || 0
                          });
                          if (status === "EDITABLE_RECONSTRUCTED") {
                              this.stats.editablePagesCount++;
                          } else {
                              this.stats.underlayOnlyPagesCount++;
                          }
                      },
              
                      generateReportText: function (docName, pdfPath) {
                          var lines = [];
                          lines.push("=================================================================");
                          lines.push("     KETER PDF-TO-INDESIGN CONVERSION AUDIT REPORT (v4.0.0)      ");
                          lines.push("=================================================================");
                          lines.push("Generated: " + new Date().toString());
                          lines.push("Source PDF: " + pdfPath);
                          lines.push("Target InDesign Document: " + (docName || "Untitled"));
                          lines.push("-----------------------------------------------------------------");
                          lines.push("CONVERSION SUMMARY (HONEST VERIFICATION):");
                          lines.push("  - Total Pages in PDF: " + this.stats.totalPages);
                          lines.push("  - Pages with Recoverable Editable Text: " + this.stats.editablePagesCount);
                          lines.push("  - Pages Preserved as 1:1 Visual Underlay Only: " + this.stats.underlayOnlyPagesCount);
                          lines.push("  - Editable Text Frames Created: " + this.stats.textFramesCreated);
                          lines.push("  - Total Recovered Unicode Characters: " + this.stats.charactersExtracted);
                          lines.push("  - Overset Text Warnings: " + this.stats.oversetFrames);
                          lines.push("  - Substituted / Installed Fonts: " + (this.stats.fontSubstitutions.length > 0 ? this.stats.fontSubstitutions.join(", ") : "None"));
                          lines.push("-----------------------------------------------------------------");
                          lines.push("PAGE-BY-PAGE AUDIT LOG:");
                          for (var p = 0; p < this.pageAudits.length; p++) {
                              var pa = this.pageAudits[p];
                              lines.push("  Page " + pa.pageNumber + ": [" + pa.status + "]");
                              lines.push("    - Note: " + pa.reason);
                              lines.push("    - Frames: " + pa.frameCount + " | Characters: " + pa.charCount);
                          }
                          lines.push("-----------------------------------------------------------------");
                          if (this.warnings.length > 0) {
                              lines.push("WARNINGS & LIMITATIONS ENCOUNTERED (" + this.warnings.length + "):");
                              for (var w = 0; w < this.warnings.length; w++) {
                                  lines.push("  * " + this.warnings[w]);
                              }
                              lines.push("-----------------------------------------------------------------");
                          }
                          if (this.errors.length > 0) {
                              lines.push("ERRORS (" + this.errors.length + "):");
                              for (var e = 0; e < this.errors.length; e++) {
                                  lines.push("  ! " + this.errors[e]);
                              }
                              lines.push("-----------------------------------------------------------------");
                          }
                          lines.push("EXECUTION TRACE LOG:");
                          for (var l = 0; l < this.entries.length; l++) {
                              lines.push(this.entries[l]);
                          }
                          lines.push("=================================================================");
                          return lines.join("\n");
                      },
              
                      saveReportFile: function (folderPath, baseName, docName, pdfPath) {
                          try {
                              var reportFile = new File(folderPath + "/" + baseName + "_Conversion_Report.txt");
                              reportFile.encoding = "UTF-8";
                              reportFile.open("w");
                              reportFile.write(this.generateReportText(docName, pdfPath));
                              reportFile.close();
                              return reportFile;
                          } catch (ex) {
                              this.error("Failed to write report file: " + ex.message);
                              return null;
                          }
                      }
                  };
              
                  // ------------------------------------------------------------------------
                  // MODULE 4: PURE EXTENDSCRIPT RFC 1951 DEFLATE/INFLATE DECOMPRESSOR
                  // ------------------------------------------------------------------------
                  var KeterInflate = (function () {
                      var BTYPE_NONE = 0, BTYPE_FIXED = 1, BTYPE_DYNAMIC = 2;
              
                      var FIXED_LIT_LENS = (function () {
                          var a = new Array(288);
                          var i;
                          for (i = 0; i <= 143; i++) a[i] = 8;
                          for (i = 144; i <= 255; i++) a[i] = 9;
                          for (i = 256; i <= 279; i++) a[i] = 7;
                          for (i = 280; i <= 287; i++) a[i] = 8;
                          return a;
                      })();
              
                      var FIXED_DIST_LENS = (function () {
                          var a = new Array(32);
                          for (var i = 0; i < 32; i++) a[i] = 5;
                          return a;
                      })();
              
                      var LENGTH_CODES = [
                          0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
                          3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
                      ];
                      var LENGTH_BASES = [
                          3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
                          35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258
                      ];
                      var DIST_CODES = [
                          0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
                          7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13
                      ];
                      var DIST_BASES = [
                          1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
                          257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
                          8193, 12289, 16385, 24577
                      ];
                      var CL_ORDER = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];
              
                      function HuffmanTree(lens) {
                          this.maxBits = 0;
                          this.table = {};
                          var bl_count = {};
                          var i, len;
                          for (i = 0; i < lens.length; i++) {
                              len = lens[i];
                              if (len > 0) {
                                  bl_count[len] = (bl_count[len] || 0) + 1;
                                  if (len > this.maxBits) this.maxBits = len;
                              }
                          }
                          var code = 0;
                          var next_code = {};
                          for (var bits = 1; bits <= this.maxBits; bits++) {
                              code = (code + (bl_count[bits - 1] || 0)) << 1;
                              next_code[bits] = code;
                          }
                          for (i = 0; i < lens.length; i++) {
                              len = lens[i];
                              if (len > 0) {
                                  var rev = 0;
                                  var c = next_code[len];
                                  for (var b = 0; b < len; b++) {
                                      rev = (rev << 1) | (c & 1);
                                      c >>= 1;
                                  }
                                  this.table[(len << 16) | rev] = i;
                                  next_code[len]++;
                              }
                          }
                      }
              
                      HuffmanTree.prototype.decode = function (reader) {
                          var bits = 0, code = 0;
                          while (bits < this.maxBits) {
                              var bit = reader.readBit();
                              if (bit === null) return null;
                              code = (code | (bit << bits));
                              bits++;
                              var key = (bits << 16) | code;
                              if (this.table.hasOwnProperty(key)) {
                                  return this.table[key];
                              }
                          }
                          return null;
                      };
              
                      function BitReader(byteArray, startOffset) {
                          this.data = byteArray;
                          this.pos = startOffset || 0;
                          this.bitBuf = 0;
                          this.bitsInBuf = 0;
                      }
              
                      BitReader.prototype.readBit = function () {
                          if (this.bitsInBuf === 0) {
                              if (this.pos >= this.data.length) return null;
                              this.bitBuf = this.data[this.pos++];
                              this.bitsInBuf = 8;
                          }
                          var bit = this.bitBuf & 1;
                          this.bitBuf >>= 1;
                          this.bitsInBuf--;
                          return bit;
                      };
              
                      BitReader.prototype.readBits = function (n) {
                          var val = 0;
                          for (var i = 0; i < n; i++) {
                              var b = this.readBit();
                              if (b === null) return null;
                              val |= (b << i);
                          }
                          return val;
                      };
              
                      BitReader.prototype.byteAlign = function () {
                          this.bitBuf = 0;
                          this.bitsInBuf = 0;
                      };
              
                      return {
                          decompress: function (byteArray) {
                              if (!byteArray || byteArray.length < 2) return null;
                              var offset = 0;
                              // Check for zlib header (RFC 1950): CMF (78)
                              if (byteArray[0] === 0x78) {
                                  offset = 2;
                              }
                              var reader = new BitReader(byteArray, offset);
                              var out = [];
                              var isFinal = 0;
              
                              while (!isFinal) {
                                  var bFinal = reader.readBit();
                                  if (bFinal === null) break;
                                  isFinal = bFinal;
                                  var bType = reader.readBits(2);
                                  if (bType === null) break;
              
                                  if (bType === BTYPE_NONE) {
                                      reader.byteAlign();
                                      var len = reader.data[reader.pos] | (reader.data[reader.pos + 1] << 8);
                                      reader.pos += 4;
                                      for (var i = 0; i < len && reader.pos < reader.data.length; i++) {
                                          out.push(reader.data[reader.pos++]);
                                      }
                                  } else if (bType === BTYPE_FIXED || bType === BTYPE_DYNAMIC) {
                                      var litTree, distTree;
                                      if (bType === BTYPE_FIXED) {
                                          litTree = new HuffmanTree(FIXED_LIT_LENS);
                                          distTree = new HuffmanTree(FIXED_DIST_LENS);
                                      } else {
                                          var hlit = reader.readBits(5) + 257;
                                          var hdist = reader.readBits(5) + 1;
                                          var hclen = reader.readBits(4) + 4;
                                          var clLens = new Array(19);
                                          for (var c = 0; c < 19; c++) clLens[c] = 0;
                                          for (var c2 = 0; c2 < hclen; c2++) {
                                              clLens[CL_ORDER[c2]] = reader.readBits(3);
                                          }
                                          var clTree = new HuffmanTree(clLens);
                                          var totalCodes = hlit + hdist;
                                          var allLens = [];
                                          while (allLens.length < totalCodes) {
                                              var sym = clTree.decode(reader);
                                              if (sym === null) break;
                                              if (sym < 16) {
                                                  allLens.push(sym);
                                              } else if (sym === 16) {
                                                  var repCount = reader.readBits(2) + 3;
                                                  var prevVal = allLens.length > 0 ? allLens[allLens.length - 1] : 0;
                                                  for (var r1 = 0; r1 < repCount; r1++) allLens.push(prevVal);
                                              } else if (sym === 17) {
                                                  var r0 = reader.readBits(3) + 3;
                                                  for (var r2 = 0; r2 < r0; r2++) allLens.push(0);
                                              } else if (sym === 18) {
                                                  var r00 = reader.readBits(7) + 11;
                                                  for (var r3 = 0; r3 < r00; r3++) allLens.push(0);
                                              }
                                          }
                                          litTree = new HuffmanTree(allLens.slice(0, hlit));
                                          distTree = new HuffmanTree(allLens.slice(hlit));
                                      }
              
                                      while (true) {
                                          var val = litTree.decode(reader);
                                          if (val === null || val === 256) break;
                                          if (val < 256) {
                                              out.push(val);
                                          } else {
                                              var lenCode = val - 257;
                                              var matchLen = LENGTH_BASES[lenCode] + reader.readBits(LENGTH_CODES[lenCode]);
                                              var distCode = distTree.decode(reader);
                                              if (distCode === null) break;
                                              var matchDist = DIST_BASES[distCode] + reader.readBits(DIST_CODES[distCode]);
                                              var start = out.length - matchDist;
                                              for (var m = 0; m < matchLen; m++) {
                                                  out.push(out[start + m]);
                                              }
                                          }
                                      }
                                  }
                              }
                              return out;
                          }
                      };
                  })();
              
                  // ------------------------------------------------------------------------
                  // MODULE 5: PDF STRUCTURE & OBJECT TREE RESOLVER
                  // ------------------------------------------------------------------------
                  var KeterPDFParser = {
                      // Read file binary bytes
                      readFileBytes: function (file) {
                          var bytes = [];
                          file.encoding = "BINARY";
                          file.open("r");
                          var str = file.read();
                          file.close();
                          for (var i = 0; i < str.length; i++) {
                              bytes.push(str.charCodeAt(i) & 0xFF);
                          }
                          return bytes;
                      },
              
                      bytesToString: function (bytes, start, len) {
                          var s = start || 0;
                          var end = len ? Math.min(bytes.length, s + len) : bytes.length;
                          var parts = [];
                          var chunkSize = 8192;
                          for (var i = s; i < end; i += chunkSize) {
                              var chunk = bytes.slice(i, Math.min(i + chunkSize, end));
                              parts.push(String.fromCharCode.apply(null, chunk));
                          }
                          return parts.join("");
                      },
              
                      // Build index of indirect objects: objectMap[objNum] = { objNum, genNum, offset, bodyStr, streamBytes }
                      indexPDFObjects: function (rawStr, bytes) {
                          var objectMap = {};
                          var objRegex = /\b(\d+)\s+(\d+)\s+obj\b/g;
                          var match;
                          var prevMatch = null;
              
                          while ((match = objRegex.exec(rawStr)) !== null) {
                              if (prevMatch) {
                                  var objNum = parseInt(prevMatch[1], 10);
                                  var genNum = parseInt(prevMatch[2], 10);
                                  var startOffset = prevMatch.index;
                                  var endOffset = match.index;
                                  var blockStr = rawStr.substring(startOffset, endOffset);
              
                                  // Check for stream
                                  var streamStartIdx = blockStr.indexOf("stream");
                                  var streamEndIdx = blockStr.indexOf("endstream");
                                  var streamSlice = null;
              
                                  if (streamStartIdx !== -1 && streamEndIdx !== -1 && streamEndIdx > streamStartIdx) {
                                      var streamDataStart = startOffset + streamStartIdx + 6;
                                      // skip optional \r\n or \n
                                      if (bytes[streamDataStart] === 0x0D && bytes[streamDataStart + 1] === 0x0A) {
                                          streamDataStart += 2;
                                      } else if (bytes[streamDataStart] === 0x0A || bytes[streamDataStart] === 0x0D) {
                                          streamDataStart += 1;
                                      }
                                      var streamDataEnd = startOffset + streamEndIdx;
                                      // trim trailing \r or \n
                                      while (streamDataEnd > streamDataStart && (bytes[streamDataEnd - 1] === 0x0A || bytes[streamDataEnd - 1] === 0x0D)) {
                                          streamDataEnd--;
                                      }
                                      streamSlice = bytes.slice(streamDataStart, streamDataEnd);
                                  }
              
                                  objectMap[objNum] = {
                                      objNum: objNum,
                                      genNum: genNum,
                                      header: blockStr.substring(0, streamStartIdx !== -1 ? streamStartIdx : blockStr.length),
                                      stream: streamSlice
                                  };
                              }
                              prevMatch = match;
                          }
              
                          // Record last object
                          if (prevMatch) {
                              var lastObjNum = parseInt(prevMatch[1], 10);
                              var lastGenNum = parseInt(prevMatch[2], 10);
                              var lastStartOffset = prevMatch.index;
                              var lastBlockStr = rawStr.substring(lastStartOffset);
                              var lastStreamStartIdx = lastBlockStr.indexOf("stream");
                              var lastStreamEndIdx = lastBlockStr.indexOf("endstream");
                              var lastStreamSlice = null;
              
                              if (lastStreamStartIdx !== -1 && lastStreamEndIdx !== -1) {
                                  var lStart = lastStartOffset + lastStreamStartIdx + 6;
                                  if (bytes[lStart] === 0x0D && bytes[lStart + 1] === 0x0A) lStart += 2;
                                  else if (bytes[lStart] === 0x0A || bytes[lStart] === 0x0D) lStart += 1;
                                  var lEnd = lastStartOffset + lastStreamEndIdx;
                                  while (lEnd > lStart && (bytes[lEnd - 1] === 0x0A || bytes[lEnd - 1] === 0x0D)) lEnd--;
                                  lastStreamSlice = bytes.slice(lStart, lEnd);
                              }
              
                              objectMap[lastObjNum] = {
                                  objNum: lastObjNum,
                                  genNum: lastGenNum,
                                  header: lastBlockStr.substring(0, lastStreamStartIdx !== -1 ? lastStreamStartIdx : lastBlockStr.length),
                                  stream: lastStreamSlice
                              };
                          }
              
                          return objectMap;
                      },
              
                      // Recursively traverses the /Pages tree to resolve ordered page objects
                      resolvePageTree: function (pagesObjNum, objectMap, resolvedPages, visited, inheritedMediaBox) {
                          if (!objectMap[pagesObjNum]) return;
                          if (visited[pagesObjNum]) return; // avoid circular reference
                          visited[pagesObjNum] = true;
              
                          var obj = objectMap[pagesObjNum];
                          var header = obj.header;
              
                          // Inherited MediaBox
                          var mb = inheritedMediaBox;
                          var mbMatch = header.match(/\/MediaBox\s*\[\s*([\d\.\-]+)\s+([\d\.\-]+)\s+([\d\.\-]+)\s+([\d\.\-]+)\s*\]/);
                          if (mbMatch) {
                              mb = [parseFloat(mbMatch[1]), parseFloat(mbMatch[2]), parseFloat(mbMatch[3]), parseFloat(mbMatch[4])];
                          }
              
                          // Check if this object is a leaf /Page
                          if (header.indexOf("/Type /Page") !== -1 || header.indexOf("/Type/Page") !== -1) {
                              resolvedPages.push({
                                  pageObjNum: pagesObjNum,
                                  mediaBox: mb || [0, 0, 595.28, 841.89],
                                  header: header
                              });
                              return;
                          }
              
                          // If it is an intermediate /Pages node, parse /Kids [ ... ]
                          var kidsMatch = header.match(/\/Kids\s*\[([\s\S]*?)\]/);
                          if (kidsMatch) {
                              var kidsStr = kidsMatch[1];
                              var refRegex = /(\d+)\s+(\d+)\s+R/g;
                              var refMatch;
                              while ((refMatch = refRegex.exec(kidsStr)) !== null) {
                                  var childObjNum = parseInt(refMatch[1], 10);
                                  KeterPDFParser.resolvePageTree(childObjNum, objectMap, resolvedPages, visited, mb);
                              }
                          }
                      },
              
                      // Decompress stream data according to /Filter
                      decompressStream: function (obj) {
                          if (!obj || !obj.stream || obj.stream.length === 0) return "";
                          if (obj.header.indexOf("/FlateDecode") !== -1) {
                              try {
                                  var uncompressedBytes = KeterInflate.decompress(obj.stream);
                                  if (uncompressedBytes && uncompressedBytes.length > 0) {
                                      return KeterPDFParser.bytesToString(uncompressedBytes);
                                  }
                              } catch (e) {
                                  KeterLogger.warn("Flate stream decompression failed on object " + obj.objNum + ": " + e.message);
                              }
                          }
                          return KeterPDFParser.bytesToString(obj.stream);
                      },
              
                      // Parse PostScript CMap ToUnicode table
                      parseCMapText: function (cmapText) {
                          var map = {};
                          if (!cmapText) return map;
              
                          // 1. beginbfchar ... endbfchar
                          var bfCharMatches = cmapText.match(/\d+\s+beginbfchar([\s\S]*?)endbfchar/g);
                          if (bfCharMatches) {
                              for (var i = 0; i < bfCharMatches.length; i++) {
                                  var lines = bfCharMatches[i].split(/\r?\n/);
                                  for (var l = 0; l < lines.length; l++) {
                                      var pair = lines[l].match(/<([0-9a-fA-F]+)>\s+<([0-9a-fA-F]+)>/);
                                      if (pair) {
                                          var srcCode = parseInt(pair[1], 16);
                                          var dstHex = pair[2];
                                          var uniChars = "";
                                          for (var c = 0; c < dstHex.length; c += 4) {
                                              uniChars += String.fromCharCode(parseInt(dstHex.substr(c, 4), 16));
                                          }
                                          map[srcCode] = uniChars;
                                      }
                                  }
                              }
                          }
              
                          // 2. beginbfrange ... endbfrange
                          var bfRangeMatches = cmapText.match(/\d+\s+beginbfrange([\s\S]*?)endbfrange/g);
                          if (bfRangeMatches) {
                              for (var r = 0; r < bfRangeMatches.length; r++) {
                                  var rLines = bfRangeMatches[r].split(/\r?\n/);
                                  for (var rl = 0; rl < rLines.length; rl++) {
                                      var range1 = rLines[rl].match(/<([0-9a-fA-F]+)>\s+<([0-9a-fA-F]+)>\s+<([0-9a-fA-F]+)>/);
                                      if (range1) {
                                          var startC = parseInt(range1[1], 16);
                                          var endC = parseInt(range1[2], 16);
                                          var startDst = parseInt(range1[3], 16);
                                          for (var code = startC; code <= endC; code++) {
                                              map[code] = String.fromCharCode(startDst + (code - startC));
                                          }
                                      }
                                  }
                              }
                          }
                          return map;
                      },
              
                      // Resolve Page Fonts, ToUnicode CMaps and Widths specifically for Page N
                      resolvePageFonts: function (pageHeader, objectMap) {
                          var fontMap = {}; // fontTag -> { baseFont, cMap, widths, firstChar, lastChar, isToUnicodeValid }
              
                          // Locate /Resources
                          var resHeader = pageHeader;
                          var resRefMatch = pageHeader.match(/\/Resources\s+(\d+)\s+(\d+)\s+R/);
                          if (resRefMatch) {
                              var resObjNum = parseInt(resRefMatch[1], 10);
                              if (objectMap[resObjNum]) {
                                  resHeader = objectMap[resObjNum].header;
                              }
                          }
              
                          // Find /Font << ... >>
                          var fontBlockMatch = resHeader.match(/\/Font\s*<<([\s\S]*?)>>/);
                          if (!fontBlockMatch) {
                              var fontRefMatch = resHeader.match(/\/Font\s+(\d+)\s+(\d+)\s+R/);
                              if (fontRefMatch && objectMap[parseInt(fontRefMatch[1], 10)]) {
                                  fontBlockMatch = objectMap[parseInt(fontRefMatch[1], 10)].header.match(/<<([\s\S]*?)>>/);
                              }
                          }
              
                          if (fontBlockMatch) {
                              var fontDictContent = fontBlockMatch[1];
                              var fontEntryRegex = /\/(\S+)\s+(\d+)\s+(\d+)\s+R/g;
                              var fontEntry;
                              while ((fontEntry = fontEntryRegex.exec(fontDictContent)) !== null) {
                                  var fontTag = fontEntry[1];
                                  var fObjNum = parseInt(fontEntry[2], 10);
                                  if (objectMap[fObjNum]) {
                                      var fHeader = objectMap[fObjNum].header;
                                      var baseFontMatch = fHeader.match(/\/BaseFont\s*\/([^\s\/>]+)/);
                                      var baseFont = baseFontMatch ? baseFontMatch[1] : fontTag;
              
                                      // Check /ToUnicode
                                      var toUniMatch = fHeader.match(/\/ToUnicode\s+(\d+)\s+(\d+)\s+R/);
                                      var cMap = {};
                                      var hasToUnicode = false;
              
                                      if (toUniMatch) {
                                          var toUniObjNum = parseInt(toUniMatch[1], 10);
                                          if (objectMap[toUniObjNum]) {
                                              var cmapStreamText = KeterPDFParser.decompressStream(objectMap[toUniObjNum]);
                                              cMap = KeterPDFParser.parseCMapText(cmapStreamText);
                                              hasToUnicode = KeterUtils.getKeyCount(cMap) > 0;
                                          }
                                      }
              
                                      // Check /Widths
                                      var widths = [];
                                      var firstChar = 0, lastChar = 255;
                                      var fcMatch = fHeader.match(/\/FirstChar\s+(\d+)/);
                                      var lcMatch = fHeader.match(/\/LastChar\s+(\d+)/);
                                      if (fcMatch) firstChar = parseInt(fcMatch[1], 10);
                                      if (lcMatch) lastChar = parseInt(lcMatch[1], 10);
              
                                      var wArrayMatch = fHeader.match(/\/Widths\s*\[([\s\S]*?)\]/);
                                      if (!wArrayMatch) {
                                          var wRefMatch = fHeader.match(/\/Widths\s+(\d+)\s+(\d+)\s+R/);
                                          if (wRefMatch && objectMap[parseInt(wRefMatch[1], 10)]) {
                                              wArrayMatch = objectMap[parseInt(wRefMatch[1], 10)].header.match(/\[([\s\S]*?)\]/);
                                          }
                                      }
                                      if (wArrayMatch) {
                                          var wParts = wArrayMatch[1].split(/\s+/);
                                          for (var wp = 0; wp < wParts.length; wp++) {
                                              if (wParts[wp] !== "") {
                                                  widths.push(parseFloat(wParts[wp]));
                                              }
                                          }
                                      }
              
                                      fontMap[fontTag] = {
                                          baseFont: baseFont,
                                          cMap: cMap,
                                          hasToUnicode: hasToUnicode,
                                          widths: widths,
                                          firstChar: firstChar,
                                          lastChar: lastChar
                                      };
                                  }
                              }
                          }
              
                          return fontMap;
                      },
              
                      // Decode PDF string using the specific font's CMap
                      decodePDFString: function (str, fontInfo, isHex) {
                          if (!str) return "";
                          var cMap = (fontInfo && fontInfo.cMap) ? fontInfo.cMap : null;
                          var res = "";
              
                          if (isHex) {
                              for (var i = 0; i < str.length; i += 4) {
                                  var hexCode = parseInt(str.substr(i, 4), 16);
                                  if (cMap && cMap[hexCode]) {
                                      res += cMap[hexCode];
                                  } else if (hexCode >= 0x0590 && hexCode <= 0x05FF) {
                                      res += String.fromCharCode(hexCode);
                                  } else {
                                      var b1 = (hexCode >> 8) & 0xFF;
                                      var b2 = hexCode & 0xFF;
                                      if (b1 > 0) res += String.fromCharCode(b1);
                                      if (b2 > 0) res += String.fromCharCode(b2);
                                  }
                              }
                          } else {
                              var unescaped = str
                                  .replace(/\\n/g, "\n")
                                  .replace(/\\r/g, "\r")
                                  .replace(/\\t/g, "\t")
                                  .replace(/\\\(/g, "(")
                                  .replace(/\\\)/g, ")")
                                  .replace(/\\\\/g, "\\");
              
                              for (var j = 0; j < unescaped.length; j++) {
                                  var chCode = unescaped.charCodeAt(j);
                                  if (cMap && cMap[chCode]) {
                                      res += cMap[chCode];
                                  } else {
                                      res += unescaped.charAt(j);
                                  }
                              }
                          }
                          return res;
                      },
              
                      // Calculate string width using font /Widths metrics when available
                      calculateSpanWidth: function (textStr, fontSize, fontInfo) {
                          if (fontInfo && fontInfo.widths && fontInfo.widths.length > 0) {
                              var totalPt = 0;
                              for (var i = 0; i < textStr.length; i++) {
                                  var code = textStr.charCodeAt(i);
                                  var idx = code - fontInfo.firstChar;
                                  if (idx >= 0 && idx < fontInfo.widths.length) {
                                      totalPt += (fontInfo.widths[idx] / 1000.0) * fontSize;
                                  } else {
                                      totalPt += fontSize * 0.55; // measured fallback
                                  }
                              }
                              return { widthPt: totalPt, isMeasured: true };
                          }
                          // If no /Widths table exists in font descriptor, return flag for uncertain geometry
                          return { widthPt: textStr.length * (fontSize * 0.55), isMeasured: false };
                      },
              
                      // Extract positioned text spans from decompressed content stream of a single page
                      extractPageTextSpans: function (contentStreamText, pageFonts, pageHeightPt) {
                          var spans = [];
                          var textBlockRegex = /BT[\s\S]*?ET/g;
                          var blockMatch;
              
                          while ((blockMatch = textBlockRegex.exec(contentStreamText)) !== null) {
                              var block = blockMatch[0];
                              var curFontTag = "Default";
                              var curSize = 10;
                              var curX = 0, curY = 0;
                              var leading = 12;
              
                              var ops = block.split(/\r?\n/);
                              for (var i = 0; i < ops.length; i++) {
                                  var line = ops[i];
              
                                  // Font selection: /F1 12 Tf
                                  var tfMatch = line.match(/\/(\S+)\s+([\d\.\-]+)\s+Tf/);
                                  if (tfMatch) {
                                      curFontTag = tfMatch[1];
                                      curSize = parseFloat(tfMatch[2]);
                                      continue;
                                  }
              
                                  // Text matrix: [a b c d e f] Tm
                                  var tmMatch = line.match(/([\d\.\-]+)\s+([\d\.\-]+)\s+([\d\.\-]+)\s+([\d\.\-]+)\s+([\d\.\-]+)\s+([\d\.\-]+)\s+Tm/);
                                  if (tmMatch) {
                                      curX = parseFloat(tmMatch[5]);
                                      curY = parseFloat(tmMatch[6]);
                                      continue;
                                  }
              
                                  // Text position: x y Td or TD
                                  var tdMatch = line.match(/([\d\.\-]+)\s+([\d\.\-]+)\s+T[dD]/);
                                  if (tdMatch) {
                                      curX += parseFloat(tdMatch[1]);
                                      curY += parseFloat(tdMatch[2]);
                                      continue;
                                  }
              
                                  // Set leading: TL
                                  var tlMatch = line.match(/([\d\.\-]+)\s+TL/);
                                  if (tlMatch) {
                                      leading = parseFloat(tlMatch[1]);
                                      continue;
                                  }
              
                                  // Move to next line: T*
                                  if (line.match(/T\*/)) {
                                      curY -= leading;
                                      continue;
                                  }
              
                                  // Show text: (string) Tj or <hex> Tj
                                  var tjMatch = line.match(/\(([\s\S]*?)\)\s*Tj/) || line.match(/<([0-9a-fA-F]+)>\s*Tj/);
                                  if (tjMatch) {
                                      var rawText = tjMatch[1];
                                      var fontInfo = pageFonts[curFontTag];
                                      var decoded = KeterPDFParser.decodePDFString(rawText, fontInfo, line.indexOf("<") !== -1);
                                      if (decoded && decoded.length > 0) {
                                          var wResult = KeterPDFParser.calculateSpanWidth(decoded, curSize, fontInfo);
                                          var idTop = pageHeightPt - curY - curSize;
                                          spans.push({
                                              text: decoded,
                                              x: curX,
                                              y: idTop,
                                              fontSize: curSize,
                                              fontTag: curFontTag,
                                              baseFont: fontInfo ? fontInfo.baseFont : "Unknown",
                                              width: wResult.widthPt,
                                              isMeasuredWidth: wResult.isMeasured,
                                              height: curSize * 1.2
                                          });
                                          curX += wResult.widthPt;
                                      }
                                      continue;
                                  }
              
                                  // Show text array: [ (str) 20 (str) ] TJ
                                  var bigTjMatch = line.match(/\[([\s\S]*?)\]\s*TJ/);
                                  if (bigTjMatch) {
                                      var arrayContent = bigTjMatch[1];
                                      var fontInfo2 = pageFonts[curFontTag];
                                      var elemRegex = /\(([\s\S]*?)\)|<([0-9a-fA-F]+)>|([\d\.\-]+)/g;
                                      var elemMatch;
                                      var chunkText = "";
                                      var chunkWidth = 0;
              
                                      while ((elemMatch = elemRegex.exec(arrayContent)) !== null) {
                                          if (elemMatch[1] || elemMatch[2]) {
                                              var itemRaw = elemMatch[1] || elemMatch[2];
                                              var isHex = !!elemMatch[2];
                                              var dStr = KeterPDFParser.decodePDFString(itemRaw, fontInfo2, isHex);
                                              chunkText += dStr;
                                              var wSub = KeterPDFParser.calculateSpanWidth(dStr, curSize, fontInfo2);
                                              chunkWidth += wSub.widthPt;
                                          } else if (elemMatch[3]) {
                                              // Kerning adjustment in 1/1000 text units
                                              var kernVal = parseFloat(elemMatch[3]);
                                              chunkWidth -= (kernVal / 1000.0) * curSize;
                                          }
                                      }
              
                                      if (chunkText && chunkText.length > 0) {
                                          var idTop2 = pageHeightPt - curY - curSize;
                                          spans.push({
                                              text: chunkText,
                                              x: curX,
                                              y: idTop2,
                                              fontSize: curSize,
                                              fontTag: curFontTag,
                                              baseFont: fontInfo2 ? fontInfo2.baseFont : "Unknown",
                                              width: chunkWidth,
                                              isMeasuredWidth: !!(fontInfo2 && fontInfo2.widths && fontInfo2.widths.length > 0),
                                              height: curSize * 1.2
                                          });
                                          curX += chunkWidth;
                                      }
                                  }
                              }
                          }
              
                          return spans;
                      }
                  };
              
                  // ------------------------------------------------------------------------
                  // MODULE 6: SPATIAL LAYOUT & PHYSICAL GUTTER ANALYSIS (NO ARBITRARY %)
                  // ------------------------------------------------------------------------
                  var KeterLayoutEngine = {
                      // Groups raw text spans into lines and detects physical column gutters
                      analyzeLayout: function (spans, pageWidthPt, pageHeightPt) {
                          if (!spans || spans.length === 0) return [];
              
                          // 1. Sort spans: Top-to-Bottom, then Right-to-Left (for Hebrew)
                          spans.sort(function (a, b) {
                              var yDiff = a.y - b.y;
                              if (Math.abs(yDiff) > 3.5) {
                                  return yDiff;
                              }
                              return b.x - a.x; // Right-to-Left
                          });
              
                          // 2. Assemble into visual lines
                          var lines = [];
                          var curLine = null;
                          for (var i = 0; i < spans.length; i++) {
                              var s = spans[i];
                              if (!curLine || Math.abs(s.y - curLine.y) > (s.fontSize * 0.45)) {
                                  curLine = {
                                      y: s.y,
                                      fontSize: s.fontSize,
                                      minX: s.x,
                                      maxX: s.x + s.width,
                                      spans: [s],
                                      text: s.text
                                  };
                                  lines.push(curLine);
                              } else {
                                  curLine.spans.push(s);
                                  curLine.minX = Math.min(curLine.minX, s.x);
                                  curLine.maxX = Math.max(curLine.maxX, s.x + s.width);
                                  curLine.text += " " + s.text;
                              }
                          }
              
                          // 3. Detect Headers & Footers based on vertical margins
                          var headerLines = [];
                          var footerLines = [];
                          var candidateBodyLines = [];
              
                          var topMarginBoundary = pageHeightPt * 0.10;
                          var bottomMarginBoundary = pageHeightPt * 0.90;
              
                          for (var l = 0; l < lines.length; l++) {
                              var line = lines[l];
                              if (line.y < topMarginBoundary && line.fontSize <= 12) {
                                  headerLines.push(line);
                              } else if (line.y > bottomMarginBoundary && line.fontSize <= 11) {
                                  footerLines.push(line);
                              } else {
                                  candidateBodyLines.push(line);
                              }
                          }
              
                          var regions = [];
              
                          if (headerLines.length > 0) {
                              regions.push(this.buildRegion(headerLines, "RunningHeader", "Keter_RunningHeader"));
                          }
              
                          // 4. Physical Gutter Analysis for Body Columns (not fixed arbitrary percentages)
                          var columnRegions = this.detectPhysicalColumns(candidateBodyLines, pageWidthPt);
                          for (var c = 0; c < columnRegions.length; c++) {
                              regions.push(columnRegions[c]);
                          }
              
                          if (footerLines.length > 0) {
                              regions.push(this.buildRegion(footerLines, "PageFooter", "Keter_RunningHeader"));
                          }
              
                          return regions;
                      },
              
                      // Analyzes horizontal gaps between lines to detect true columns
                      detectPhysicalColumns: function (bodyLines, pageWidthPt) {
                          if (!bodyLines || bodyLines.length === 0) return [];
              
                          // Calculate horizontal span frequencies
                          var leftColumnLines = [];
                          var rightColumnLines = [];
                          var fullWidthLines = [];
              
                          var midX = pageWidthPt / 2.0;
                          var minGutterWidth = 14.0; // at least 14pt gutter between columns
              
                          var hasLeft = false;
                          var hasRight = false;
              
                          for (var i = 0; i < bodyLines.length; i++) {
                              var bl = bodyLines[i];
                              var width = bl.maxX - bl.minX;
                              // If a line spans more than 70% of the page, it is a single-column or banner
                              if (width > pageWidthPt * 0.70) {
                                  fullWidthLines.push(bl);
                              } else if (bl.minX > (midX - 10)) {
                                  // Right column (RTL start)
                                  rightColumnLines.push(bl);
                                  hasRight = true;
                              } else if (bl.maxX < (midX + 10)) {
                                  // Left column
                                  leftColumnLines.push(bl);
                                  hasLeft = true;
                              } else {
                                  fullWidthLines.push(bl);
                              }
                          }
              
                          var resultRegions = [];
              
                          // If genuine dual columns are detected
                          if (hasLeft && hasRight && (leftColumnLines.length + rightColumnLines.length > fullWidthLines.length)) {
                              KeterLogger.log("Physical column gutter detected at X ≈ " + Math.round(midX) + " pt.");
                              // Right-to-Left order: Right column first, then Left column
                              if (rightColumnLines.length > 0) {
                                  resultRegions.push(this.buildRegion(rightColumnLines, "Column_Right_RTL", "Keter_Main_Hebrew_RTL"));
                              }
                              if (leftColumnLines.length > 0) {
                                  resultRegions.push(this.buildRegion(leftColumnLines, "Column_Left_RTL", "Keter_Main_Hebrew_RTL"));
                              }
                              if (fullWidthLines.length > 0) {
                                  resultRegions.push(this.buildRegion(fullWidthLines, "Body_Spanning", "Keter_Main_Hebrew_RTL"));
                              }
                          } else {
                              // Single unified text stream
                              resultRegions.push(this.buildRegion(bodyLines, "BodyText", "Keter_Main_Hebrew_RTL"));
                          }
              
                          return resultRegions;
                      },
              
                      buildRegion: function (linesList, roleName, styleName) {
                          var minY = 999999, minX = 999999, maxY = 0, maxX = 0;
                          var textParts = [];
              
                          for (var i = 0; i < linesList.length; i++) {
                              var l = linesList[i];
                              minY = Math.min(minY, l.y);
                              minX = Math.min(minX, l.minX);
                              maxY = Math.max(maxY, l.y + (l.fontSize * 1.25));
                              maxX = Math.max(maxX, l.maxX);
                              textParts.push(l.text);
                          }
              
                          return {
                              role: roleName,
                              styleName: styleName,
                              bounds: [minY, minX, maxY, maxX],
                              content: textParts.join("\r")
                          };
                      }
                  };
              
                  // ------------------------------------------------------------------------
                  // MODULE 7: INDESIGN DOM GENERATOR (VALIDATED API ACCESS)
                  // ------------------------------------------------------------------------
                  var KeterInDesignDOM = {
                      setupDocument: function (templateFile, pageWidthPt, pageHeightPt) {
                          var doc;
                          if (templateFile && templateFile.exists) {
                              KeterLogger.log("Opening existing template: " + templateFile.fsName);
                              doc = app.open(templateFile);
                          } else {
                              KeterLogger.log("Creating new InDesign document: " + Math.round(pageWidthPt) + " x " + Math.round(pageHeightPt) + " pt");
                              doc = app.documents.add();
                              doc.documentPreferences.pageWidth = pageWidthPt + "pt";
                              doc.documentPreferences.pageHeight = pageHeightPt + "pt";
                              doc.documentPreferences.facingPages = true;
                          }
              
                          // CRITICAL FIX: Explicitly lock document measurement units to Points
                          // to prevent coordinate scaling errors when user InDesign uses mm or picas
                          try {
                              doc.viewPreferences.horizontalMeasurementUnits = MeasurementUnits.POINTS;
                              doc.viewPreferences.verticalMeasurementUnits = MeasurementUnits.POINTS;
                              doc.viewPreferences.rulerOrigin = RulerOrigin.PAGE_ORIGIN;
                          } catch (eUnits) {
                              KeterLogger.warn("Measurement unit assignment warning: " + eUnits.message);
                          }
              
                          this.ensureLayers(doc);
                          this.ensureStyles(doc);
              
                          return doc;
                      },
              
                      ensureLayers: function (doc) {
                          // PDF Reference Underlay (locked, bottom)
                          var underlayLayer = doc.layers.itemByName(KeterConfig.layerUnderlay);
                          if (!underlayLayer.isValid) {
                              // UIColors safety check: never reference bare UIColors
                              underlayLayer = doc.layers.add({ name: KeterConfig.layerUnderlay });
                          }
                          underlayLayer.move(LocationOptions.AT_END);
              
                          // Reconstructed Editable Text (active, top)
                          var textLayer = doc.layers.itemByName(KeterConfig.layerText);
                          if (!textLayer.isValid) {
                              textLayer = doc.layers.add({ name: KeterConfig.layerText });
                          }
                          doc.activeLayer = textLayer;
                      },
              
                      ensureStyles: function (doc) {
                          var bestHebrewFont = this.findBestAvailableFont(KeterConfig.hebrewFontFallbacks);
                          KeterLogger.log("Selected primary Hebrew font: " + bestHebrewFont);
              
                          this.createOrUpdateParaStyle(doc, "Keter_Main_Hebrew_RTL", {
                              appliedFont: bestHebrewFont,
                              pointSize: 12,
                              leading: 15.5,
                              justification: Justification.FULLY_JUSTIFIED,
                              isRTL: true
                          });
              
                          this.createOrUpdateParaStyle(doc, "Keter_RunningHeader", {
                              appliedFont: bestHebrewFont,
                              pointSize: 9,
                              leading: 11,
                              justification: Justification.CENTER_ALIGN,
                              isRTL: true
                          });
                      },
              
                      findBestAvailableFont: function (candidates) {
                          for (var i = 0; i < candidates.length; i++) {
                              var candidate = candidates[i];
                              try {
                                  var f = app.fonts.itemByName(candidate);
                                  if (f && f.isValid) {
                                      return candidate;
                                  }
                              } catch (e) {}
                          }
                          KeterLogger.stats.fontSubstitutions.push("Times New Roman (Hebrew fallback)");
                          return "Times New Roman";
                      },
              
                      createOrUpdateParaStyle: function (doc, styleName, props) {
                          var style = doc.paragraphStyles.itemByName(styleName);
                          if (!style.isValid) {
                              style = doc.paragraphStyles.add({ name: styleName });
                          }
              
                          try {
                              if (props.appliedFont) style.appliedFont = props.appliedFont;
                              if (props.pointSize) style.pointSize = props.pointSize;
                              if (props.leading) style.leading = props.leading;
                              if (props.justification) style.justification = props.justification;
              
                              // Enforce Adobe World-Ready Paragraph Composer
                              try {
                                  style.composer = "Adobe World-Ready Paragraph Composer";
                              } catch (e1) {
                                  try {
                                      style.composer = "$ID/Adobe World-Ready Paragraph Composer";
                                  } catch (e2) {}
                              }
              
                              // Enforce Right-to-Left Direction
                              if (props.isRTL) {
                                  try {
                                      style.paragraphDirection = ParagraphDirectionOptions.RIGHT_TO_LEFT_DIRECTION;
                                  } catch (e3) {
                                      try {
                                          style.paragraphDirection = 1278366308;
                                      } catch (e4) {}
                                  }
                              }
                          } catch (ex) {
                              KeterLogger.warn("Style configuration note for '" + styleName + "': " + ex.message);
                          }
                          return style;
                      },
              
                      placePDFUnderlay: function (doc, page, pdfFile, pageNum, opacity) {
                          try {
                              var underlayLayer = doc.layers.itemByName(KeterConfig.layerUnderlay);
                              underlayLayer.locked = false;
                              doc.activeLayer = underlayLayer;
              
                              try {
                                  app.pdfPlacePreferences.pdfCrop = PDFCrop.CROP_MEDIA;
                              } catch (eCrop) {
                                  try { app.pdfPlacePreferences.pdfCrop = PDFCrop.cropMedia; } catch (eCrop2) {}
                              }
                              app.pdfPlacePreferences.pageNumber = pageNum;
                              app.pdfPlacePreferences.transparentBackground = true;
              
                              var placed = page.place(pdfFile, [0, 0])[0];
                              if (placed && placed.isValid && opacity && opacity < 100) {
                                  try {
                                      placed.transparencySettings.blendingSettings.opacity = opacity;
                                  } catch (eOp) {}
                              }
              
                              underlayLayer.locked = true;
                              doc.activeLayer = doc.layers.itemByName(KeterConfig.layerText);
                              KeterLogger.log("Placed 1:1 PDF underlay reference for page " + pageNum);
                              return true;
                          } catch (ex) {
                              KeterLogger.error("Failed to place PDF underlay for page " + pageNum + ": " + ex.message);
                              return false;
                          }
                      },
              
                      createTextFrame: function (doc, page, bounds, content, styleName) {
                          try {
                              var textLayer = doc.layers.itemByName(KeterConfig.layerText);
                              doc.activeLayer = textLayer;
              
                              var top = Math.max(0, bounds[0]);
                              var left = Math.max(0, bounds[1]);
                              var bottom = Math.max(top + 16, bounds[2]);
                              var right = Math.max(left + 24, bounds[3]);
              
                              var frame = page.textFrames.add(textLayer, LocationOptions.UNKNOWN_VALUE, {
                                  geometricBounds: [top, left, bottom, right]
                              });
              
                              // Apply World-Ready Composer directly to frame parent story
                              try {
                                  frame.parentStory.composer = "Adobe World-Ready Paragraph Composer";
                                  frame.parentStory.paragraphDirection = ParagraphDirectionOptions.RIGHT_TO_LEFT_DIRECTION;
                              } catch (eWRC) {}
              
                              // Assign Unicode text contents
                              frame.contents = content;
              
                              var pStyle = doc.paragraphStyles.itemByName(styleName);
                              if (pStyle.isValid) {
                                  frame.parentStory.texts.item(0).applyParagraphStyle(pStyle, true);
                              }
              
                              KeterLogger.stats.textFramesCreated++;
                              KeterLogger.stats.charactersExtracted += content.length;
              
                              if (frame.overflows) {
                                  KeterLogger.stats.oversetFrames++;
                                  KeterLogger.warn("Overset text in frame on page " + page.name + " (" + styleName + "). Frame resized slightly or leading adjustment required.");
                              }
              
                              return frame;
                          } catch (ex) {
                              KeterLogger.error("Error creating InDesign text frame: " + ex.message);
                              return null;
                          }
                      }
                  };
              
                  // ------------------------------------------------------------------------
                  // MODULE 8: USER INTERFACE (SCRIPTUI DIALOG & PROGRESS WINDOW)
                  // ------------------------------------------------------------------------
                  var KeterUI = {
                      showMainDialog: function () {
                          var w = new Window("dialog", KeterConfig.name + " v" + KeterConfig.version);
                          w.orientation = "column";
                          w.alignChildren = ["fill", "top"];
                          w.spacing = 10;
                          w.margins = 16;
              
                          var headerPnl = w.add("panel", undefined, undefined, { borderStyle: "black" });
                          headerPnl.orientation = "column";
                          headerPnl.alignChildren = ["fill", "top"];
                          headerPnl.margins = 10;
              
                          var titleTxt = headerPnl.add("statictext", undefined, "KETER PDF-TO-INDESIGN CONVERSION ENGINE");
                          titleTxt.graphics.font = ScriptUI.newFont(w.graphics.font.name, ScriptUI.FontStyle.BOLD, 14);
                          headerPnl.add("statictext", undefined, "Audited Production Engine: Strict Truth-in-Extraction Architecture");
              
                          // SOURCE PDF
                          var srcPnl = w.add("panel", undefined, "Source PDF & Options");
                          srcPnl.orientation = "column";
                          srcPnl.alignChildren = ["fill", "top"];
                          srcPnl.margins = 12;
                          srcPnl.spacing = 8;
              
                          var pdfRow = srcPnl.add("group");
                          pdfRow.orientation = "row";
                          var pdfPathInput = pdfRow.add("edittext", undefined, "", { readonly: true });
                          pdfPathInput.characters = 42;
                          var browsePdfBtn = pdfRow.add("button", undefined, "Browse PDF...");
              
                          var pdfInfoTxt = srcPnl.add("statictext", undefined, "Select a PDF to inspect structure and content streams.");
              
                          var optGroup = srcPnl.add("group");
                          optGroup.orientation = "column";
                          optGroup.alignChildren = ["left", "top"];
                          optGroup.spacing = 4;
              
                          var underlayCb = optGroup.add("checkbox", undefined, "Place original PDF page as locked 1:1 visual reference underlay");
                          underlayCb.value = true;
              
                          var opacityRow = optGroup.add("group");
                          opacityRow.orientation = "row";
                          opacityRow.add("statictext", undefined, "Underlay Opacity:");
                          var opacityDropdown = opacityRow.add("dropdownlist", undefined, ["25%", "40% (Recommended)", "60%", "100% (Solid)"]);
                          opacityDropdown.selection = 1;
              
                          var pageRangeRow = srcPnl.add("group");
                          pageRangeRow.orientation = "row";
                          pageRangeRow.add("statictext", undefined, "Page Range to Process:");
                          var pageRangeInput = pageRangeRow.add("edittext", undefined, "All");
                          pageRangeInput.characters = 12;
                          pageRangeRow.add("statictext", undefined, "(e.g., 'All', '1-5')");
              
                          var btnRow = w.add("group");
                          btnRow.orientation = "row";
                          btnRow.alignment = "right";
                          var cancelBtn = btnRow.add("button", undefined, "Cancel", { name: "cancel" });
                          var convertBtn = btnRow.add("button", undefined, "Start Conversion", { name: "ok" });
                          convertBtn.enabled = false;
              
                          var selectedFile = null;
              
                          browsePdfBtn.onClick = function () {
                              var f = File.openDialog("Select Source PDF File", "PDF Files:*.pdf;All Files:*.*");
                              if (f) {
                                  selectedFile = f;
                                  pdfPathInput.text = f.fsName;
                                  pdfInfoTxt.text = "Inspecting PDF: " + f.name + "...";
                                  convertBtn.enabled = true;
                              }
                          };
              
                          if (w.show() === 1) {
                              var opacityVal = 40;
                              if (opacityDropdown.selection.index === 0) opacityVal = 25;
                              if (opacityDropdown.selection.index === 1) opacityVal = 40;
                              if (opacityDropdown.selection.index === 2) opacityVal = 60;
                              if (opacityDropdown.selection.index === 3) opacityVal = 100;
              
                              return {
                                  pdfFile: selectedFile,
                                  placeUnderlay: underlayCb.value,
                                  underlayOpacity: opacityVal,
                                  pageRange: pageRangeInput.text
                              };
                          }
                          return null;
                      },
              
                      showProgress: function (title, maxVal) {
                          var pw = new Window("palette", title);
                          pw.orientation = "column";
                          pw.alignChildren = ["fill", "top"];
                          pw.margins = 16;
                          pw.spacing = 10;
              
                          var statusTxt = pw.add("statictext", undefined, "Initializing conversion pipeline...");
                          statusTxt.characters = 45;
              
                          var pBar = pw.add("progressbar", undefined, 0, maxVal);
                          pBar.preferredSize.width = 320;
              
                          pw.center();
                          pw.show();
              
                          return {
                              update: function (val, text) {
                                  pBar.value = val;
                                  if (text) statusTxt.text = text;
                                  pw.update();
                              },
                              close: function () {
                                  pw.close();
                              }
                          };
                      }
                  };
              
                  // ------------------------------------------------------------------------
                  // MODULE 9: CONVERSION PIPELINE (STRICT & HONEST EXTRACTION)
                  // ------------------------------------------------------------------------
                  function parsePageRange(rangeStr, totalPages) {
                      var pages = [];
                      if (!rangeStr || rangeStr.toLowerCase() === "all") {
                          for (var i = 1; i <= totalPages; i++) pages.push(i);
                          return pages;
                      }
                      var parts = rangeStr.split(",");
                      for (var p = 0; p < parts.length; p++) {
                          var part = KeterUtils.trim(parts[p]);
                          if (part.indexOf("-") !== -1) {
                              var range = part.split("-");
                              var start = parseInt(range[0], 10);
                              var end = parseInt(range[1], 10);
                              if (!isNaN(start) && !isNaN(end)) {
                                  for (var r = start; r <= Math.min(end, totalPages); r++) {
                                      pages.push(r);
                                  }
                              }
                          } else {
                              var single = parseInt(part, 10);
                              if (!isNaN(single) && single >= 1 && single <= totalPages) {
                                  pages.push(single);
                              }
                          }
                      }
                      return pages.length > 0 ? pages : [1];
                  }
              
                  function runConversion(options) {
                      KeterLogger.log("Starting Keter conversion: " + options.pdfFile.fsName);
              
                      // 1. Read binary bytes and raw string
                      var bytes = KeterPDFParser.readFileBytes(options.pdfFile);
                      var rawStr = KeterPDFParser.bytesToString(bytes);
              
                      // 2. Index PDF objects
                      var objectMap = KeterPDFParser.indexPDFObjects(rawStr, bytes);
                      var totalObjects = KeterUtils.getKeyCount(objectMap);
                      KeterLogger.log("Indexed " + totalObjects + " indirect PDF objects.");
              
                      // 3. Locate Root Catalog & Pages Tree
                      var catalogObjNum = null;
                      var pagesObjNum = null;
              
                      var rootMatch = rawStr.match(/\/Root\s+(\d+)\s+(\d+)\s+R/);
                      if (rootMatch) {
                          catalogObjNum = parseInt(rootMatch[1], 10);
                          if (objectMap[catalogObjNum]) {
                              var catHeader = objectMap[catalogObjNum].header;
                              var pagesMatch = catHeader.match(/\/Pages\s+(\d+)\s+(\d+)\s+R/);
                              if (pagesMatch) {
                                  pagesObjNum = parseInt(pagesMatch[1], 10);
                              }
                          }
                      }
              
                      // Fallback: search for /Type /Pages object
                      if (!pagesObjNum) {
                          for (var objId in objectMap) {
                              if (objectMap[objId].header.indexOf("/Type /Pages") !== -1 || objectMap[objId].header.indexOf("/Type/Pages") !== -1) {
                                  pagesObjNum = parseInt(objId, 10);
                                  break;
                              }
                          }
                      }
              
                      // 4. Resolve Page Objects through Pages Tree
                      var resolvedPages = [];
                      if (pagesObjNum) {
                          KeterPDFParser.resolvePageTree(pagesObjNum, objectMap, resolvedPages, {}, null);
                      }
              
                      var totalPages = resolvedPages.length;
                      if (totalPages === 0) {
                          // Scan /Type /Page directly if Pages tree was obfuscated
                          for (var pId in objectMap) {
                              if (objectMap[pId].header.indexOf("/Type /Page") !== -1 || objectMap[pId].header.indexOf("/Type/Page") !== -1) {
                                  resolvedPages.push({
                                      pageObjNum: parseInt(pId, 10),
                                      mediaBox: [0, 0, 595.28, 841.89],
                                      header: objectMap[pId].header
                                  });
                              }
                          }
                          totalPages = resolvedPages.length;
                      }
              
                      if (totalPages === 0) {
                          totalPages = 1;
                      }
              
                      KeterLogger.reset(totalPages);
                      KeterLogger.log("Resolved " + totalPages + " pages from PDF object graph.");
              
                      var targetPages = parsePageRange(options.pageRange, totalPages);
                      var progress = KeterUI.showProgress("Reconstructing InDesign Document", targetPages.length + 2);
                      progress.update(0, "Setting up InDesign document & World-Ready styles...");
              
                      // 5. Establish InDesign Document matching initial page geometry
                      var initialMediaBox = (resolvedPages.length > 0 && resolvedPages[0].mediaBox) ? resolvedPages[0].mediaBox : [0, 0, 595.28, 841.89];
                      var pageWidthPt = Math.abs(initialMediaBox[2] - initialMediaBox[0]);
                      var pageHeightPt = Math.abs(initialMediaBox[3] - initialMediaBox[1]);
              
                      var doc = KeterInDesignDOM.setupDocument(null, pageWidthPt, pageHeightPt);
              
                      while (doc.pages.length < targetPages.length) {
                          doc.pages.add(LocationOptions.AT_END);
                      }
              
                      // 6. Process each selected page
                      for (var pIdx = 0; pIdx < targetPages.length; pIdx++) {
                          var pageNum = targetPages[pIdx];
                          var idPage = doc.pages[pIdx];
                          progress.update(pIdx + 1, "Processing Page " + pageNum + " of " + targetPages.length + "...");
              
                          // Always place PDF 1:1 visual reference underlay when requested
                          if (options.placeUnderlay) {
                              KeterInDesignDOM.placePDFUnderlay(doc, idPage, options.pdfFile, pageNum, options.underlayOpacity);
                          }
              
                          var pageMeta = (pageNum - 1 < resolvedPages.length) ? resolvedPages[pageNum - 1] : null;
                          if (!pageMeta) {
                              KeterLogger.recordPageAudit(
                                  pageNum,
                                  "REFERENCE_UNDERLAY_ONLY",
                                  "Page structure could not be resolved from object tree. Visual underlay placed.",
                                  0,
                                  0
                              );
                              continue;
                          }
              
                          // Extract page /Contents object(s)
                          var contentsMatches = [];
                          var cRefRegex = /\/Contents\s+(\d+)\s+(\d+)\s+R/g;
                          var cMatch;
                          while ((cMatch = cRefRegex.exec(pageMeta.header)) !== null) {
                              contentsMatches.push(parseInt(cMatch[1], 10));
                          }
              
                          // Also check for /Contents [ 12 0 R 13 0 R ]
                          var cArrayMatch = pageMeta.header.match(/\/Contents\s*\[([\s\S]*?)\]/);
                          if (cArrayMatch) {
                              var cArrRefs = cArrayMatch[1].match(/(\d+)\s+(\d+)\s+R/g);
                              if (cArrRefs) {
                                  for (var cr = 0; cr < cArrRefs.length; cr++) {
                                      var idNum = parseInt(cArrRefs[cr].split(/\s+/)[0], 10);
                                      if (!KeterUtils.arrayContains(contentsMatches, idNum)) {
                                          contentsMatches.push(idNum);
                                      }
                                  }
                              }
                          }
              
                          // If no contents objects could be located
                          if (contentsMatches.length === 0) {
                              KeterLogger.recordPageAudit(
                                  pageNum,
                                  "REFERENCE_UNDERLAY_ONLY",
                                  "No /Contents stream found (Page may be scanned raster image or use ObjStm). Visual underlay preserved.",
                                  0,
                                  0
                              );
                              continue;
                          }
              
                          // Concatenate all content streams for this page
                          var pageContentText = "";
                          for (var cIdx = 0; cIdx < contentsMatches.length; cIdx++) {
                              var cObjNum = contentsMatches[cIdx];
                              if (objectMap[cObjNum]) {
                                  pageContentText += KeterPDFParser.decompressStream(objectMap[cObjNum]) + "\n";
                              }
                          }
              
                          // Check if content stream has any text operators (BT...ET)
                          if (pageContentText.indexOf("BT") === -1 || pageContentText.indexOf("ET") === -1) {
                              KeterLogger.recordPageAudit(
                                  pageNum,
                                  "REFERENCE_UNDERLAY_ONLY",
                                  "Content stream contains vector/raster artwork only (no text operators BT...ET). Visual underlay preserved.",
                                  0,
                                  0
                              );
                              continue;
                          }
              
                          // Resolve page-specific fonts and ToUnicode CMaps
                          var pageFonts = KeterPDFParser.resolvePageFonts(pageMeta.header, objectMap);
              
                          // Extract text spans
                          var curPageHeightPt = Math.abs(pageMeta.mediaBox[3] - pageMeta.mediaBox[1]);
                          var curPageWidthPt = Math.abs(pageMeta.mediaBox[2] - pageMeta.mediaBox[0]);
                          var spans = KeterPDFParser.extractPageTextSpans(pageContentText, pageFonts, curPageHeightPt);
              
                          if (spans.length === 0) {
                              KeterLogger.recordPageAudit(
                                  pageNum,
                                  "REFERENCE_UNDERLAY_ONLY",
                                  "Text operators could not be mapped to Unicode characters (Font encodings / ToUnicode missing). Visual underlay preserved.",
                                  0,
                                  0
                              );
                              continue;
                          }
              
                          // Gutter and layout analysis
                          var regions = KeterLayoutEngine.analyzeLayout(spans, curPageWidthPt, curPageHeightPt);
              
                          // Create editable InDesign Text Frames
                          var pageCharCount = 0;
                          for (var r = 0; r < regions.length; r++) {
                              var reg = regions[r];
                              KeterInDesignDOM.createTextFrame(doc, idPage, reg.bounds, reg.content, reg.styleName);
                              pageCharCount += reg.content.length;
                          }
              
                          KeterLogger.recordPageAudit(
                              pageNum,
                              "EDITABLE_RECONSTRUCTED",
                              "Successfully reconstructed " + regions.length + " editable text frame(s).",
                              regions.length,
                              pageCharCount
                          );
                      }
              
                      progress.update(targetPages.length + 1, "Saving diagnostic report...");
                      progress.close();
              
                      // 7. Save Audit Report
                      var folder = options.pdfFile.parent;
                      var baseName = options.pdfFile.name.replace(/\.pdf$/i, "");
                      var reportFile = KeterLogger.saveReportFile(folder.fsName, baseName, doc.name, options.pdfFile.fsName);
              
                      // 8. Display Completion Summary Dialog
                      var summaryMsg = "Keter Conversion Completed!\n\n" +
                          "• Total Pages Processed: " + targetPages.length + "\n" +
                          "• Pages Converted to Editable Text: " + KeterLogger.stats.editablePagesCount + "\n" +
                          "• Pages Preserved as 1:1 Visual Underlay: " + KeterLogger.stats.underlayOnlyPagesCount + "\n" +
                          "• Text Frames Created: " + KeterLogger.stats.textFramesCreated + "\n" +
                          "• Recovered Characters: " + KeterLogger.stats.charactersExtracted + "\n" +
                          "• Overset Text Warnings: " + KeterLogger.stats.oversetFrames + "\n\n" +
                          "Diagnostic report saved to:\n" + (reportFile ? reportFile.fsName : "Report generated in log.");
              
                      alert(summaryMsg, KeterConfig.name);
                  }
              
                  // ------------------------------------------------------------------------
                  // ENTRY POINT: SINGLE UNDOABLE TRANSACTION
                  // ------------------------------------------------------------------------
                  function main() {
                      if (typeof app === "undefined" || app.documents === undefined) {
                          alert("This script must be run directly inside Adobe InDesign.", "Keter Engine Error");
                          return;
                      }
              
                      var options = KeterUI.showMainDialog();
                      if (!options) return;
              
                      app.doScript(
                          function () {
                              try {
                                  runConversion(options);
                              } catch (err) {
                                  alert("Conversion encountered a critical error:\n" + err.message + "\nLine: " + (err.line || "unknown"), "Keter Error");
                                  KeterLogger.error("CRITICAL RUNTIME ERROR: " + err.message + " (Line " + (err.line || "unknown") + ")");
                              }
                          },
                          ScriptLanguage.JAVASCRIPT,
                          [],
                          UndoModes.ENTIRE_SCRIPT,
                          "Keter PDF to InDesign Conversion"
                      );
                  }
              
                  main();
              
              })();
              
              
              תגובה 1 תגובה אחרונה
              0

              שלום! נראה שהשיחה הזו מעניינת אותך, אבל עדיין אין לך חשבון.

              נמאס לכם לגלול בין אותם הפוסטים בכל ביקור? כשנרשמים לחשבון, תמיד תחזרו בדיוק למקום שבו הייתם קודם, ותוכלו לבחור לקבל התראות על תגובות חדשות (בין אם במייל, ובין אם בהתראת פוש). תוכלו גם לשמור סימניות ולפרגן ב-upvote לפוסטים כדי להביע הערכה לחברי קהילה אחרים.

              בעזרת התרומה שלך, הפוסט הזה יכול להיות אפילו טוב יותר 💗

              הרשמה התחברות

              • התחברות

              • אין לך חשבון עדיין? הרשמה

              • התחברו או הירשמו כדי לחפש.
              • פוסט ראשון
                פוסט אחרון
              0
              • חוקי הפורום
              • פופולרי
              • לא נפתר
              • משתמשים
              • חיפוש גוגל בפורום
              • צור קשר