-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
200 additions
and
170 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
const { createCanvas, loadImage } = require('canvas') | ||
const { calculateAvgColor } = require('./utils') | ||
|
||
const addHeadingToImage = async ( | ||
imageBuffer, | ||
text, | ||
targetWidth, | ||
targetHeight, | ||
) => { | ||
const canvas = createCanvas(targetWidth, targetHeight) | ||
const ctx = canvas.getContext('2d') | ||
const image = await loadImage(imageBuffer) | ||
ctx.drawImage(image, 0, 0, targetWidth, targetHeight) | ||
|
||
const avgColor = calculateAvgColor( | ||
ctx.getImageData( | ||
targetWidth / 4, | ||
(targetHeight * 9) / 32, | ||
targetWidth / 2, | ||
(targetHeight * 9) / 16, | ||
), | ||
) | ||
ctx.fillStyle = avgColor > 128 ? '#000000' : '#FFFFFF' | ||
ctx.font = 'bold 48px sans-serif' | ||
ctx.textAlign = 'center' | ||
|
||
const words = text.split(' ') | ||
let line = '', | ||
y = targetHeight / 2 | ||
for (const word of words) { | ||
const testLine = line + word + ' ' | ||
if (ctx.measureText(testLine).width > targetWidth * 0.9) { | ||
ctx.fillText(line, targetWidth / 2, y) | ||
line = word + ' ' | ||
y += 50 | ||
} else { | ||
line = testLine | ||
} | ||
} | ||
ctx.fillText(line, targetWidth / 2, y) | ||
|
||
return canvas.toBuffer('image/png') | ||
} | ||
|
||
module.exports = addHeadingToImage |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
const ffmpeg = require('fluent-ffmpeg') | ||
const { getAudioDuration } = require('./utils') | ||
|
||
const createVideoFromParts = async (imageFile, audioFile, videoOutput) => { | ||
console.log(`🎥 Creating video from ${imageFile} and ${audioFile}...`) | ||
const audioDuration = await getAudioDuration(audioFile) | ||
const additionalSeconds = 0 | ||
|
||
return new Promise((resolve, reject) => { | ||
ffmpeg() | ||
.input(imageFile) | ||
.input(audioFile) | ||
.outputOptions([ | ||
'-c:v libx264', | ||
'-profile:v baseline', | ||
'-level 3.0', | ||
'-pix_fmt yuv420p', | ||
'-c:a aac', | ||
'-movflags faststart', | ||
'-filter_complex', | ||
`[0:v]loop=loop=${ | ||
Math.ceil(audioDuration + additionalSeconds) * 25 | ||
}:size=1:start=0[v];[v][1:a]concat=n=1:v=1:a=1`, | ||
]) | ||
.format('mp4') | ||
.saveToFile(videoOutput) | ||
.on('end', resolve) | ||
.on('error', reject) | ||
}) | ||
} | ||
|
||
module.exports = createVideoFromParts |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
const { createCanvas, loadImage } = require('canvas') | ||
|
||
const cropAndScaleImage = async (imageBuffer, targetWidth, targetHeight) => { | ||
const canvas = createCanvas(targetWidth, targetHeight) | ||
const ctx = canvas.getContext('2d') | ||
const image = await loadImage(imageBuffer) | ||
|
||
const originalWidth = 1024 // Original width of the image | ||
const originalHeight = 1024 // Original height of the image | ||
|
||
// Calculate the scaling factor to retain aspect ratio | ||
const scaleFactor = Math.max( | ||
targetWidth / originalWidth, | ||
targetHeight / originalHeight, | ||
) | ||
|
||
// Calculate new width and height based on the scaling factor | ||
const newWidth = originalWidth * scaleFactor | ||
const newHeight = originalHeight * scaleFactor | ||
|
||
// Calculate the position to center the image on the canvas | ||
const x = (targetWidth - newWidth) / 2 | ||
const y = (targetHeight - newHeight) / 2 | ||
|
||
// Draw the image on the canvas, scaling it and positioning it to fit the target dimensions | ||
ctx.drawImage(image, x, y, newWidth, newHeight) | ||
|
||
return canvas.toBuffer('image/png') | ||
} | ||
|
||
module.exports = cropAndScaleImage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
const axios = require('axios') | ||
const fs = require('fs-extra') | ||
const cropAndScaleImage = require('./cropAndScaleImage') | ||
const addHeadingToImage = require('./addHeadingToImage') | ||
|
||
const targetWidth = 1920 | ||
const targetHeight = 1080 | ||
|
||
const generatePrompt = async (content, openaiInstance) => { | ||
const response = await openaiInstance.createChatCompletion({ | ||
model: 'gpt-3.5-turbo', | ||
messages: [ | ||
{ | ||
role: 'system', | ||
content: | ||
'You are ChatGPT, and your task is to summarize the essence of the user\'s text in less than a dozen words, in a way that would guide the creation of an image e.g. "a teddy bear on a skateboard in Times Square".', | ||
}, | ||
{ | ||
role: 'user', | ||
content: content, | ||
}, | ||
], | ||
}) | ||
return response.data.choices[0].message.content.trim() | ||
} | ||
|
||
const generateImageFromText = async (line, outputPath, openaiInstance) => { | ||
try { | ||
const imagePrompt = await generatePrompt(line.content, openaiInstance) | ||
console.log('🖼️ Image prompt:', imagePrompt) | ||
|
||
const createImageResponse = await openaiInstance.createImage({ | ||
prompt: `An illustration of ${imagePrompt}`, | ||
n: 1, | ||
size: '1024x1024', | ||
}) | ||
|
||
const imageUrl = createImageResponse.data.data[0].url | ||
const imageResponse = await axios.get(imageUrl, { | ||
responseType: 'arraybuffer', | ||
}) | ||
|
||
let finalImageBuffer = await cropAndScaleImage( | ||
imageResponse.data, | ||
targetWidth, | ||
targetHeight, | ||
) | ||
if (line.type === 'heading') { | ||
finalImageBuffer = await addHeadingToImage( | ||
finalImageBuffer, | ||
line.content, | ||
targetWidth, | ||
targetHeight, | ||
) | ||
} | ||
|
||
await fs.outputFile(outputPath, Buffer.from(finalImageBuffer, 'binary')) | ||
console.log(`✅ Image saved to: ${outputPath}`) | ||
} catch (error) { | ||
console.error(`Failed to generate image from text: ${error.message}`) | ||
throw error | ||
} | ||
} | ||
|
||
module.exports = generateImageFromText |
4 changes: 2 additions & 2 deletions
4
src/imageGenerator.test.js → src/generateImageFromText.test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.