Skip to main content
Glama

mcp-google-sheets

image-to-pdf.ts7.11 kB
import { createAction, Property } from '@activepieces/pieces-framework'; import { PDFDocument, PDFImage, RotationTypes, PageSizes } from 'pdf-lib'; export const imageToPdf = createAction({ name: 'imageToPdf', displayName: 'Image to PDF', description: 'Convert image to PDF', props: { image: Property.File({ displayName: 'image', description: 'Image has to be png, jpeg or jpg and it will be scaled down to fit the page when image is larger than an A4 page', required: true, }), }, errorHandlingOptions: { continueOnFailure: { defaultValue: false, }, retryOnFailure: { hide: true, }, }, async run(context) { try { const image = context.propsValue.image; const imageExtension = image.extension?.toLowerCase(); const pdfDoc = await PDFDocument.create(); const page = pdfDoc.addPage(); const [pageWidth, pageHeight] = PageSizes.A4; page.setSize(pageWidth, pageHeight); const xMargin = 30; const yMargin = 30; const [maxCardWidth, maxCardHeight] = [pageWidth - xMargin * 2, pageHeight - yMargin * 2]; let result: PDFImage | null = null; if (imageExtension === 'png') { result = await pdfDoc.embedPng(image.data); } else if (imageExtension === 'jpg' || imageExtension === 'jpeg') { result = await pdfDoc.embedJpg(image.data); } else { throw new Error(`Unsupported image format: ${imageExtension}`); } if (result === null) { throw new Error('Failed to embed image'); } const exifOrientation = getImageOrientation(image.data.buffer); const orientationCorrection = getOrientationCorrection(exifOrientation); let scaledImage, correctedWidth, correctedHeight; switch (exifOrientation) { case ImageOrientation.FlipHorizontalRotate90: case ImageOrientation.Rotate90: case ImageOrientation.FlipVerticalRotate90: case ImageOrientation.Rotate270: // The uploaded image is rotated +/- 90 degrees scaledImage = result.scaleToFit(maxCardHeight, maxCardWidth); correctedWidth = scaledImage.height; correctedHeight = scaledImage.width; break; default: scaledImage = result.scaleToFit(maxCardWidth, maxCardHeight); correctedWidth = scaledImage.width; correctedHeight = scaledImage.height; } let xShift, yShift; const yOffset = pageHeight - yMargin; switch (exifOrientation) { case ImageOrientation.FlipHorizontal: xShift = pageWidth - xMargin - correctedWidth; yShift = yOffset - correctedHeight; break; case ImageOrientation.Rotate180: xShift = xMargin + correctedWidth; yShift = yOffset; break; case ImageOrientation.FlipVertical: xShift = pageWidth - xMargin; yShift = yOffset; break; case ImageOrientation.FlipHorizontalRotate90: xShift = xMargin + correctedWidth; yShift = pageHeight - yOffset; break; case ImageOrientation.Rotate90: xShift = xMargin; yShift = yOffset; break; case ImageOrientation.FlipVerticalRotate90: xShift = xMargin; yShift = pageHeight - yOffset + correctedHeight; break; case ImageOrientation.Rotate270: xShift = xMargin + correctedWidth; yShift = yOffset - correctedHeight; break; default: xShift = xMargin; yShift = yOffset - correctedHeight; } page.drawImage(result, { x: xShift, y: yShift, height: scaledImage.height, width: scaledImage.width, rotate: { angle: orientationCorrection.degrees, type: RotationTypes.Degrees }, }); const pdfBytes = await pdfDoc.save(); const base64Pdf = Buffer.from(pdfBytes).toString('base64'); return context.files.write({ data: Buffer.from(base64Pdf, 'base64'), fileName: `${image.filename}.pdf`, }); } catch (error) { throw new Error(`Failed to convert text to PDF: ${(error as Error).message}`); } }, }); // https://sirv.com/help/articles/rotate-photos-to-be-upright/#exif-orientation-values enum ImageOrientation { Normal = 1, // "Image is in normal orientation, no rotation or flipping" Rotate90 = 6, // "Image is rotated 90 degrees" Rotate180 = 3, // "Image is rotated 180 degrees" Rotate270 = 8, // "Image is rotated 270 degrees" FlipHorizontal = 2, // "Image is flipped horizontally" FlipVertical = 4, // "Image is flipped horizontally and rotated 180 degrees" FlipHorizontalRotate90 = 5, // "Image is rotated 90 degrees and flipped horizontally" FlipVerticalRotate90 = 7, // "Image is rotated 270 degrees and flipped horizontally" Unknown= -1 } // https://github.com/Hopding/pdf-lib/issues/1284 // https://stackoverflow.com/questions/7584794/accessing-jpeg-exif-rotation-data-in-javascript-on-the-client-side/32490603#32490603 function getImageOrientation(file: ArrayBuffer): ImageOrientation { const view = new DataView(file); const length = view.byteLength; let offset = 2; while (offset < length) { if (view.getUint16(offset + 2, false) <= 8) return ImageOrientation.Unknown; const marker = view.getUint16(offset, false); offset += 2; // If EXIF buffer segment exists find the orientation if (marker == 0xffe1) { if (view.getUint32((offset += 2), false) != 0x45786966) { return ImageOrientation.Unknown; } const little = view.getUint16((offset += 6), false) == 0x4949; offset += view.getUint32(offset + 4, little); const tags = view.getUint16(offset, little); offset += 2; for (let i = 0; i < tags; i++) { if (view.getUint16(offset + i * 12, little) == 0x0112) { const orientation = view.getUint16(offset + i * 12 + 8, little); switch (orientation) { case 1: return ImageOrientation.Normal; case 3: return ImageOrientation.Rotate180; case 6: return ImageOrientation.Rotate90; case 8: return ImageOrientation.Rotate270; case 2: return ImageOrientation.FlipHorizontal; case 4: return ImageOrientation.FlipVertical; case 5: return ImageOrientation.FlipHorizontalRotate90; case 7: return ImageOrientation.FlipVerticalRotate90; default: return ImageOrientation.Unknown; } } } } else if ((marker & 0xff00) != 0xff00) { break; } else { offset += view.getUint16(offset, false); } } return ImageOrientation.Unknown; } function getOrientationCorrection(orientation: number): { degrees: number; mirrored?: 'x' | 'y' } { switch (orientation) { case ImageOrientation.FlipHorizontal: return { degrees: 0, mirrored: 'x' }; case ImageOrientation.Rotate180: return { degrees: -180 }; case ImageOrientation.FlipVertical: return { degrees: 180, mirrored: 'x' }; case ImageOrientation.FlipHorizontalRotate90: return { degrees: 90, mirrored: 'y' }; case ImageOrientation.Rotate90: return { degrees: -90 }; case ImageOrientation.FlipVerticalRotate90: return { degrees: -90, mirrored: 'y' }; case ImageOrientation.Rotate270: return { degrees: 90 }; default: return { degrees: 0 }; } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/activepieces/activepieces'

If you have feedback or need assistance with the MCP directory API, please join our Discord server