From 4c62e5032fa385473d270b218873de0eeaa48705 Mon Sep 17 00:00:00 2001 From: ale Date: Sat, 6 Sep 2025 19:31:34 +0200 Subject: [PATCH] examples Signed-off-by: ale --- .gitignore | 4 ++ README.md | 18 +++++++ examples/README.md | 50 ++++++++++++++++++ examples/basic_usage.js | 92 ++++++++++++++++++++++------------ examples/chiquito-cobarde.mp3 | Bin 0 -> 6176 bytes examples/risitas.jpg | Bin 0 -> 927 bytes 6 files changed, 131 insertions(+), 33 deletions(-) create mode 100644 examples/README.md create mode 100644 examples/chiquito-cobarde.mp3 create mode 100644 examples/risitas.jpg diff --git a/.gitignore b/.gitignore index 232a892..ed57edc 100644 --- a/.gitignore +++ b/.gitignore @@ -63,6 +63,10 @@ example_*.i2m *.test.js *.spec.js +# Example generated files +examples/risitas_with_chiquito.i2m +examples/extracted_* + # Build directories dist/ build/ \ No newline at end of file diff --git a/README.md b/README.md index 9bee586..c90e216 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,24 @@ npm install -g img2mp3 npm install img2mp3 ``` +## Quick Start + +To see IMG2MP3 in action, run the included example: + +```bash +# Clone the repository +git clone https://github.com/ale/img2mp3.git +cd img2mp3 + +# Install dependencies +npm install + +# Run the example with sample files +npm run example +``` + +This will demonstrate encoding, decoding, and playing with the included sample files (`risitas.jpg` and `chiquito-cobarde.mp3`). + ## Usage ### Command Line Interface diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..fa1e742 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,50 @@ +# Examples + +This directory contains example files and usage demonstrations for IMG2MP3. + +## Files + +- `basic_usage.js` - Complete example showing all functionality +- `risitas.jpg` - Sample image file for testing +- `chiquito-cobarde.mp3` - Sample audio file for testing + +## Running the Example + +To run the complete example with the provided files: + +```bash +# From the project root directory +npm run example + +# Or run directly +node examples/basic_usage.js +``` + +## What the Example Does + +1. **Encodes** the MP3 file into the image, creating a `.i2m` file +2. **Gets information** about the created `.i2m` file +3. **Plays** the embedded audio (if an audio player is available) +4. **Decodes** the `.i2m` file back to separate image and MP3 files + +## Expected Output + +The example will create the following files in the `examples` directory: + +- `risitas_with_chiquito.i2m` - The image with embedded audio +- `extracted_risitas.png` - The extracted original image +- `extracted_chiquito.mp3` - The extracted audio file + +## Testing Different Files + +You can replace `risitas.jpg` and `chiquito-cobarde.mp3` with your own files to test with different content. Just make sure to update the filenames in `basic_usage.js` accordingly. + +## Audio Players + +For the playback functionality to work, you need one of these audio players installed: + +- **Linux**: `sudo apt install mpg123` or `sudo apt install mpv` +- **macOS**: `brew install mpg123` or `brew install mpv` +- **Windows**: Install [mpv](https://mpv.io/installation/) + +If no audio player is available, the example will show a warning but continue with the other functionality. diff --git a/examples/basic_usage.js b/examples/basic_usage.js index f117886..476b304 100644 --- a/examples/basic_usage.js +++ b/examples/basic_usage.js @@ -7,48 +7,59 @@ async function example() { console.log('šŸŽµ IMG2MP3 Example Usage\n'); try { - // Note: You'll need to provide actual image and MP3 files - const imagePath = 'sample_image.jpg'; // Replace with actual image - const mp3Path = 'sample_audio.mp3'; // Replace with actual MP3 - const outputPath = 'example_output.i2m'; + // Using the actual files in the examples directory + const imagePath = path.join(__dirname, 'risitas.jpg'); + const mp3Path = path.join(__dirname, 'chiquito-cobarde.mp3'); + const outputPath = path.join(__dirname, 'risitas_with_chiquito.i2m'); console.log('1. Encoding MP3 into image...'); - // Uncomment when you have actual files: - // const encodeResult = await img2mp3.encode(imagePath, mp3Path, outputPath); - // console.log('āœ… Encoding successful!'); - // console.log(` Output size: ${encodeResult.outputSize} bytes`); - // console.log(` Container image: ${encodeResult.imageSize}\n`); + console.log(` Image: ${path.basename(imagePath)}`); + console.log(` Audio: ${path.basename(mp3Path)}`); + + const encodeResult = await img2mp3.encode(imagePath, mp3Path, outputPath); + console.log('āœ… Encoding successful!'); + console.log(` Original image: ${formatBytes(encodeResult.originalImageSize)}`); + console.log(` MP3 file: ${formatBytes(encodeResult.mp3Size)}`); + console.log(` Output size: ${formatBytes(encodeResult.outputSize)}`); + console.log(` Container image: ${encodeResult.imageSize}\n`); console.log('2. Getting file information...'); - // Uncomment when you have an actual .i2m file: - // const info = await img2mp3.getInfo(outputPath); - // if (info.isValid) { - // console.log('āœ… Valid .i2m file detected!'); - // console.log(` Embedded audio: ${info.mp3Size} bytes`); - // console.log(` Original image: ${info.originalImageSize} bytes\n`); - // } + const info = await img2mp3.getInfo(outputPath); + if (info.isValid) { + console.log('āœ… Valid .i2m file detected!'); + console.log(` Embedded audio: ${formatBytes(info.mp3Size)}`); + console.log(` Original image: ${formatBytes(info.originalImageSize)}`); + console.log(` Container dimensions: ${info.dimensions}\n`); + } console.log('3. Playing embedded audio...'); - // Uncomment when you have an actual .i2m file: - // await img2mp3.play(outputPath); - // console.log('āœ… Playback finished!\n'); + console.log(' (Press Ctrl+C to stop playback)'); + try { + await img2mp3.play(outputPath); + console.log('āœ… Playback finished!\n'); + } catch (playError) { + console.log(`āš ļø Playback failed: ${playError.message}`); + console.log(' (This is normal if no audio player is installed)\n'); + } console.log('4. Decoding back to separate files...'); - // Uncomment when you have an actual .i2m file: - // const decodeResult = await img2mp3.decode( - // outputPath, - // 'extracted_image.png', - // 'extracted_audio.mp3' - // ); - // console.log('āœ… Decoding successful!'); - // console.log(` Extracted image: ${decodeResult.extractedImageSize} bytes`); - // console.log(` Extracted audio: ${decodeResult.extractedMp3Size} bytes`); + const extractedImagePath = path.join(__dirname, 'extracted_risitas.png'); + const extractedMp3Path = path.join(__dirname, 'extracted_chiquito.mp3'); - console.log('\nšŸŽ‰ Example completed!'); - console.log('\nTo run this example with real files:'); - console.log('1. Place an image file named "sample_image.jpg" in this directory'); - console.log('2. Place an MP3 file named "sample_audio.mp3" in this directory'); - console.log('3. Uncomment the code above and run again'); + const decodeResult = await img2mp3.decode( + outputPath, + extractedImagePath, + extractedMp3Path + ); + console.log('āœ… Decoding successful!'); + console.log(` Extracted image: ${path.basename(extractedImagePath)} (${formatBytes(decodeResult.extractedImageSize)})`); + console.log(` Extracted audio: ${path.basename(extractedMp3Path)} (${formatBytes(decodeResult.extractedMp3Size)})`); + + console.log('\nšŸŽ‰ Example completed successfully!'); + console.log('\nGenerated files:'); + console.log(`šŸ“ ${path.basename(outputPath)} - The image with embedded audio`); + console.log(`šŸ–¼ļø ${path.basename(extractedImagePath)} - Extracted image`); + console.log(`šŸŽµ ${path.basename(extractedMp3Path)} - Extracted audio`); } catch (error) { console.error('āŒ Error:', error.message); @@ -58,5 +69,20 @@ async function example() { } } +/** + * Format bytes to human readable format + */ +function formatBytes(bytes, decimals = 2) { + if (bytes === 0) return '0 Bytes'; + + const k = 1024; + const dm = decimals < 0 ? 0 : decimals; + const sizes = ['Bytes', 'KB', 'MB', 'GB']; + + const i = Math.floor(Math.log(bytes) / Math.log(k)); + + return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; +} + // Run the example example().catch(console.error); diff --git a/examples/chiquito-cobarde.mp3 b/examples/chiquito-cobarde.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..1b395f00fe282a7f17426549c6a953383ed15fe4 GIT binary patch literal 6176 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 BAaMWy literal 0 HcmV?d00001 diff --git a/examples/risitas.jpg b/examples/risitas.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8c394f09e4e473df2d203d7c08583001579750f5 GIT binary patch literal 927 zcmex=>ukC3pCfH06P05XITq?4J21E^7eo0A(TN+S4wfI*Oh zL4iSmnNg5|Nsy6Qkn#T!21y16CT5^J5rCDQiG_^=D5WdFz{CWymYIniBF)Ie%)-hh zsK~%BBy8v?5|}7zq@--@6jaysIDgw1Ci7$RMw$Hcwp`ze zwj}Ryiiv+GUjEuOZC&<`88K|aXD6)vwcgOL_DbW=-(MV@qY{@$)oWV^u3lwW{KJ`T z-{RRDf=_Hoe02Y>@+bRee~W#&>rGRP?7wJx%W1POU+HahS}S7H9XIuI*WVLb-q@?J zGBmuU-J$KYCb?KUSnQ_C?x^sMo48IJeBD>3SXY%VdepSK_upa(vxCp__Ub&05?6GY zB{}<7ftU)@8FS5@GC~~pSCl>Nw49_FHajGf$5tjJ_{rvtDeJ^llhrIm!{2%J)k}XB z`pM+Dajt1$dFfZXDxExQVYjRE{oZ=UMSI*{b!4eC??3a$^SAxY(qen8nyhXw3W+PstO#*-fdAI zS!mVPwQ`ba#J{zou@1M7CpjqO)m3$79GkLdXZx+947(>cua-Prto=4^!KaFo57z(G zlx_?D&hka*Y|Km9)vw%T7D=V8ap#R)<}z(daoZ$o4wai%m_ny~2yNy){-88DE^282 zJ74Hq>xI94CoIm$=9Rg*np^q$ns0CX6Sc43FY$1;|1`CxgKG(&?XDd$FMkJ_te)a- ze_QXCd-q~K@vT<*ayuoxRL;h#%}w?%yLsB^{l_Qn8(&KA$u(Tc;JoZ|#9C#R9dATE hUWcsc*{IcEuJZ0o+2bPr