UTA DevHub

Image Optimization Guide

Comprehensive guide for optimizing images in React Native applications including format decisions, multi-resolution handling, and automated workflows

Image Optimization Guide

Overview

This guide provides comprehensive strategies for optimizing brand assets, illustrations, and complex graphics in React Native applications. We focus on format selection, multi-resolution handling, and automated optimization workflows.

SVG vs Image Format Decision Framework

When to Use SVG for Brand Assets

(Do ✅) Use SVG for:

  • Logos: Perfect scalability, crisp at any size, small file size
  • Simple Illustrations: Vector-based graphics with solid colors
  • Icons in Brand Assets: Brand-specific iconography
  • Geometric Graphics: Shapes, patterns, simple designs

Benefits:

  • Resolution independent (perfect on all screen densities)
  • Smaller file sizes for simple graphics
  • Easy to programmatically modify colors/styling
  • Crisp rendering at any scale

When to Use PNG/JPG for Brand Assets

(Do ✅) Use PNG/JPG for:

  • Photographic Content: Real photos, complex textures
  • Complex Illustrations: Detailed artwork with gradients, shadows, effects
  • Screenshots: App screenshots, UI mockups
  • Backgrounds: Complex gradients, photographic backgrounds

Benefits:

  • Better for photographic/complex content
  • Faster rendering for complex graphics
  • No dependency on react-native-svg
  • Better browser/platform compatibility

Decision Matrix

Asset TypeSVGPNGJPGRecommendation
Company Logo🤔SVG - Perfect scalability
Product Logo🤔SVG - Brand consistency
Simple Illustration🤔SVG - Small size, scalable
Complex Illustration🤔PNG/JPG - Better rendering
Photo Background🤔JPG - Optimized for photos
App Screenshots🤔PNG - Lossless UI elements
Hero Banner (photo)🤔JPG - Photographic content
Hero Banner (graphic)🤔SVG - Vector graphics

Multi-Resolution Image Management

Understanding Screen Densities

Screen Density Basics: React Native automatically selects the appropriate image resolution based on device pixel density. Provide multiple resolutions to ensure crisp rendering across all devices.

DensityScale FactorTypical DevicesFile Suffix
MDPI1xLower-end Androidimage.png
HDPI/Retina2xMost modern devicesimage@2x.png
XHDPI3xHigh-end devicesimage@3x.png

Multi-Resolution Implementation

PNG/JPG Multi-Resolution Setup

assets/brand/logos/
├── partner-logo.png        # 1x resolution (base)
├── partner-logo@2x.png     # 2x resolution
└── partner-logo@3x.png     # 3x resolution

Best Practices:

  • (Do ✅) Start with highest resolution and scale down
  • (Do ✅) Maintain aspect ratio across all resolutions
  • (Do ✅) Use consistent naming with @2x, @3x suffixes
  • (Don't ❌) Use only single resolution images

Image Optimization Workflows

Manual Optimization Tools

Online Optimization Tools

Privacy Consideration: Be aware of privacy implications when using online tools with sensitive brand assets. Consider on-premise solutions for confidential materials.

Automated Optimization Pipeline

Set Up Package Scripts

Add optimization scripts to your package.json

{
  "scripts": {
    "optimize:images": "imagemin assets/brand/**/*.{jpg,png} --out-dir=assets/brand/optimized",
    "optimize:svg": "svgo assets/brand/**/*.svg",
    "generate:webp": "node scripts/generate-webp.js",
    "optimize:all": "npm run optimize:images && npm run optimize:svg"
  }
}

Install Optimization Dependencies

Add necessary packages for automated optimization

npm install --save-dev imagemin imagemin-pngquant imagemin-mozjpeg svgo

Create Optimization Script

Set up automated processing for new assets

// scripts/optimize-assets.js
const imagemin = require('imagemin');
const imageminPngquant = require('imagemin-pngquant');
const imageminMozjpeg = require('imagemin-mozjpeg');
 
async function optimizeImages() {
  await imagemin(['assets/brand/**/*.{jpg,png}'], {
    destination: 'assets/brand/optimized',
    plugins: [
      imageminMozjpeg({ quality: 85 }),
      imageminPngquant({ quality: [0.6, 0.8] })
    ]
  });
  console.log('Images optimized!');
}
 
optimizeImages();

Set Up Pre-commit Hook

Automatically optimize assets before committing

// package.json
{
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "assets/**/*.{png,jpg,jpeg}": [
      "npm run optimize:images",
      "git add"
    ],
    "assets/**/*.svg": [
      "npm run optimize:svg",
      "git add"
    ]
  }
}

Asset Constants Pattern

Centralized Asset Management

