Skip to content

Instantly share code, notes, and snippets.

@ericksli
Last active January 11, 2020 11:37
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ericksli/65734e77591f1f2a9e948297fefa8371 to your computer and use it in GitHub Desktop.
Save ericksli/65734e77591f1f2a9e948297fefa8371 to your computer and use it in GitHub Desktop.
Move PNG files for Android and iOS project

movepng

Move PNG files for Android and iOS project.

Suppose you have these images exported from Avocode in ~/Downloads/test:

.
├── image_distance-hdpi.png
├── image_distance-mdpi.png
├── image_distance-xhdpi.png
├── image_distance-xxhdpi.png
└── image_distance-xxxhdpi.png

This script can help you to move these image files to your Android or iOS project easily based on the area of the images.

Usage

USAGE

 movepng <target> <name> <exportDir> <images...>

ARGUMENTS

 <target>         Export target (android or ios)      required      
 <name>           File name of the moved files        required      
 <exportDir>      Export directory                    required      
 <images...>      Image files                         required    

Android

Execute the script:

./movepng android example_image ~/Downloads/test_output ~/Downloads/test/image_distance-mdpi.png ~/Downloads/test/image_distance-hdpi.png ~/Downloads/test/image_distance-xhdpi.png ~/Downloads/test/image_distance-xxhdpi.png ~/Downloads/test/image_distance-xxxhdpi.png

It will output:

Moved [/Users/testing/Downloads/test/image_distance-mdpi.png] to [/Users/testing/Downloads/test_output/drawable-mdpi/example_image.png]
Moved [/Users/testing/Downloads/test/image_distance-hdpi.png] to [/Users/testing/Downloads/test_output/drawable-hdpi/example_image.png]
Moved [/Users/testing/Downloads/test/image_distance-xhdpi.png] to [/Users/testing/Downloads/test_output/drawable-xhdpi/example_image.png]
Moved [/Users/testing/Downloads/test/image_distance-xxhdpi.png] to [/Users/testing/Downloads/test_output/drawable-xxhdpi/example_image.png]
Moved [/Users/testing/Downloads/test/image_distance-xxxhdpi.png] to [/Users/testing/Downloads/test_output/drawable-xxxhdpi/example_image.png]

Inside the ~/Downloads/test_output directory:

.
├── drawable-hdpi
│   └── example_image.png
├── drawable-mdpi
│   └── example_image.png
├── drawable-xhdpi
│   └── example_image.png
├── drawable-xxhdpi
│   └── example_image.png
└── drawable-xxxhdpi
    └── example_image.png

iOS

Execute the script:

./movepng ios example_image ~/Downloads/test_output ~/Downloads/test/image_distance-mdpi.png ~/Downloads/test/image_distance-hdpi.png ~/Downloads/test/image_distance-xhdpi.png ~/Downloads/test/image_distance-xxhdpi.png ~/Downloads/test/image_distance-xxxhdpi.png

It will output:

Moved [/Users/testing/Downloads/test/image_distance-mdpi.png] to [/Users/testing/Downloads/test_output/example_image.png]
Skipped [/Users/testing/Downloads/test/image_distance-hdpi.png]
Moved [/Users/testing/Downloads/test/image_distance-xhdpi.png] to [/Users/testing/Downloads/test_output/example_image@2x.png]
Moved [/Users/testing/Downloads/test/image_distance-xxhdpi.png] to [/Users/testing/Downloads/test_output/example_image@3x.png]
Skipped [/Users/testing/Downloads/test/image_distance-xxxhdpi.png]

Inside the ~/Downloads/test_output directory:

.
├── example_image.png
├── example_image@2x.png
└── example_image@3x.png
const program = require('caporal')
const fs = require('fs-extra')
const path = require('path')
const imageSizeOf = require('image-size')
const _ = require('lodash')
const ANDROID_QUALIFIERS = ['mdpi', 'hdpi', 'xhdpi', 'xxhdpi', 'xxxhdpi']
const IOS_QUALIFIERS = [
{
suffix: '',
androidEquivalent: 'mdpi'
}, {
suffix: '@2x',
androidEquivalent: 'xhdpi'
}, {
suffix: '@3x',
androidEquivalent: 'xxhdpi'
}
]
const movepng = async (args, options, logger) => {
// Find the area of the images and sort by area
const imageInfoList = []
for (let image of args.images) {
const imageInfo = await imageSizeOf(image)
imageInfoList.push({
path: image,
area: imageInfo.width * imageInfo.height,
type: imageInfo.type
})
}
const sortedImageInfoList = _.sortBy(imageInfoList, (image) => image.area)
// Copy files
if (args.target === 'android') {
for (let i = 0; i < sortedImageInfoList.length; i++) {
const imageInfo = sortedImageInfoList[i]
const qualifier = ANDROID_QUALIFIERS[i]
const exportPath = path.normalize(`${args.exportDir}${path.sep}drawable-${qualifier}${path.sep}${args.name}.${imageInfo.type}`)
await copyFile(imageInfo.path, exportPath, logger)
}
} else {
for (let i = 0; i < sortedImageInfoList.length; i++) {
const imageInfo = sortedImageInfoList[i]
let iosQualifier
if (sortedImageInfoList.length > IOS_QUALIFIERS.length) {
// Input images are for Android, need to pick some of the images for iOS
const androidQualifier = ANDROID_QUALIFIERS[i]
iosQualifier = _.find(IOS_QUALIFIERS, (item) => item.androidEquivalent === androidQualifier)
} else {
// Input images are for iOS, no need to map Android qualifiers
iosQualifier = IOS_QUALIFIERS[i]
}
if (iosQualifier === undefined) {
logger.info(`Skipped [${imageInfo.path}]`)
} else {
const exportPath = path.normalize(`${args.exportDir}${path.sep}${args.name}${iosQualifier.suffix}.${imageInfo.type}`)
await copyFile(imageInfo.path, exportPath, logger)
}
}
}
}
const copyFile = async (src, dest, logger) => {
await fs.copy(src, dest)
logger.info(`Moved [${src}] to [${dest}]`)
}
program
.version('1.0.0')
.description('Move PNG files for Android and iOS project')
.argument('<target>', 'Export target (android or ios)', (opt) => {
if (['android', 'ios'].includes(opt.toLowerCase()) === false) {
throw new Error('Either android or ios')
}
return opt.toLowerCase()
})
.argument('<name>', 'File name of the moved files')
.argument('<exportDir>', 'Export directory', async (opt) => {
const normalized = path.normalize(opt)
await fs.access(normalized)
return normalized
})
.argument('<images...>', 'Image files', async (opt) => {
if (opt.length > Math.max(ANDROID_QUALIFIERS.length, IOS_QUALIFIERS.length)) {
throw new Error('Too many images')
}
const normalized = opt.map((image) => path.normalize(image))
for (let image of normalized) {
await fs.access(image)
}
return normalized
})
.action((args, options, logger) => {
try {
return movepng(args, options, logger)
} catch (e) {
logger.error(e)
}
})
program.parse(process.argv)
{
"name": "movepng",
"version": "1.0.0",
"description": "",
"main": "movepng.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"caporal": "^1.3.0",
"fs-extra": "^8.1.0",
"image-size": "^0.8.3",
"lodash": "^4.17.15"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment