This commit is contained in:
lovebird 2025-04-21 10:49:46 +02:00
parent c4241a2108
commit 05105804c9
199 changed files with 1732 additions and 55 deletions

View File

@ -0,0 +1 @@
./tests/out

View 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`).
```

View File

@ -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);
}
}

View File

@ -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();

View File

@ -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;
}

View File

@ -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"],
});

File diff suppressed because it is too large Load Diff

View File

@ -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"
},

View File

@ -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);
}
}

View File

@ -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();

View File

@ -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;

View File

@ -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>;

View File

@ -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
});
});

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Some files were not shown because too many files have changed in this diff Show More