// core/constants/images.ts
export const Images = {
  brand: {
    logos: {
      // SVG logos (recommended for scalability)
      company: require('@/assets/brand/logos/company-logo.svg'),
      product: require('@/assets/brand/logos/product-logo.svg'),
      // PNG logos (when SVG not available)
      partner: require('@/assets/brand/logos/partner-logo.png'),
    },
    illustrations: {
      onboarding: {
        // SVG for simple illustrations
        welcomeSimple: require('@/assets/brand/illustrations/onboarding/welcome-simple.svg'),
        // PNG for complex illustrations
        featuresComplex: require('@/assets/brand/illustrations/onboarding/features-complex.png'),
      },
      emptyStates: {
        // SVG for simple graphics
        noData: require('@/assets/brand/illustrations/empty-states/no-data.svg'),
        noNetwork: require('@/assets/brand/illustrations/empty-states/no-network.svg'),
      },
    },
    backgrounds: {
      // JPG for photographic backgrounds
      splashPhoto: require('@/assets/brand/backgrounds/splash-photo.jpg'),
      heroBanner: require('@/assets/brand/backgrounds/hero-banner.jpg'),
      // SVG for geometric/gradient backgrounds
      gradientBg: require('@/assets/brand/backgrounds/gradient-bg.svg'),
    },
  },
};

Usage Examples

SVG Component Usage

// SVG Components (for logos and simple graphics)
import CompanyLogo from '@/assets/brand/logos/CompanyLogo';
 
export const Header = () => (
  <View style={styles.header}>
    <CompanyLogo width={120} height={40} />
  </View>
);

Common Optimization Issues

Issue 1: Oversized Images

Problem: Using large images for small display areas Impact: Increased bundle size, slower loading, memory issues

// ❌ BAD: Using unoptimized images
<Image source={require('./hero.png')} />
// 5MB image displayed at 200x200
 
// ✅ GOOD: Using optimized assets
<Image
  source={require('./hero-optimized.jpg')}
  style={{ width: 200, height: 200 }}
  resizeMode="cover"
/>
// 150KB image sized appropriately

Issue 2: Missing Multi-Resolution Assets

Problem: Only providing single resolution images Impact: Blurry images on high-density screens

// ❌ BAD: Single resolution only
assets/brand/logos/logo.png
 
// ✅ GOOD: Multiple resolutions
assets/brand/logos/logo.png      # 1x
assets/brand/logos/logo@2x.png   # 2x  
assets/brand/logos/logo@3x.png   # 3x

Issue 3: Wrong Format Selection

Problem: Using PNG for photographic content or JPG for logos Impact: Larger file sizes, quality issues

// ❌ BAD: Wrong format choices
company-logo.jpg        // Should be SVG or PNG
photo-background.png    // Should be JPG
complex-illustration.svg // Should be PNG for complex artwork
 
// ✅ GOOD: Correct format choices
company-logo.svg        // Vector logo
photo-background.jpg    // Photographic content
complex-illustration.png // Complex raster artwork

Performance Best Practices

Bundle Size Management

  • (Do ✅) Monitor bundle size impact when adding new assets
  • (Do ✅) Use bundle analyzer to identify large assets
  • (Do ✅) Implement lazy loading for large assets
  • (Consider 🤔) Using remote assets for very large images

Memory Management

  • (Do ✅) Specify image dimensions to prevent layout shifts
  • (Do ✅) Use appropriate resizeMode for your use case
  • (Do ✅) Implement image caching with libraries like FastImage
  • (Don't ❌) Load large images unnecessarily

Loading Strategies

// ✅ GOOD: Lazy loading with FastImage
import FastImage from 'react-native-fast-image';
 
export const OptimizedImage = ({ source, style }) => (
  <FastImage
    source={source}
    style={style}
    resizeMode={FastImage.resizeMode.cover}
    priority={FastImage.priority.normal}
  />
);

Asset Naming Conventions

✅ GOOD:
- logo-company-primary.svg
- logo-product-secondary.svg
- bg-onboarding-welcome.jpg
- bg-onboarding-welcome@2x.jpg
- bg-onboarding-welcome@3x.jpg
- illustration-empty-state-no-data.svg

❌ BAD:
- company_logo.png
- CompanyLogo.png
- logo-2x.png (missing descriptive name)
- onboarding_bg_1.jpg (unclear purpose)

Naming Conventions

  • Use kebab-case for all filenames
  • Include asset type prefix (logo-, bg-, illustration-)
  • Add descriptive context (company, product, onboarding)
  • Use semantic suffixes (@2x, @3x for multi-resolution)

Testing Asset Optimization

// __tests__/assets.test.ts
describe('Asset Optimization', () => {
  it('should load all required brand assets', () => {
    Object.values(Images.brand.logos).forEach(image => {
      expect(image).toBeDefined();
    });
  });
 
  it('should have optimized file sizes', async () => {
    // Test that images are under reasonable size limits
    const logoSize = await getAssetSize(Images.brand.logos.company);
    expect(logoSize).toBeLessThan(50000); // 50KB limit for logos
  });
 
  it('should provide multi-resolution assets', () => {
    // Verify that @2x and @3x variants exist for PNG/JPG
    const partnerLogo = Images.brand.logos.partner;
    expect(partnerLogo).toBeDefined();
    // Additional checks for resolution variants
  });
});