tests
1
packages/content/ref/pdf-to-images/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
./tests/out
|
||||
151
packages/content/ref/pdf-to-images/README.md
Normal file
@ -0,0 +1,151 @@
|
||||
# @polymech/pdf
|
||||
|
||||
## Installation
|
||||
|
||||
1. **Clone the repository (optional):**
|
||||
```bash
|
||||
git clone <repository-url> # Replace with your repository URL
|
||||
cd <directory-name> # e.g., cd pdf
|
||||
```
|
||||
|
||||
2. **Install dependencies:**
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
3. **Build the project:**
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
## CLI Usage
|
||||
|
||||
When running from within the cloned project directory after building:
|
||||
|
||||
```bash
|
||||
npm start -- convert [options]
|
||||
# or directly execute the built script
|
||||
node dist/index.js convert [options]
|
||||
```
|
||||
|
||||
*(Note: If you publish this package and install it elsewhere, you might execute it differently, potentially using `npx @polymech/pdf convert ...` if a `bin` entry is added to `package.json`)*
|
||||
|
||||
Available command: `convert` - Convert PDF to images
|
||||
|
||||
### Options for `convert` command:
|
||||
|
||||
* `-i, --input <string>`: Input PDF file (required)
|
||||
* `-o, --output <string>`: Output directory prefix for images (required)
|
||||
* `--dpi <number>`: DPI for output images (default: 300)
|
||||
* `--format <string>`: Output image format (choices: 'png', 'jpg', default: 'png')
|
||||
* `-s, --startPage <number>`: First page to convert (1-based)
|
||||
* `-e, --endPage <number>`: Last page to convert (1-based, inclusive)
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
node dist/index.js convert -i mydocument.pdf -o output/image
|
||||
```
|
||||
|
||||
This will generate images like `output/image_1.png`, `output/image_2.png`, etc.
|
||||
|
||||
Another example (using JPG format and 150 DPI):
|
||||
|
||||
```bash
|
||||
node dist/index.js convert -i report.pdf -o images/report_page --format jpg --dpi 150
|
||||
```
|
||||
|
||||
This generates `images/report_page_1.jpg`, `images/report_page_2.jpg`, etc.
|
||||
|
||||
Example specifying a page range (pages 3 to 5):
|
||||
|
||||
```bash
|
||||
node dist/index.js convert -i long_doc.pdf -o pages/doc_pg --startPage 3 --endPage 5
|
||||
```
|
||||
|
||||
This generates `pages/doc_pg_3.png`, `pages/doc_pg_4.png`, `pages/doc_pg_5.png`.
|
||||
|
||||
## API Usage
|
||||
|
||||
```typescript
|
||||
import { convertPdfToImages, ImageFormat, PdfToImageOptions } from './dist/lib/pdf'; // Adjust path based on your project structure
|
||||
import { readFile } from 'node:fs/promises';
|
||||
|
||||
async function example() {
|
||||
try {
|
||||
const pdfBuffer = await readFile('mydocument.pdf');
|
||||
|
||||
const options: PdfToImageOptions = {
|
||||
outputPathPrefix: 'output/image',
|
||||
dpi: 300,
|
||||
format: 'png'
|
||||
};
|
||||
|
||||
const outputFilePaths = await convertPdfToImages(pdfBuffer, options);
|
||||
console.log('Generated images:', outputFilePaths);
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
}
|
||||
}
|
||||
|
||||
example();
|
||||
```
|
||||
|
||||
Example using JPG format:
|
||||
|
||||
```typescript
|
||||
import { convertPdfToImages, PdfToImageOptions } from './dist/lib/pdf'; // Adjust path
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import { Logger } from 'tslog'; // Assuming you want logging
|
||||
|
||||
async function exampleJpg() {
|
||||
const logger = new Logger();
|
||||
try {
|
||||
const pdfBuffer = await readFile('report.pdf');
|
||||
const options: PdfToImageOptions = {
|
||||
outputPathPrefix: 'images/report_page',
|
||||
dpi: 150,
|
||||
format: 'jpg',
|
||||
};
|
||||
const outputFilePaths = await convertPdfToImages(pdfBuffer, options);
|
||||
logger.info('Generated JPG images:', outputFilePaths);
|
||||
} catch (error) {
|
||||
logger.error('Error generating JPGs:', error);
|
||||
}
|
||||
}
|
||||
|
||||
exampleJpg();
|
||||
```
|
||||
|
||||
Example with specific page range:
|
||||
|
||||
```typescript
|
||||
import { convertPdfToImages, PdfToImageOptions } from './dist/lib/pdf'; // Adjust path
|
||||
import { readFile } from 'node:fs/promises';
|
||||
|
||||
async function examplePageRange() {
|
||||
try {
|
||||
const pdfBuffer = await readFile('long_doc.pdf');
|
||||
const options: PdfToImageOptions = {
|
||||
outputPathPrefix: 'pages/doc_pg',
|
||||
dpi: 200,
|
||||
format: 'png',
|
||||
startPage: 3,
|
||||
endPage: 5
|
||||
};
|
||||
const outputFilePaths = await convertPdfToImages(pdfBuffer, options);
|
||||
console.log('Generated specific pages:', outputFilePaths);
|
||||
} catch (error) {
|
||||
console.error('Error generating page range:', error);
|
||||
}
|
||||
}
|
||||
|
||||
examplePageRange();
|
||||
```
|
||||
|
||||
### Exports
|
||||
|
||||
* `convertPdfToImages(pdfData: Buffer, options: PdfToImageOptions): Promise<string[]>`: Converts a PDF buffer to images.
|
||||
* `ImageFormat`: Type alias for `'png' | 'jpg'`.
|
||||
* `PdfToImageOptions`: Interface for conversion options (`outputPathPrefix`, `dpi`, `format`, optional `startPage`, optional `endPage`, optional `logger`).
|
||||
```
|
||||
@ -2,8 +2,9 @@ import { Logger } from 'tslog';
|
||||
import { ConvertCommandSchema } from '../types.js';
|
||||
import { convertPdfToImages } from '../lib/pdf.js';
|
||||
import { existsSync } from 'node:fs';
|
||||
import { dirname } from 'node:path';
|
||||
import { dirname, sep, extname, basename } from 'node:path';
|
||||
import { mkdir, readFile } from 'node:fs/promises';
|
||||
import * as z from 'zod';
|
||||
export const command = 'convert';
|
||||
export const desc = 'Convert PDF to images';
|
||||
export const builder = {
|
||||
@ -16,7 +17,7 @@ export const builder = {
|
||||
output: {
|
||||
alias: 'o',
|
||||
type: 'string',
|
||||
description: 'Output directory for images',
|
||||
description: 'Output directory prefix for images',
|
||||
demandOption: true
|
||||
},
|
||||
dpi: {
|
||||
@ -29,6 +30,18 @@ export const builder = {
|
||||
choices: ['png', 'jpg'],
|
||||
default: 'png',
|
||||
description: 'Output image format'
|
||||
},
|
||||
startPage: {
|
||||
alias: 's',
|
||||
type: 'number',
|
||||
description: 'First page to convert (1-based)',
|
||||
requiresArg: true
|
||||
},
|
||||
endPage: {
|
||||
alias: 'e',
|
||||
type: 'number',
|
||||
description: 'Last page to convert (1-based, inclusive)',
|
||||
requiresArg: true
|
||||
}
|
||||
};
|
||||
export async function handler(argv) {
|
||||
@ -38,20 +51,40 @@ export async function handler(argv) {
|
||||
if (!existsSync(config.input)) {
|
||||
throw new Error(`Input file ${config.input} does not exist`);
|
||||
}
|
||||
await mkdir(dirname(config.output), { recursive: true });
|
||||
// Ensure the full output directory path exists
|
||||
// config.output is the prefix, e.g., "tests/e5dc/image"
|
||||
// We need to create the directory part, e.g., "tests/e5dc/"
|
||||
const outputDir = dirname(config.output);
|
||||
// Check if output path itself ends with a separator or if the base name contains no extension
|
||||
// This helps determine if the output path is intended as a directory.
|
||||
const isOutputDir = config.output.endsWith(sep) || config.output.endsWith('/') || !extname(basename(config.output));
|
||||
const dirToCreate = isOutputDir ? config.output : outputDir;
|
||||
// Check if dirToCreate is not empty and not the root directory before creating
|
||||
if (dirToCreate && dirToCreate !== '.' && dirToCreate !== '/' && dirToCreate !== sep) {
|
||||
await mkdir(dirToCreate, { recursive: true });
|
||||
logger.info(`Ensured output directory exists: ${dirToCreate}`);
|
||||
}
|
||||
logger.info(`Converting PDF ${config.input} to images...`);
|
||||
const pdfData = await readFile(config.input);
|
||||
const outputFiles = await convertPdfToImages(pdfData, {
|
||||
outputPathPrefix: config.output,
|
||||
dpi: config.dpi,
|
||||
format: config.format,
|
||||
startPage: config.startPage,
|
||||
endPage: config.endPage,
|
||||
logger
|
||||
});
|
||||
logger.info('Conversion completed successfully');
|
||||
logger.info(`Generated ${outputFiles.length} images`);
|
||||
}
|
||||
catch (error) {
|
||||
logger.error('Error during conversion:', error);
|
||||
if (error instanceof z.ZodError) {
|
||||
logger.error('Invalid arguments:', error.flatten());
|
||||
}
|
||||
else {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
logger.error('Error during conversion:', message, error);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
12
packages/content/ref/pdf-to-images/dist/index.js
vendored
@ -1,7 +1,15 @@
|
||||
import yargs from 'yargs';
|
||||
import { hideBin } from 'yargs/helpers';
|
||||
import * as convertCommand from './commands/convert.js';
|
||||
const commandModule = {
|
||||
command: convertCommand.command,
|
||||
describe: convertCommand.desc,
|
||||
builder: convertCommand.builder,
|
||||
handler: convertCommand.handler
|
||||
};
|
||||
yargs(hideBin(process.argv))
|
||||
.command(require('./commands/convert.js'))
|
||||
.command(commandModule)
|
||||
.demandCommand(1, 'You need to specify a command')
|
||||
.strict()
|
||||
.argv;
|
||||
.help()
|
||||
.parse();
|
||||
|
||||
@ -7,17 +7,32 @@ export async function convertPdfToImages(pdfData, options) {
|
||||
try {
|
||||
const doc = mupdf.Document.openDocument(pdfData, 'pdf');
|
||||
const pageCount = doc.countPages();
|
||||
logger.info(`Processing ${pageCount} pages`);
|
||||
for (let i = 0; i < pageCount; i++) {
|
||||
// Validate and determine page range (adjusting for 0-based index)
|
||||
const start = (options.startPage ?? 1) - 1;
|
||||
const end = (options.endPage ?? pageCount) - 1;
|
||||
if (start < 0 || start >= pageCount) {
|
||||
throw new Error(`startPage (${options.startPage}) is out of valid range (1-${pageCount})`);
|
||||
}
|
||||
if (end < 0 || end >= pageCount) {
|
||||
throw new Error(`endPage (${options.endPage}) is out of valid range (1-${pageCount})`);
|
||||
}
|
||||
if (start > end) {
|
||||
// This should also be caught by Zod schema, but good to double-check
|
||||
throw new Error(`startPage (${options.startPage}) cannot be greater than endPage (${options.endPage})`);
|
||||
}
|
||||
const numPagesToProcess = end - start + 1;
|
||||
logger.info(`Processing pages ${start + 1} to ${end + 1} (${numPagesToProcess} pages) of ${pageCount} total`);
|
||||
for (let i = start; i <= end; i++) {
|
||||
const pageNumber = i + 1; // User-facing page number (1-based)
|
||||
const page = doc.loadPage(i);
|
||||
const pixmap = page.toPixmap([1, 0, 0, 1, 0, 0], mupdf.ColorSpace.DeviceRGB, false);
|
||||
const outputPath = `${options.outputPathPrefix}_${i + 1}.${options.format}`;
|
||||
const outputPath = `${options.outputPathPrefix}_${pageNumber}.${options.format}`;
|
||||
const imageData = options.format === 'png'
|
||||
? pixmap.asPNG()
|
||||
: pixmap.asJPEG(90, false);
|
||||
: pixmap.asJPEG(100, false);
|
||||
await writeFile(outputPath, imageData);
|
||||
outputFiles.push(outputPath);
|
||||
logger.info(`Converted page ${i + 1} to ${outputPath}`);
|
||||
logger.info(`Converted page ${pageNumber} to ${outputPath}`);
|
||||
}
|
||||
return outputFiles;
|
||||
}
|
||||
|
||||
31
packages/content/ref/pdf-to-images/dist/types.js
vendored
@ -2,12 +2,29 @@ import { z } from 'zod';
|
||||
export const ConvertCommandSchema = z.object({
|
||||
input: z.string(),
|
||||
output: z.string(),
|
||||
dpi: z.number().default(300),
|
||||
format: z.enum(['png', 'jpg']).default('png')
|
||||
});
|
||||
export const ConfigSchema = z.object({
|
||||
input: z.string().min(1),
|
||||
output: z.string().min(1),
|
||||
dpi: z.number().int().positive().default(300),
|
||||
format: z.enum(['png', 'jpg']).default('png')
|
||||
format: z.enum(['png', 'jpg']).default('png'),
|
||||
startPage: z.number().int().positive().optional(),
|
||||
endPage: z.number().int().positive().optional(),
|
||||
i: z.string().optional(),
|
||||
o: z.string().optional(),
|
||||
s: z.number().int().positive().optional(),
|
||||
e: z.number().int().positive().optional(),
|
||||
_: z.array(z.union([z.string(), z.number()])).optional(),
|
||||
$0: z.string().optional()
|
||||
}).transform((data) => ({
|
||||
input: data.input ?? data.i,
|
||||
output: data.output ?? data.o,
|
||||
dpi: data.dpi,
|
||||
format: data.format,
|
||||
startPage: data.startPage ?? data.s,
|
||||
endPage: data.endPage ?? data.e
|
||||
})).refine((data) => {
|
||||
if (data.startPage !== undefined && data.endPage !== undefined) {
|
||||
return data.startPage <= data.endPage;
|
||||
}
|
||||
return true;
|
||||
}, {
|
||||
message: "startPage must be less than or equal to endPage",
|
||||
path: ["startPage"],
|
||||
});
|
||||
|
||||
1353
packages/content/ref/pdf-to-images/package-lock.json
generated
@ -1,14 +1,25 @@
|
||||
{
|
||||
"name": "mu",
|
||||
"name": "@polymech/pdf",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"start": "node dist/index.js"
|
||||
"bin": {
|
||||
"pdf-to-images": "dist/index.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"scripts": {
|
||||
"dev": "tsc -p . --watch",
|
||||
"build": "tsc",
|
||||
"start": "node dist/index.js",
|
||||
"test:pdf": "node dist/index.js convert -i tests/e5dc.pdf -o tests/e5dc/ --startPage 3 --endPage 5",
|
||||
"test:basic": "vitest run"
|
||||
},
|
||||
"keywords": [
|
||||
"pdf",
|
||||
"images",
|
||||
"convert",
|
||||
"pdf-to-images"
|
||||
],
|
||||
"author": "Polymech",
|
||||
"license": "ISC",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
@ -16,6 +27,7 @@
|
||||
"mupdf": "^1.3.3",
|
||||
"tslog": "^4.9.3",
|
||||
"typescript": "^5.8.2",
|
||||
"vitest": "^3.1.1",
|
||||
"yargs": "^17.7.2",
|
||||
"zod": "^3.24.2"
|
||||
},
|
||||
|
||||
@ -1,16 +1,17 @@
|
||||
|
||||
import { Arguments } from 'yargs';
|
||||
import { Logger } from 'tslog';
|
||||
import { ConvertCommandSchema, ConvertCommandConfig } from '../types.js';
|
||||
import { convertPdfToImages } from '../lib/pdf.js';
|
||||
import { existsSync } from 'node:fs';
|
||||
import { dirname } from 'node:path';
|
||||
import { dirname, sep, extname, basename } from 'node:path';
|
||||
import { mkdir, readFile } from 'node:fs/promises';
|
||||
import * as z from 'zod';
|
||||
import type { Options } from 'yargs';
|
||||
|
||||
export const command = 'convert';
|
||||
export const desc = 'Convert PDF to images';
|
||||
|
||||
export const builder = {
|
||||
export const builder: { [key: string]: Options } = {
|
||||
input: {
|
||||
alias: 'i',
|
||||
type: 'string',
|
||||
@ -20,7 +21,7 @@ export const builder = {
|
||||
output: {
|
||||
alias: 'o',
|
||||
type: 'string',
|
||||
description: 'Output directory for images',
|
||||
description: 'Output directory prefix for images',
|
||||
demandOption: true
|
||||
},
|
||||
dpi: {
|
||||
@ -30,13 +31,25 @@ export const builder = {
|
||||
},
|
||||
format: {
|
||||
type: 'string',
|
||||
choices: ['png', 'jpg'],
|
||||
choices: ['png', 'jpg'] as const,
|
||||
default: 'png',
|
||||
description: 'Output image format'
|
||||
},
|
||||
startPage: {
|
||||
alias: 's',
|
||||
type: 'number',
|
||||
description: 'First page to convert (1-based)',
|
||||
requiresArg: true
|
||||
},
|
||||
endPage: {
|
||||
alias: 'e',
|
||||
type: 'number',
|
||||
description: 'Last page to convert (1-based, inclusive)',
|
||||
requiresArg: true
|
||||
}
|
||||
};
|
||||
|
||||
export async function handler(argv: Arguments): Promise<void> {
|
||||
export async function handler(argv: Arguments<ConvertCommandConfig>): Promise<void> {
|
||||
const logger = new Logger();
|
||||
|
||||
try {
|
||||
@ -46,7 +59,20 @@ export async function handler(argv: Arguments): Promise<void> {
|
||||
throw new Error(`Input file ${config.input} does not exist`);
|
||||
}
|
||||
|
||||
await mkdir(dirname(config.output), { recursive: true });
|
||||
// Ensure the full output directory path exists
|
||||
// config.output is the prefix, e.g., "tests/e5dc/image"
|
||||
// We need to create the directory part, e.g., "tests/e5dc/"
|
||||
const outputDir = dirname(config.output);
|
||||
// Check if output path itself ends with a separator or if the base name contains no extension
|
||||
// This helps determine if the output path is intended as a directory.
|
||||
const isOutputDir = config.output.endsWith(sep) || config.output.endsWith('/') || !extname(basename(config.output));
|
||||
const dirToCreate = isOutputDir ? config.output : outputDir;
|
||||
|
||||
// Check if dirToCreate is not empty and not the root directory before creating
|
||||
if (dirToCreate && dirToCreate !== '.' && dirToCreate !== '/' && dirToCreate !== sep) {
|
||||
await mkdir(dirToCreate, { recursive: true });
|
||||
logger.info(`Ensured output directory exists: ${dirToCreate}`);
|
||||
}
|
||||
|
||||
logger.info(`Converting PDF ${config.input} to images...`);
|
||||
|
||||
@ -55,13 +81,20 @@ export async function handler(argv: Arguments): Promise<void> {
|
||||
outputPathPrefix: config.output,
|
||||
dpi: config.dpi,
|
||||
format: config.format,
|
||||
startPage: config.startPage,
|
||||
endPage: config.endPage,
|
||||
logger
|
||||
});
|
||||
|
||||
logger.info('Conversion completed successfully');
|
||||
logger.info(`Generated ${outputFiles.length} images`);
|
||||
} catch (error) {
|
||||
logger.error('Error during conversion:', error);
|
||||
if (error instanceof z.ZodError) {
|
||||
logger.error('Invalid arguments:', error.flatten());
|
||||
} else {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
logger.error('Error during conversion:', message, error);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,19 @@
|
||||
import yargs from 'yargs';
|
||||
import { hideBin } from 'yargs/helpers';
|
||||
import * as convertCommand from './commands/convert.js';
|
||||
import type { CommandModule } from 'yargs';
|
||||
import type { ConvertCommandConfig } from './types.js';
|
||||
|
||||
const commandModule: CommandModule<{}, ConvertCommandConfig> = {
|
||||
command: convertCommand.command,
|
||||
describe: convertCommand.desc,
|
||||
builder: convertCommand.builder,
|
||||
handler: convertCommand.handler
|
||||
};
|
||||
|
||||
yargs(hideBin(process.argv))
|
||||
.command(require('./commands/convert.js'))
|
||||
.command(commandModule)
|
||||
.demandCommand(1, 'You need to specify a command')
|
||||
.strict()
|
||||
.argv;
|
||||
.help()
|
||||
.parse();
|
||||
|
||||
@ -8,6 +8,8 @@ export interface PdfToImageOptions {
|
||||
outputPathPrefix: string;
|
||||
dpi: number;
|
||||
format: ImageFormat;
|
||||
startPage?: number;
|
||||
endPage?: number;
|
||||
logger?: Logger<any>;
|
||||
}
|
||||
|
||||
@ -22,9 +24,26 @@ export async function convertPdfToImages(
|
||||
const doc = mupdf.Document.openDocument(pdfData, 'pdf');
|
||||
const pageCount = doc.countPages();
|
||||
|
||||
logger.info(`Processing ${pageCount} pages`);
|
||||
// Validate and determine page range (adjusting for 0-based index)
|
||||
const start = (options.startPage ?? 1) - 1;
|
||||
const end = (options.endPage ?? pageCount) - 1;
|
||||
|
||||
for (let i = 0; i < pageCount; i++) {
|
||||
if (start < 0 || start >= pageCount) {
|
||||
throw new Error(`startPage (${options.startPage}) is out of valid range (1-${pageCount})`);
|
||||
}
|
||||
if (end < 0 || end >= pageCount) {
|
||||
throw new Error(`endPage (${options.endPage}) is out of valid range (1-${pageCount})`);
|
||||
}
|
||||
if (start > end) {
|
||||
// This should also be caught by Zod schema, but good to double-check
|
||||
throw new Error(`startPage (${options.startPage}) cannot be greater than endPage (${options.endPage})`);
|
||||
}
|
||||
|
||||
const numPagesToProcess = end - start + 1;
|
||||
logger.info(`Processing pages ${start + 1} to ${end + 1} (${numPagesToProcess} pages) of ${pageCount} total`);
|
||||
|
||||
for (let i = start; i <= end; i++) {
|
||||
const pageNumber = i + 1; // User-facing page number (1-based)
|
||||
const page = doc.loadPage(i);
|
||||
const pixmap = page.toPixmap(
|
||||
[1, 0, 0, 1, 0, 0],
|
||||
@ -32,14 +51,14 @@ export async function convertPdfToImages(
|
||||
false
|
||||
);
|
||||
|
||||
const outputPath = `${options.outputPathPrefix}_${i + 1}.${options.format}`;
|
||||
const outputPath = `${options.outputPathPrefix}_${pageNumber}.${options.format}`;
|
||||
const imageData = options.format === 'png'
|
||||
? pixmap.asPNG()
|
||||
: pixmap.asJPEG(90, false);
|
||||
: pixmap.asJPEG(100, false);
|
||||
|
||||
await writeFile(outputPath, imageData);
|
||||
outputFiles.push(outputPath);
|
||||
logger.info(`Converted page ${i + 1} to ${outputPath}`);
|
||||
logger.info(`Converted page ${pageNumber} to ${outputPath}`);
|
||||
}
|
||||
|
||||
return outputFiles;
|
||||
|
||||
@ -1,22 +1,35 @@
|
||||
|
||||
import { z } from 'zod';
|
||||
import type { ImageFormat } from './lib/pdf.js';
|
||||
|
||||
export const ConvertCommandSchema = z.object({
|
||||
input: z.string(),
|
||||
output: z.string(),
|
||||
dpi: z.number().default(300),
|
||||
format: z.enum(['png', 'jpg'] as const).default('png')
|
||||
dpi: z.number().int().positive().default(300),
|
||||
format: z.enum(['png', 'jpg']).default('png'),
|
||||
startPage: z.number().int().positive().optional(),
|
||||
endPage: z.number().int().positive().optional(),
|
||||
i: z.string().optional(),
|
||||
o: z.string().optional(),
|
||||
s: z.number().int().positive().optional(),
|
||||
e: z.number().int().positive().optional(),
|
||||
_: z.array(z.union([z.string(), z.number()])).optional(),
|
||||
$0: z.string().optional()
|
||||
}).transform((data) => ({
|
||||
input: data.input ?? data.i,
|
||||
output: data.output ?? data.o,
|
||||
dpi: data.dpi,
|
||||
format: data.format,
|
||||
startPage: data.startPage ?? data.s,
|
||||
endPage: data.endPage ?? data.e
|
||||
})).refine((data) => {
|
||||
if (data.startPage !== undefined && data.endPage !== undefined) {
|
||||
return data.startPage <= data.endPage;
|
||||
}
|
||||
return true;
|
||||
}, {
|
||||
message: "startPage must be less than or equal to endPage",
|
||||
path: ["startPage"],
|
||||
});
|
||||
|
||||
export type ConvertCommandConfig = z.infer<typeof ConvertCommandSchema>;
|
||||
|
||||
export const ConfigSchema = z.object({
|
||||
input: z.string().min(1),
|
||||
output: z.string().min(1),
|
||||
dpi: z.number().int().positive().default(300),
|
||||
format: z.enum(['png', 'jpg']).default('png')
|
||||
});
|
||||
|
||||
export type Config = z.infer<typeof ConfigSchema>;
|
||||
|
||||
|
||||
@ -0,0 +1,9 @@
|
||||
// Test suite for src/commands/convert.ts
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
|
||||
// TODO: Add tests
|
||||
describe('Convert Command CLI', () => {
|
||||
it('should be implemented', () => {
|
||||
expect(true).toBe(true); // Placeholder
|
||||
});
|
||||
});
|
||||
BIN
packages/content/ref/pdf-to-images/tests/e5dc.pdf
Normal file
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_10.jpg
Normal file
|
After Width: | Height: | Size: 244 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_100.jpg
Normal file
|
After Width: | Height: | Size: 161 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_101.jpg
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_102.jpg
Normal file
|
After Width: | Height: | Size: 159 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_103.jpg
Normal file
|
After Width: | Height: | Size: 144 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_104.jpg
Normal file
|
After Width: | Height: | Size: 133 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_105.jpg
Normal file
|
After Width: | Height: | Size: 163 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_106.jpg
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_107.jpg
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_108.jpg
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_109.jpg
Normal file
|
After Width: | Height: | Size: 143 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_11.jpg
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_110.jpg
Normal file
|
After Width: | Height: | Size: 94 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_111.jpg
Normal file
|
After Width: | Height: | Size: 149 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_112.jpg
Normal file
|
After Width: | Height: | Size: 158 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_113.jpg
Normal file
|
After Width: | Height: | Size: 144 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_114.jpg
Normal file
|
After Width: | Height: | Size: 158 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_115.jpg
Normal file
|
After Width: | Height: | Size: 154 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_116.jpg
Normal file
|
After Width: | Height: | Size: 186 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_117.jpg
Normal file
|
After Width: | Height: | Size: 146 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_118.jpg
Normal file
|
After Width: | Height: | Size: 134 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_119.jpg
Normal file
|
After Width: | Height: | Size: 143 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_12.jpg
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_120.jpg
Normal file
|
After Width: | Height: | Size: 191 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_121.jpg
Normal file
|
After Width: | Height: | Size: 184 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_122.jpg
Normal file
|
After Width: | Height: | Size: 169 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_123.jpg
Normal file
|
After Width: | Height: | Size: 224 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_124.jpg
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_125.jpg
Normal file
|
After Width: | Height: | Size: 186 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_126.jpg
Normal file
|
After Width: | Height: | Size: 188 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_127.jpg
Normal file
|
After Width: | Height: | Size: 145 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_128.jpg
Normal file
|
After Width: | Height: | Size: 182 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_129.jpg
Normal file
|
After Width: | Height: | Size: 127 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_13.jpg
Normal file
|
After Width: | Height: | Size: 68 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_130.jpg
Normal file
|
After Width: | Height: | Size: 160 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_131.jpg
Normal file
|
After Width: | Height: | Size: 93 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_132.jpg
Normal file
|
After Width: | Height: | Size: 193 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_133.jpg
Normal file
|
After Width: | Height: | Size: 201 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_134.jpg
Normal file
|
After Width: | Height: | Size: 116 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_135.jpg
Normal file
|
After Width: | Height: | Size: 154 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_136.jpg
Normal file
|
After Width: | Height: | Size: 170 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_137.jpg
Normal file
|
After Width: | Height: | Size: 171 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_138.jpg
Normal file
|
After Width: | Height: | Size: 186 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_139.jpg
Normal file
|
After Width: | Height: | Size: 95 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_14.jpg
Normal file
|
After Width: | Height: | Size: 128 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_140.jpg
Normal file
|
After Width: | Height: | Size: 128 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_141.jpg
Normal file
|
After Width: | Height: | Size: 114 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_142.jpg
Normal file
|
After Width: | Height: | Size: 193 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_143.jpg
Normal file
|
After Width: | Height: | Size: 152 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_144.jpg
Normal file
|
After Width: | Height: | Size: 94 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_145.jpg
Normal file
|
After Width: | Height: | Size: 122 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_146.jpg
Normal file
|
After Width: | Height: | Size: 170 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_147.jpg
Normal file
|
After Width: | Height: | Size: 193 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_148.jpg
Normal file
|
After Width: | Height: | Size: 159 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_149.jpg
Normal file
|
After Width: | Height: | Size: 202 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_15.jpg
Normal file
|
After Width: | Height: | Size: 118 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_150.jpg
Normal file
|
After Width: | Height: | Size: 172 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_151.jpg
Normal file
|
After Width: | Height: | Size: 132 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_152.jpg
Normal file
|
After Width: | Height: | Size: 164 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_153.jpg
Normal file
|
After Width: | Height: | Size: 218 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_154.jpg
Normal file
|
After Width: | Height: | Size: 161 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_155.jpg
Normal file
|
After Width: | Height: | Size: 173 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_156.jpg
Normal file
|
After Width: | Height: | Size: 144 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_157.jpg
Normal file
|
After Width: | Height: | Size: 132 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_158.jpg
Normal file
|
After Width: | Height: | Size: 155 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_159.jpg
Normal file
|
After Width: | Height: | Size: 125 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_16.jpg
Normal file
|
After Width: | Height: | Size: 186 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_160.jpg
Normal file
|
After Width: | Height: | Size: 167 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_161.jpg
Normal file
|
After Width: | Height: | Size: 170 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_162.jpg
Normal file
|
After Width: | Height: | Size: 171 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_163.jpg
Normal file
|
After Width: | Height: | Size: 119 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_164.jpg
Normal file
|
After Width: | Height: | Size: 112 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_165.jpg
Normal file
|
After Width: | Height: | Size: 156 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_166.jpg
Normal file
|
After Width: | Height: | Size: 86 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_167.jpg
Normal file
|
After Width: | Height: | Size: 119 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_168.jpg
Normal file
|
After Width: | Height: | Size: 210 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_169.jpg
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_17.jpg
Normal file
|
After Width: | Height: | Size: 208 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_170.jpg
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_171.jpg
Normal file
|
After Width: | Height: | Size: 53 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_172.jpg
Normal file
|
After Width: | Height: | Size: 148 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_173.jpg
Normal file
|
After Width: | Height: | Size: 128 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_174.jpg
Normal file
|
After Width: | Height: | Size: 68 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_175.jpg
Normal file
|
After Width: | Height: | Size: 163 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_176.jpg
Normal file
|
After Width: | Height: | Size: 131 KiB |
BIN
packages/content/ref/pdf-to-images/tests/e5dc/_177.jpg
Normal file
|
After Width: | Height: | Size: 28 KiB |