zpl-js-helper
Version:
A package that is intended to help with the creation of ZPL labels and templates using JS, with scalable text sizes to prevent overflow and overlap of text.
1 lines • 24.1 kB
Source Map (JSON)
{"version":3,"sources":["../src/index.ts","../src/components/density.ts","../src/components/size.ts","../src/components/template.ts","../src/components/origin.ts","../src/components/text-line.ts","../src/components/padding.ts","../src/components/text-section.ts","../src/components/label-builder.ts"],"sourcesContent":["export * from './components/density';\r\nexport * from './components/template';\r\nexport * from './components/origin';\r\nexport * from './components/section-interface';\r\nexport * from './components/size';\r\nexport * from './components/template';\r\nexport * from './components/text-line';\r\nexport * from './components/text-section';\r\nexport * from './components/fontFamily';\r\nexport * from './components/label-builder';\r\nexport * from './components/record';\r\nexport * from './components/padding';\r\nexport * from './components/record';","export enum PrintDensity {\r\n \"8dpmm\"= 8\r\n}","export class Size{\r\n\r\n heightInDots: number;\r\n widthInDots: number;\r\n constructor(widthInDots: number, heightInDots: number){\r\n this.widthInDots = widthInDots;\r\n this.heightInDots = heightInDots;\r\n }\r\n}","import { Size } from './size';\r\nimport { SectionComponent } from \"./section-interface\";\r\nimport { PrintDensity } from './density';\r\n\r\nexport class Template {\r\n \r\n dotsPerMM: PrintDensity;\r\n size: Size; \r\n sections: SectionComponent[] = [];\r\n \r\n constructor(widthInMM: number, heightInMM: number, dotsPerMM = PrintDensity['8dpmm']) {\r\n \r\n this.dotsPerMM = dotsPerMM;\r\n\r\n const size = new Size(widthInMM * this.dotsPerMM, heightInMM * this.dotsPerMM)\r\n this.size = size;\r\n }\r\n \r\n generateTestZpl(): string {\r\n const start = '^XA';\r\n const end = '^XZ';\r\n \r\n const borderBox = `\r\n ^PW${this.size.widthInDots.toString()}\r\n ^LL${this.size.heightInDots.toString()}\r\n ^FWR\r\n ^FO0,0\r\n ^GB${this.size.heightInDots.toString()},${this.size.widthInDots.toString()},5^FS\r\n ^FB\r\n ^FDTEST^FS\r\n `;\r\n \r\n return start + borderBox + end;\r\n }\r\n \r\n addZPLSection(zplSection: SectionComponent): void {\r\n this.sections.push(zplSection);\r\n }\r\n \r\n getSections(): SectionComponent[]{\r\n return this.sections;\r\n }\r\n }\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n ","export class Origin {\r\n originXInDots: number;\r\n originYInDots:number;\r\n constructor( orginXInDots: number, orginYInDots: number){\r\n if(orginXInDots < 0 || orginYInDots < 0)\r\n throw new Error(\"Origin cannot have negative values.\")\r\n\r\n this.originXInDots = orginXInDots;\r\n this.originYInDots = orginYInDots;\r\n }\r\n}"," export class TextLine {\r\n text: string;\r\n\r\n constructor(text: string){\r\n this.text = text;\r\n }\r\n }","export class Padding {\r\n top: number = 0;\r\n bottom: number = 0;\r\n left: number = 0;\r\n right: number = 0;\r\n \r\n constructor(top: number, bottom: number, left: number, right: number) {\r\n this.top = top;\r\n this.bottom = bottom;\r\n this.left = left;\r\n this.right = right;\r\n }\r\n \r\n totalX() {\r\n return this.left + this.right;\r\n }\r\n \r\n totalY() {\r\n return this.top + this.bottom;\r\n }\r\n }","import { SectionRecord } from \"./record\";\r\nimport { FontFamily } from \"./fontFamily\";\r\nimport { Origin } from \"./origin\";\r\nimport { Padding } from \"./padding\";\r\nimport { SectionComponent } from \"./section-interface\";\r\nimport { Size } from \"./size\";\r\nimport { TextLine } from \"./text-line\";\r\n\r\nexport class TextSection implements SectionComponent {\r\n fontFamily: FontFamily;\r\n padding: Padding;\r\n origin: Origin;\r\n size: Size;\r\n sectionKey: string;\r\n border: string;\r\n borderThickness: number;\r\n orientation: \"portrait\" | \"landscape\";\r\n defaultFontSize: number = 30;\r\n textAlignment: \"J\" | \"L\" | \"C\" | \"R\";\r\n\r\n // Constructor with parameters for all the properties\r\n constructor(\r\n fontFamily: FontFamily,\r\n size: Size,\r\n origin: Origin,\r\n sectionKey: string,\r\n border: string = \"none\", // Defaulting to 'none' if no border is specified\r\n borderThickness: number = 2, // Default border thickness is 2\r\n padding: Padding = new Padding(0, 0, 0, 0),\r\n orientation: \"portrait\" | \"landscape\" = \"portrait\",\r\n textAlignment: \"J\" | \"L\" | \"C\" | \"R\" = \"J\",\r\n fontSize: number = 30\r\n ) {\r\n this.fontFamily = fontFamily;\r\n this.padding = padding;\r\n\r\n this.size = size;\r\n this.origin = origin;\r\n this.sectionKey = sectionKey;\r\n this.border = border;\r\n this.borderThickness = borderThickness;\r\n this.orientation = orientation;\r\n this.textAlignment = textAlignment;\r\n this.defaultFontSize = fontSize;\r\n }\r\n\r\n // Method to generate ZPL string\r\n public generateZpl(values: string[] = []): string {\r\n const content = this.generateText(values);\r\n const border = this.generateSectionBorders();\r\n\r\n return content + border;\r\n }\r\n\r\n // Method to generate borders for the section based on the border property\r\n private generateSectionBorders(): string {\r\n let zpl = \"\";\r\n\r\n // Draw borders based on the border property\r\n const borderThickness = this.borderThickness; // Thickness of the border\r\n\r\n // Top border\r\n if (this.border === \"top\" || this.border === \"all\") {\r\n zpl += `^FO${this.origin.originXInDots},${this.origin.originYInDots}\\r\\n^GB${this.size.widthInDots},${borderThickness},${borderThickness}^FS\\r\\n`;\r\n }\r\n\r\n // Bottom border\r\n if (this.border === \"bottom\" || this.border === \"all\") {\r\n zpl += `^FO${this.origin.originXInDots},${\r\n this.origin.originYInDots + this.size.heightInDots - borderThickness\r\n }\\r\\n^GB${\r\n this.size.widthInDots\r\n },${borderThickness},${borderThickness}^FS\\r\\n`;\r\n }\r\n\r\n // Left border\r\n if (this.border === \"left\" || this.border === \"all\") {\r\n zpl += `^FO${this.origin.originXInDots},${this.origin.originYInDots}\\r\\n^GB${borderThickness},${this.size.heightInDots},${borderThickness}^FS\\r\\n`;\r\n }\r\n\r\n // Right border\r\n if (this.border === \"right\" || this.border === \"all\") {\r\n zpl += `^FO${\r\n this.origin.originXInDots + this.size.widthInDots - borderThickness\r\n },${this.origin.originYInDots}\\r\\n^GB${borderThickness},${\r\n this.size.heightInDots\r\n },${borderThickness}^FS\\r\\n`;\r\n }\r\n\r\n return zpl;\r\n }\r\n\r\n private generateText(values: string[] = []) {\r\n if (values.length === 0) {\r\n return \"\";\r\n }\r\n\r\n let zpl =\r\n this.orientation == \"landscape\"\r\n ? \"^CI28\\r\\n^FWB\\r\\n\"\r\n : \"^CI28\\r\\n^FWN\\r\\n\";\r\n\r\n const totalLengthX = this.size.widthInDots - this.padding.totalX();\r\n const totalLengthY = this.size.heightInDots - this.padding.totalY();\r\n\r\n const availableHeight =\r\n this.orientation == \"landscape\" ? totalLengthX : totalLengthY;\r\n const availableWidth =\r\n this.orientation == \"landscape\" ? totalLengthY : totalLengthX;\r\n\r\n //const textLines: string[]= this.processText(values, availableWidth);\r\n const result = this.processTextUpdated(\r\n values,\r\n availableWidth,\r\n this.defaultFontSize\r\n );\r\n const textLines = result.lines;\r\n const adjustedFontSize = result.fontSize;\r\n\r\n const fontSize = Math.min(\r\n adjustedFontSize,\r\n Math.floor(availableHeight / textLines.length)\r\n );\r\n\r\n const textAlignmentEscape = this.textAlignment == \"C\" ? \"\\\\&\" : \"\";\r\n\r\n for (let i = 0; i < textLines.length; i++) {\r\n const textOriginX =\r\n this.orientation == \"landscape\"\r\n ? i * fontSize + this.origin.originXInDots + this.padding.left\r\n : this.origin.originXInDots + this.padding.left;\r\n\r\n const textOriginY =\r\n this.orientation == \"landscape\"\r\n ? this.origin.originYInDots + this.padding.top\r\n : i * fontSize + this.padding.top + this.origin.originYInDots;\r\n\r\n zpl += `^FO ${textOriginX},${textOriginY}\\r\\n\r\n ^A${this.fontFamily.toString()},${fontSize} ${\r\n this.fontFamily == \"0\" ? \",\" + fontSize.toString() : \"\"\r\n }\\r\\n\r\n ^FB${\r\n this.orientation == \"landscape\" ? totalLengthY : totalLengthX\r\n },,5,${this.textAlignment}\r\n ^FD${textLines[i]}${textAlignmentEscape}^FS\\r\\n`;\r\n }\r\n\r\n return zpl;\r\n }\r\n\r\n private processText(text: string[], availableWidth: number): string[] {\r\n const processedLines: string[] = [];\r\n\r\n const scaleFactor = this.fontFamily == \"0\" ? 2 : 1.25;\r\n text.forEach((line) => {\r\n const words = line.split(\" \");\r\n let currentLine = \"\";\r\n\r\n words.forEach((word) => {\r\n const testLine = currentLine ? `${currentLine} ${word}` : word;\r\n console.log(\r\n `Available Width: ${availableWidth}\\n Testline: ${testLine}\\n Testline width: ${\r\n this.calculateStringLengthRelativeToCharacters(testLine) *\r\n this.defaultFontSize\r\n }`\r\n );\r\n if (\r\n this.calculateStringLengthRelativeToCharacters(testLine) *\r\n (this.defaultFontSize / scaleFactor) <=\r\n availableWidth\r\n ) {\r\n // Add the word to the current line if it fits\r\n currentLine = testLine;\r\n } else {\r\n // If the word doesn't fit, push the current line and start a new one\r\n if (currentLine) processedLines.push(currentLine);\r\n currentLine = word; // Start a new line with the word\r\n }\r\n });\r\n\r\n // Push any remaining text\r\n if (currentLine) processedLines.push(currentLine);\r\n });\r\n\r\n return processedLines;\r\n }\r\n\r\n private calculateStringLengthRelativeToCharacters(text: string): number {\r\n // Define wide and skinny characters\r\n const charWidths: { [key: string]: number } = {\r\n \" \": 117,\r\n \"!\": 113,\r\n '\"': 183,\r\n \"#\": 183,\r\n $: 183,\r\n \"%\": 366,\r\n \"&\": 235,\r\n \"'\": 113,\r\n \"(\": 113,\r\n \")\": 113,\r\n \"*\": 183,\r\n \"+\": 330,\r\n \",\": 110,\r\n \"-\": 200,\r\n \".\": 113,\r\n \"/\": 113,\r\n \"0\": 183,\r\n \"1\": 183,\r\n \"2\": 183,\r\n \"3\": 183,\r\n \"4\": 183,\r\n \"5\": 183,\r\n \"6\": 183,\r\n \"7\": 183,\r\n \"8\": 183,\r\n \"9\": 183,\r\n \":\": 117,\r\n \";\": 117,\r\n \"<\": 366,\r\n \"=\": 366,\r\n \">\": 366,\r\n \"?\": 165,\r\n \"@\": 330,\r\n A: 220,\r\n B: 220,\r\n C: 206,\r\n D: 235,\r\n E: 194,\r\n F: 194,\r\n G: 220,\r\n H: 235,\r\n I: 110,\r\n J: 173,\r\n K: 220,\r\n L: 183,\r\n M: 300,\r\n N: 235,\r\n O: 220,\r\n P: 220,\r\n Q: 220,\r\n R: 220,\r\n S: 206,\r\n T: 183,\r\n U: 235,\r\n V: 206,\r\n W: 300,\r\n X: 206,\r\n Y: 206,\r\n Z: 194,\r\n \"[\": 113,\r\n \"\\\\\": 192,\r\n \"]\": 113,\r\n \"^\": 192,\r\n _: 194,\r\n \"`\": 113,\r\n a: 173,\r\n b: 194,\r\n c: 173,\r\n d: 194,\r\n e: 183,\r\n f: 106,\r\n g: 194,\r\n h: 194,\r\n i: 100,\r\n j: 100,\r\n k: 173,\r\n l: 100,\r\n m: 300,\r\n n: 194,\r\n o: 183,\r\n p: 194,\r\n q: 194,\r\n r: 126,\r\n s: 165,\r\n t: 106,\r\n u: 194,\r\n v: 173,\r\n w: 253,\r\n x: 173,\r\n y: 173,\r\n z: 150,\r\n \"{\": 194,\r\n \"|\": 194,\r\n \"}\": 194,\r\n \"~\": 192,\r\n };\r\n\r\n let relativeStringLength = 0;\r\n\r\n for (const char of text) {\r\n // If the character exists in the mapping, add the corresponding value\r\n relativeStringLength += charWidths[char] || 192; // Default to 186 if the char is not in the map\r\n }\r\n //console.log(text, relativeStringLength / 398);\r\n return relativeStringLength / 192;\r\n }\r\n\r\n private processTextUpdated(\r\n lines: string[],\r\n availableWidth: number,\r\n desiredFontSize: number\r\n ): { lines: string[]; fontSize: number } {\r\n let fontSize = desiredFontSize;\r\n const minFontSize = this.fontFamily == \"0\" ? 20 : 20;\r\n const scaleFactor =\r\n this.fontFamily == \"0\" ? 2 : this.fontFamily == \"C\" ? 1.25 : 1.25;\r\n // Try to fit text by reducing font size first\r\n let maxLineWidth = Math.max(\r\n ...lines.map(\r\n (line) =>\r\n this.calculateStringLengthRelativeToCharacters(line) *\r\n (fontSize / scaleFactor)\r\n )\r\n );\r\n\r\n console.log(lines, maxLineWidth, availableWidth);\r\n\r\n while (maxLineWidth > availableWidth && fontSize > minFontSize) {\r\n fontSize -= 1; // Reduce font size\r\n maxLineWidth = Math.max(\r\n ...lines.map(\r\n (line) =>\r\n this.calculateStringLengthRelativeToCharacters(line) *\r\n (fontSize / scaleFactor)\r\n )\r\n );\r\n }\r\n\r\n // If the font size reaches the minimum and still doesn't fit, break lines up using the min fontsize;\r\n if (fontSize <= minFontSize && maxLineWidth > availableWidth) {\r\n lines = this.breakUpLines(\r\n lines,\r\n availableWidth,\r\n minFontSize,\r\n scaleFactor\r\n );\r\n }\r\n\r\n return { lines, fontSize };\r\n }\r\n\r\n private breakUpLines(\r\n lines: string[],\r\n availableWidth: number,\r\n fontSize: number,\r\n scaleFactor: number\r\n ): string[] {\r\n const processedLines: string[] = [];\r\n lines.forEach((line) => {\r\n const words = line.split(\" \");\r\n let currentLine = \"\";\r\n\r\n words.forEach((word) => {\r\n const testLine = currentLine ? `${currentLine} ${word}` : word;\r\n\r\n if (\r\n this.calculateStringLengthRelativeToCharacters(testLine) *\r\n (fontSize / scaleFactor) <=\r\n availableWidth\r\n ) {\r\n // Add the word to the current line if it fits\r\n currentLine = testLine;\r\n } else {\r\n // If the word doesn't fit, push the current line and start a new one\r\n if (currentLine) processedLines.push(currentLine);\r\n currentLine = word; // Start a new line with the word\r\n }\r\n });\r\n\r\n // Push any remaining text\r\n if (currentLine) processedLines.push(currentLine);\r\n });\r\n\r\n return processedLines;\r\n }\r\n}\r\n","import { SectionRecord } from \"./record\";\r\nimport { SectionComponent } from \"./section-interface\";\r\nimport { Template } from \"./template\";\r\n\r\nexport class LabelBuilder {\r\n private template: Template;\r\n private records: SectionRecord[];\r\n \r\n constructor(template: Template, records: SectionRecord[]) {\r\n this.template = template;\r\n this.records = records;\r\n }\r\n \r\n // This method will generate ZPL for all records based on the template sections\r\n generateZPL(): string {\r\n const start = '^XA\\r\\n';\r\n const setup = `^PW${this.template.size.widthInDots.toString()}\\r\\n^LL${this.template.size.heightInDots.toString()}\\r\\n`;\r\n const end = '^XZ';\r\n \r\n let zplCode = '';\r\n \r\n this.records.forEach((record) => {\r\n \r\n // Apply each record to the sections of the template and generate ZPL\r\n const content = this.template.getSections()\r\n .map((section) => this.generateSectionZPL(section, record))\r\n .join('\\r\\n');\r\n\r\n const zplCodeForSection = start + setup + content + end;\r\n\r\n zplCode += zplCodeForSection;\r\n });\r\n \r\n return zplCode;\r\n }\r\n \r\n // Method to generate ZPL for each section based on the current record\r\n private generateSectionZPL(section: SectionComponent, record: SectionRecord): string {\r\n if (record[section.sectionKey]) {\r\n \r\n return section.generateZpl(record[section.sectionKey]);\r\n }\r\n return ''; // Return an empty string if no matching data\r\n }\r\n }"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAO,IAAK,eAAL,kBAAKA,kBAAL;AACH,EAAAA,4BAAA,WAAS,KAAT;AADQ,SAAAA;AAAA,GAAA;;;ACAL,IAAM,OAAN,MAAU;AAAA,EAIb,YAAY,aAAqB,cAAqB;AAClD,SAAK,cAAc;AACnB,SAAK,eAAe;AAAA,EACxB;AACJ;;;ACJO,IAAM,WAAN,MAAe;AAAA,EAMlB,YAAY,WAAmB,YAAoB,2BAAmC;AAFtF,oBAA+B,CAAC;AAI9B,SAAK,YAAY;AAEjB,UAAM,OAAO,IAAI,KAAK,YAAY,KAAK,WAAW,aAAa,KAAK,SAAS;AAC7E,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,kBAA0B;AACxB,UAAM,QAAQ;AACd,UAAM,MAAM;AAEZ,UAAM,YAAY;AAAA,WACb,KAAK,KAAK,YAAY,SAAS,CAAC;AAAA,WAChC,KAAK,KAAK,aAAa,SAAS,CAAC;AAAA;AAAA;AAAA,WAGjC,KAAK,KAAK,aAAa,SAAS,CAAC,IAAI,KAAK,KAAK,YAAY,SAAS,CAAC;AAAA;AAAA;AAAA;AAK1E,WAAO,QAAQ,YAAY;AAAA,EAC7B;AAAA,EAEA,cAAc,YAAoC;AAChD,SAAK,SAAS,KAAK,UAAU;AAAA,EAC/B;AAAA,EAEA,cAAiC;AAC/B,WAAO,KAAK;AAAA,EACd;AACF;;;AC1CK,IAAM,SAAN,MAAa;AAAA,EAGhB,YAAa,cAAsB,cAAqB;AACpD,QAAG,eAAe,KAAK,eAAe;AAClC,YAAM,IAAI,MAAM,qCAAqC;AAEzD,SAAK,gBAAgB;AACrB,SAAK,gBAAgB;AAAA,EACzB;AACJ;;;ACVQ,IAAM,WAAN,MAAe;AAAA,EAGnB,YAAY,MAAa;AACrB,SAAK,OAAO;AAAA,EAChB;AACF;;;ACNK,IAAM,UAAN,MAAc;AAAA,EAMjB,YAAY,KAAa,QAAgB,MAAc,OAAe;AALtE,eAAc;AACd,kBAAiB;AACjB,gBAAe;AACf,iBAAgB;AAGd,SAAK,MAAM;AACX,SAAK,SAAS;AACd,SAAK,OAAO;AACZ,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,SAAS;AACP,WAAO,KAAK,OAAO,KAAK;AAAA,EAC1B;AAAA,EAEA,SAAS;AACP,WAAO,KAAK,MAAM,KAAK;AAAA,EACzB;AACF;;;ACZK,IAAM,cAAN,MAA8C;AAAA;AAAA,EAanD,YACE,YACA,MACA,QACA,YACA,SAAiB,QACjB,kBAA0B,GAC1B,UAAmB,IAAI,QAAQ,GAAG,GAAG,GAAG,CAAC,GACzC,cAAwC,YACxC,gBAAuC,KACvC,WAAmB,IACnB;AAfF,2BAA0B;AAgBxB,SAAK,aAAa;AAClB,SAAK,UAAU;AAEf,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,aAAa;AAClB,SAAK,SAAS;AACd,SAAK,kBAAkB;AACvB,SAAK,cAAc;AACnB,SAAK,gBAAgB;AACrB,SAAK,kBAAkB;AAAA,EACzB;AAAA;AAAA,EAGO,YAAY,SAAmB,CAAC,GAAW;AAChD,UAAM,UAAU,KAAK,aAAa,MAAM;AACxC,UAAM,SAAS,KAAK,uBAAuB;AAE3C,WAAO,UAAU;AAAA,EACnB;AAAA;AAAA,EAGQ,yBAAiC;AACvC,QAAI,MAAM;AAGV,UAAM,kBAAkB,KAAK;AAG7B,QAAI,KAAK,WAAW,SAAS,KAAK,WAAW,OAAO;AAClD,aAAO,MAAM,KAAK,OAAO,aAAa,IAAI,KAAK,OAAO,aAAa;AAAA,KAAU,KAAK,KAAK,WAAW,IAAI,eAAe,IAAI,eAAe;AAAA;AAAA,IAC1I;AAGA,QAAI,KAAK,WAAW,YAAY,KAAK,WAAW,OAAO;AACrD,aAAO,MAAM,KAAK,OAAO,aAAa,IACpC,KAAK,OAAO,gBAAgB,KAAK,KAAK,eAAe,eACvD;AAAA,KACE,KAAK,KAAK,WACZ,IAAI,eAAe,IAAI,eAAe;AAAA;AAAA,IACxC;AAGA,QAAI,KAAK,WAAW,UAAU,KAAK,WAAW,OAAO;AACnD,aAAO,MAAM,KAAK,OAAO,aAAa,IAAI,KAAK,OAAO,aAAa;AAAA,KAAU,eAAe,IAAI,KAAK,KAAK,YAAY,IAAI,eAAe;AAAA;AAAA,IAC3I;AAGA,QAAI,KAAK,WAAW,WAAW,KAAK,WAAW,OAAO;AACpD,aAAO,MACL,KAAK,OAAO,gBAAgB,KAAK,KAAK,cAAc,eACtD,IAAI,KAAK,OAAO,aAAa;AAAA,KAAU,eAAe,IACpD,KAAK,KAAK,YACZ,IAAI,eAAe;AAAA;AAAA,IACrB;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,aAAa,SAAmB,CAAC,GAAG;AAC1C,QAAI,OAAO,WAAW,GAAG;AACvB,aAAO;AAAA,IACT;AAEA,QAAI,MACF,KAAK,eAAe,cAChB,sBACA;AAEN,UAAM,eAAe,KAAK,KAAK,cAAc,KAAK,QAAQ,OAAO;AACjE,UAAM,eAAe,KAAK,KAAK,eAAe,KAAK,QAAQ,OAAO;AAElE,UAAM,kBACJ,KAAK,eAAe,cAAc,eAAe;AACnD,UAAM,iBACJ,KAAK,eAAe,cAAc,eAAe;AAGnD,UAAM,SAAS,KAAK;AAAA,MAClB;AAAA,MACA;AAAA,MACA,KAAK;AAAA,IACP;AACA,UAAM,YAAY,OAAO;AACzB,UAAM,mBAAmB,OAAO;AAEhC,UAAM,WAAW,KAAK;AAAA,MACpB;AAAA,MACA,KAAK,MAAM,kBAAkB,UAAU,MAAM;AAAA,IAC/C;AAEA,UAAM,sBAAsB,KAAK,iBAAiB,MAAM,QAAQ;AAEhE,aAAS,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;AACzC,YAAM,cACJ,KAAK,eAAe,cAChB,IAAI,WAAW,KAAK,OAAO,gBAAgB,KAAK,QAAQ,OACxD,KAAK,OAAO,gBAAgB,KAAK,QAAQ;AAE/C,YAAM,cACJ,KAAK,eAAe,cAChB,KAAK,OAAO,gBAAgB,KAAK,QAAQ,MACzC,IAAI,WAAW,KAAK,QAAQ,MAAM,KAAK,OAAO;AAEpD,aAAO,OAAO,WAAW,IAAI,WAAW;AAAA;AAAA,YAClC,KAAK,WAAW,SAAS,CAAC,IAAI,QAAQ,IAC1C,KAAK,cAAc,MAAM,MAAM,SAAS,SAAS,IAAI,EACvD;AAAA;AAAA,aAEI,KAAK,eAAe,cAAc,eAAe,YACnD,OAAO,KAAK,aAAa;AAAA,aACpB,UAAU,CAAC,CAAC,GAAG,mBAAmB;AAAA;AAAA,IAC3C;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,YAAY,MAAgB,gBAAkC;AACpE,UAAM,iBAA2B,CAAC;AAElC,UAAM,cAAc,KAAK,cAAc,MAAM,IAAI;AACjD,SAAK,QAAQ,CAAC,SAAS;AACrB,YAAM,QAAQ,KAAK,MAAM,GAAG;AAC5B,UAAI,cAAc;AAElB,YAAM,QAAQ,CAAC,SAAS;AACtB,cAAM,WAAW,cAAc,GAAG,WAAW,IAAI,IAAI,KAAK;AAC1D,gBAAQ;AAAA,UACN,oBAAoB,cAAc;AAAA,aAAgB,QAAQ;AAAA,mBACxD,KAAK,0CAA0C,QAAQ,IACvD,KAAK,eACP;AAAA,QACF;AACA,YACE,KAAK,0CAA0C,QAAQ,KACpD,KAAK,kBAAkB,gBAC1B,gBACA;AAEA,wBAAc;AAAA,QAChB,OAAO;AAEL,cAAI,YAAa,gBAAe,KAAK,WAAW;AAChD,wBAAc;AAAA,QAChB;AAAA,MACF,CAAC;AAGD,UAAI,YAAa,gBAAe,KAAK,WAAW;AAAA,IAClD,CAAC;AAED,WAAO;AAAA,EACT;AAAA,EAEQ,0CAA0C,MAAsB;AAEtE,UAAM,aAAwC;AAAA,MAC5C,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,GAAG;AAAA,MACH,KAAK;AAAA,MACL,SAAS;AAAA,MACT,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,QAAQ;AAAA,MACR,KAAK;AAAA,MACL,QAAQ;AAAA,MACR,KAAK;AAAA,MACL,KAAK;AAAA,MACL,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,KAAK;AAAA,MACL,MAAM;AAAA,MACN,KAAK;AAAA,MACL,KAAK;AAAA,MACL,GAAG;AAAA,MACH,KAAK;AAAA,MACL,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,IACP;AAEA,QAAI,uBAAuB;AAE3B,eAAW,QAAQ,MAAM;AAEvB,8BAAwB,WAAW,IAAI,KAAK;AAAA,IAC9C;AAEA,WAAO,uBAAuB;AAAA,EAChC;AAAA,EAEQ,mBACN,OACA,gBACA,iBACuC;AACvC,QAAI,WAAW;AACf,UAAM,cAAc,KAAK,cAAc,MAAM,KAAK;AAClD,UAAM,cACJ,KAAK,cAAc,MAAM,IAAI,KAAK,cAAc,MAAM,OAAO;AAE/D,QAAI,eAAe,KAAK;AAAA,MACtB,GAAG,MAAM;AAAA,QACP,CAAC,SACC,KAAK,0CAA0C,IAAI,KAClD,WAAW;AAAA,MAChB;AAAA,IACF;AAEA,YAAQ,IAAI,OAAO,cAAc,cAAc;AAE/C,WAAO,eAAe,kBAAkB,WAAW,aAAa;AAC9D,kBAAY;AACZ,qBAAe,KAAK;AAAA,QAClB,GAAG,MAAM;AAAA,UACP,CAAC,SACC,KAAK,0CAA0C,IAAI,KAClD,WAAW;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AAGA,QAAI,YAAY,eAAe,eAAe,gBAAgB;AAC5D,cAAQ,KAAK;AAAA,QACX;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,WAAO,EAAE,OAAO,SAAS;AAAA,EAC3B;AAAA,EAEQ,aACN,OACA,gBACA,UACA,aACU;AACV,UAAM,iBAA2B,CAAC;AAClC,UAAM,QAAQ,CAAC,SAAS;AACtB,YAAM,QAAQ,KAAK,MAAM,GAAG;AAC5B,UAAI,cAAc;AAElB,YAAM,QAAQ,CAAC,SAAS;AACtB,cAAM,WAAW,cAAc,GAAG,WAAW,IAAI,IAAI,KAAK;AAE1D,YACE,KAAK,0CAA0C,QAAQ,KACpD,WAAW,gBACd,gBACA;AAEA,wBAAc;AAAA,QAChB,OAAO;AAEL,cAAI,YAAa,gBAAe,KAAK,WAAW;AAChD,wBAAc;AAAA,QAChB;AAAA,MACF,CAAC;AAGD,UAAI,YAAa,gBAAe,KAAK,WAAW;AAAA,IAClD,CAAC;AAED,WAAO;AAAA,EACT;AACF;;;ACnXO,IAAM,eAAN,MAAmB;AAAA,EAItB,YAAY,UAAoB,SAA0B;AACxD,SAAK,WAAW;AAChB,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA,EAGA,cAAsB;AACpB,UAAM,QAAQ;AACd,UAAM,QAAQ,MAAM,KAAK,SAAS,KAAK,YAAY,SAAS,CAAC;AAAA,KAAU,KAAK,SAAS,KAAK,aAAa,SAAS,CAAC;AAAA;AACjH,UAAM,MAAM;AAEZ,QAAI,UAAU;AAEd,SAAK,QAAQ,QAAQ,CAAC,WAAW;AAG/B,YAAM,UAAU,KAAK,SAAS,YAAY,EACvC,IAAI,CAAC,YAAY,KAAK,mBAAmB,SAAS,MAAM,CAAC,EACzD,KAAK,MAAM;AAEd,YAAM,oBAAoB,QAAQ,QAAQ,UAAU;AAEpD,iBAAW;AAAA,IACb,CAAC;AAED,WAAO;AAAA,EACT;AAAA;AAAA,EAGQ,mBAAmB,SAA2B,QAA+B;AACnF,QAAI,OAAO,QAAQ,UAAU,GAAG;AAE9B,aAAO,QAAQ,YAAY,OAAO,QAAQ,UAAU,CAAC;AAAA,IACvD;AACA,WAAO;AAAA,EACT;AACF;","names":["PrintDensity"]}