Skip to main content Link Search Menu Expand Document (external link)

@data-img, @data-img-data, @data-img-type : Image Data Attributes

The data-img, data-img-data, and data-img-type attributes provide alternative methods for loading images in Scryber PDF documents. These attributes enable binding image data directly from memory, databases, or APIs without requiring file system access, supporting dynamic binary image data with explicit MIME type specification.

Usage

These attributes provide programmatic image loading:

  • data-img - Binds directly to an ImageData object (binding only)
  • data-img-data - Accepts binary image data as a byte array (binding only)
  • data-img-type - Specifies the MIME type for binary image data
  • Used when images come from databases, APIs, or memory
  • Bypasses file system and URL loading
  • Supports all standard image formats (JPEG, PNG, GIF)
  • Complements the standard src attribute
  • Required MIME type specification for proper image decoding
  • Enables dynamic image generation and manipulation
<!-- Bind to ImageData object -->
<img data-img="" width="200pt" height="150pt" />

<!-- Binary data with MIME type -->
<img data-img-data=""
     data-img-type="image/jpeg"
     width="300pt" height="200pt" />

<!-- PNG image from database -->
<img data-img-data=""
     data-img-type="image/png"
     width="150pt" height="75pt"
     alt="Company Logo" />

<!-- Dynamic image with fallback -->
<img src="fallback.jpg"
     data-img-data=""
     data-img-type="image/png"
     width="400pt" height="300pt" />

Supported Elements

These attributes are used exclusively with:

Image Element

  • <img> - Displays images in PDF documents (primary use)

Binding Values

These attributes are designed specifically for data binding scenarios:

data-img Binding

<!-- Bind to ImageData object -->
<!-- Model: { logo: ImageData object } -->
<img data-img="" width="100pt" height="50pt" />

<!-- Collection of ImageData objects -->
<!-- Model: { images: [ImageData, ImageData, ...] } -->
<template data-bind="">
    <img data-img="" width="200pt" height="150pt"
         style="margin: 5pt;" />
</template>

data-img-data and data-img-type Binding

<!-- Simple binary binding -->
<!-- Model: { photoBytes: byte[], photoType: "image/jpeg" } -->
<img data-img-data=""
     data-img-type=""
     width="200pt" height="150pt" />

<!-- Static MIME type -->
<img data-img-data=""
     data-img-type="image/png"
     width="150pt" height="100pt" />

<!-- Multiple images from database -->
<!-- Model: { photos: [{ data: byte[], type: "image/jpeg" }, ...] } -->
<template data-bind="">
    <img data-img-data=""
         data-img-type=""
         width="150pt" height="150pt"
         alt=""
         style="margin: 5pt; border: 1pt solid #ddd;" />
</template>

<!-- Conditional binary or URL loading -->
<img src=""
     data-img-data=""
     data-img-type="image/jpeg"
     width="200pt" height="150pt" />

Data Model Example:

{
  "photoBytes": "<byte array>",
  "photoType": "image/jpeg",
  "pngData": "<byte array>",
  "photos": [
    {
      "data": "<byte array>",
      "type": "image/jpeg",
      "caption": "Photo 1"
    },
    {
      "data": "<byte array>",
      "type": "image/png",
      "caption": "Photo 2"
    }
  ],
  "useDefault": false,
  "customImageBytes": "<byte array>"
}

Notes

Attribute Purposes

data-img (Binding Only):

  • Binds to a complete ImageData object
  • ImageData contains all image information (dimensions, format, binary data)
  • Most direct approach when working with Scryber’s image infrastructure
  • BindingOnly attribute - only works in data binding expressions

data-img-data (Binding Only):

  • Accepts raw binary image data as byte array
  • Requires data-img-type to identify image format
  • Used for images from databases, APIs, or in-memory generation
  • BindingOnly attribute - only works in data binding expressions

data-img-type:

  • Specifies MIME type for binary image data
  • Required when using data-img-data
  • Can be static or data-bound
  • Supports: image/jpeg, image/png, image/gif

Loading Priority

When multiple image source attributes are present:

  1. data-img-data with data-img-type - Highest priority
  2. data-img - Second priority
  3. src attribute - Fallback if above are not present
<!-- data-img-data takes precedence -->
<img src="fallback.jpg"
     data-img-data=""
     data-img-type="image/png"
     width="200pt" height="150pt" />

Supported MIME Types

The data-img-type attribute accepts standard image MIME types:

MIME Type Format Description
image/jpeg JPEG/JPG Compressed photos, no transparency
image/png PNG Lossless compression, supports transparency
image/gif GIF Supports transparency and animation
image/bmp BMP Uncompressed bitmap (may work)
image/tiff TIFF High-quality images (may work)
<!-- JPEG image -->
<img data-img-data=""
     data-img-type="image/jpeg"
     width="300pt" height="200pt" />

<!-- PNG with transparency -->
<img data-img-data=""
     data-img-type="image/png"
     width="150pt" height="150pt" />

<!-- GIF image -->
<img data-img-data=""
     data-img-type="image/gif"
     width="100pt" height="100pt" />

Binary Data Sources

Common sources for binary image data:

  1. Database BLOBs: Images stored in database binary columns
  2. APIs: Image data returned from REST/SOAP services
  3. File Uploads: User-uploaded images from web forms
  4. Dynamic Generation: Images created at runtime (charts, QR codes)
  5. Memory Caching: Pre-loaded images cached in memory
  6. Image Processing: Modified/transformed images
<!-- From database -->
<img data-img-data=""
     data-img-type="image/jpeg"
     width="100pt" height="100pt" />

<!-- From API response -->
<img data-img-data=""
     data-img-type=""
     width="200pt" height="150pt" />

<!-- Dynamically generated QR code -->
<img data-img-data=""
     data-img-type="image/png"
     width="80pt" height="80pt" />

Error Handling

When binary image data cannot be loaded:

Missing MIME Type:

<!-- This will fail - no MIME type specified -->
<img data-img-data="" width="200pt" />

Strict Mode: Throws exception, stops generation Lax Mode: Logs warning, continues without image

Invalid Binary Data:

  • Corrupt or invalid image bytes
  • MIME type doesn’t match actual data format
  • Empty or null byte array
<!-- Proper error handling -->
<img data-img-data=""
     data-img-type="image/jpeg"
     data-allow-missing-images="true"
     alt="User Photo"
     width="150pt" height="150pt" />

Performance Considerations

Binary image loading:

Advantages:

  • No file system I/O required
  • No network requests
  • Faster for pre-loaded images
  • Enables dynamic image generation

Disadvantages:

  • Images remain in memory
  • Larger memory footprint
  • No automatic caching by path
  • Binary data must be included in model

Best Practices:

<!-- Good: Small images from database -->
<img data-img-data=""
     data-img-type="image/jpeg"
     width="100pt" height="75pt" />

<!-- Consider file path for large images -->
<!-- Instead of loading 5MB image into memory: -->
<img src="" width="600pt" height="400pt" />

Memory Management

For large documents with many binary images:

  1. Stream When Possible: Use file paths instead of loading all images into memory
  2. Lazy Loading: Load images just before rendering
  3. Image Sizing: Resize images before converting to byte arrays
  4. Compression: Use JPEG for photos to reduce size
  5. Cleanup: Clear image data after PDF generation

ImageData Object Structure

The data-img attribute expects an ImageData object:

// C# Example creating ImageData
var imageData = new ImageData(width, height, imageFormat);
imageData.SetData(byteArray);

// Pass to model
model.ImageData = imageData;
<!-- Use in template -->
<img data-img="" width="200pt" height="150pt" />

Combining with Standard Attributes

Binary image attributes work with all standard image attributes:

<!-- Full featured binary image -->
<img data-img-data=""
     data-img-type="image/png"
     width="300pt"
     height="200pt"
     alt="Product Photo"
     title="Product Details"
     class="product-image"
     style="border: 1pt solid #ddd; padding: 5pt;"
     data-allow-missing-images="true" />

Dynamic MIME Type Determination

MIME type can be determined at runtime:

<!-- Model determines type based on data -->
<!-- Model: { imageData: byte[], imageFormat: "jpeg|png|gif" } -->

<img data-img-data=""
     data-img-type="image/"
     width="200pt" height="150pt" />

Base64 Data URIs vs Binary Data

Comparison of approaches:

Base64 in src attribute:

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA..."
     width="100pt" height="100pt" />

Binary data with data-img-data:

<img data-img-data=""
     data-img-type="image/png"
     width="100pt" height="100pt" />

Recommendations:

  • Use src with data URI for small, embedded images
  • Use data-img-data for dynamic, database-driven images
  • Use src with file path for large, static images

Security Considerations

When handling binary image data:

  1. Validation: Verify image data is valid before rendering
  2. Size Limits: Enforce maximum image size limits
  3. Type Verification: Ensure MIME type matches actual data
  4. Sanitization: Validate user-uploaded images
  5. Memory Limits: Prevent memory exhaustion from large images
<!-- Validated and size-limited image -->
<img data-img-data=""
     data-img-type=""
     width="pt"
     height="pt"
     data-allow-missing-images="true" />

Image Factory Processing

The data-img-data attribute uses Scryber’s image factory system:

  1. Factory Lookup: System finds factory matching MIME type
  2. Data Validation: Factory validates binary data
  3. Image Loading: Binary data is decoded into ImageData
  4. Error Handling: Invalid data triggers error handling
  5. Rendering: Valid ImageData is rendered to PDF

If no factory matches the MIME type, an error is raised.


Examples

Basic Binary Image Loading

<!-- JPEG from byte array -->
<img data-img-data=""
     data-img-type="image/jpeg"
     width="300pt" height="200pt" />

<!-- PNG from byte array -->
<img data-img-data=""
     data-img-type="image/png"
     width="200pt" height="150pt" />

<!-- GIF from byte array -->
<img data-img-data=""
     data-img-type="image/gif"
     width="150pt" height="150pt" />

Database-Driven Images

<!-- User profile photo from database -->
<!-- Model: { user: { photoData: byte[], photoType: "image/jpeg" } } -->

<div style="text-align: center; padding: 20pt;">
    <img data-img-data=""
         data-img-type=""
         width="150pt" height="150pt"
         alt=""
         style="border-radius: 75pt; border: 3pt solid #336699;" />
    <h2></h2>
    <p></p>
</div>

Product Images from Database

<!-- Model: { products: [
    { name: "Widget A", imageData: byte[], imageType: "image/jpeg", price: 29.99 },
    { name: "Widget B", imageData: byte[], imageType: "image/png", price: 39.99 }
]} -->

<div>
    <h1>Product Catalog</h1>

    <template data-bind="">
        <div style="border: 1pt solid #ddd; padding: 15pt; margin-bottom: 20pt;
                    display: flex; align-items: center;">
            <img data-img-data=""
                 data-img-type=""
                 width="150pt" height="150pt"
                 alt=""
                 style="margin-right: 20pt; border: 1pt solid #eee;" />
            <div>
                <h2 style="margin: 0 0 10pt 0;"></h2>
                <p style="font-size: 18pt; color: #336699; font-weight: bold;">
                    $
                </p>
            </div>
        </div>
    </template>
</div>
<!-- Model: { gallery: [
    { data: byte[], format: "jpeg", caption: "Sunset" },
    { data: byte[], format: "png", caption: "Mountains" }
]} -->

<div>
    <h2>Photo Gallery</h2>

    <div style="display: flex; flex-wrap: wrap; gap: 10pt;">
        <template data-bind="">
            <div style="text-align: center;">
                <img data-img-data=""
                     data-img-type="image/"
                     width="200pt" height="150pt"
                     alt=""
                     style="border: 2pt solid #ddd; border-radius: 4pt;" />
                <p style="margin-top: 5pt;"></p>
            </div>
        </template>
    </div>
</div>

Dynamic QR Code Generation

<!-- Model: { qrCodes: [
    { code: byte[], label: "Product A", url: "https://..." },
    { code: byte[], label: "Product B", url: "https://..." }
]} -->

<div>
    <h2>Product QR Codes</h2>

    <template data-bind="">
        <div style="display: inline-block; margin: 15pt; text-align: center;">
            <img data-img-data=""
                 data-img-type="image/png"
                 width="100pt" height="100pt"
                 alt="QR Code for "
                 style="border: 1pt solid #ccc; padding: 5pt;" />
            <p style="margin-top: 5pt; font-weight: bold;"></p>
            <p style="margin: 0; font-size: 8pt; color: #666;"></p>
        </div>
    </template>
</div>

Employee Badge with Photo

<!-- Model: {
    employee: {
        photo: byte[], name: "John Doe",
        id: "E12345", department: "Engineering"
    }
} -->

<div style="width: 300pt; border: 2pt solid #336699; padding: 20pt;
            text-align: center; background-color: #f9f9f9;">
    <img data-img-data=""
         data-img-type="image/jpeg"
         width="150pt" height="180pt"
         alt=""
         style="border: 2pt solid #336699;" />

    <h2 style="margin: 15pt 0 5pt 0;"></h2>
    <p style="margin: 0; color: #666;"></p>
    <p style="margin: 10pt 0 0 0; font-family: monospace; font-size: 14pt;">
        ID: 
    </p>
</div>

Chart Images from Rendering Service

<!-- Model: {
    charts: [
        { data: byte[], title: "Sales Trend", type: "image/png" },
        { data: byte[], title: "Regional Distribution", type: "image/png" }
    ]
} -->

<div>
    <h1>Sales Analytics Dashboard</h1>

    <template data-bind="">
        <div style="margin: 30pt 0; page-break-inside: avoid;">
            <h2></h2>
            <div style="text-align: center; padding: 20pt; background-color: #f9f9f9;">
                <img data-img-data=""
                     data-img-type=""
                     width="600pt" height="400pt"
                     alt=" Chart"
                     style="border: 1pt solid #ddd;" />
            </div>
        </div>
    </template>
</div>

Image with Fallback Handling

<!-- Model: { userPhoto: byte[] | null, hasPhoto: boolean } -->

<div>
    <h2>User Profile</h2>

    <!-- Try binary data first, fallback to default image -->
    <img src=""
         data-img-data=""
         data-img-type="image/jpeg"
         width="150pt" height="150pt"
         data-allow-missing-images="true"
         alt="User Photo"
         style="border-radius: 75pt;" />
</div>

Medical Imaging Report

<!-- Model: {
    patient: { name: "Jane Smith", id: "P-789" },
    scans: [
        { imageData: byte[], type: "image/jpeg", view: "Frontal", date: "2024-01-15" },
        { imageData: byte[], type: "image/jpeg", view: "Lateral", date: "2024-01-15" }
    ]
} -->

<div>
    <h1>Medical Imaging Report</h1>
    <p>Patient:  ()</p>

    <template data-bind="">
        <div style="margin: 30pt 0; page-break-inside: avoid;">
            <h2> View - </h2>
            <div style="text-align: center; padding: 20pt; background-color: #000;">
                <img data-img-data=""
                     data-img-type=""
                     width="500pt" height="500pt"
                     alt=" scan from " />
            </div>
        </div>
    </template>
</div>

Signature Images from Database

<!-- Model: {
    document: { title: "Service Agreement" },
    signatures: [
        { name: "Client", imageData: byte[], date: "2024-01-10" },
        { name: "Provider", imageData: byte[], date: "2024-01-10" }
    ]
} -->

<div>
    <h1></h1>
    <p>Agreement content...</p>

    <div style="margin-top: 50pt;">
        <h2>Signatures</h2>

        <template data-bind="">
            <div style="display: inline-block; width: 45%; margin: 10pt;">
                <div style="border-bottom: 1pt solid #000; padding-bottom: 10pt;">
                    <img data-img-data=""
                         data-img-type="image/png"
                         width="200pt" height="80pt"
                         alt=" Signature" />
                </div>
                <p style="margin: 5pt 0 0 0;">
                    <strong></strong><br/>
                    Date: 
                </p>
            </div>
        </template>
    </div>
</div>

Real Estate Listing with Property Photos

<!-- Model: {
    property: {
        address: "123 Main St",
        price: "$450,000",
        photos: [
            { data: byte[], type: "image/jpeg", caption: "Front View" },
            { data: byte[], type: "image/jpeg", caption: "Living Room" },
            { data: byte[], type: "image/jpeg", caption: "Kitchen" },
            { data: byte[], type: "image/jpeg", caption: "Master Bedroom" }
        ]
    }
} -->

<div>
    <h1></h1>
    <h2 style="color: #336699;"></h2>

    <div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 15pt;">
        <template data-bind="">
            <div>
                <img data-img-data=""
                     data-img-type=""
                     width="280pt" height="210pt"
                     alt=""
                     style="width: 100%; border: 1pt solid #ddd;" />
                <p style="margin: 5pt 0; text-align: center; font-weight: bold;">
                    
                </p>
            </div>
        </template>
    </div>
</div>

Dynamic Thumbnail Generation

<!-- Model: {
    documents: [
        { name: "Report.pdf", thumbnail: byte[], pageCount: 15 },
        { name: "Analysis.pdf", thumbnail: byte[], pageCount: 8 }
    ]
} -->

<div>
    <h2>Document Library</h2>

    <template data-bind="">
        <div style="display: inline-block; margin: 10pt; width: 150pt;
                    text-align: center; border: 1pt solid #ddd; padding: 10pt;">
            <img data-img-data=""
                 data-img-type="image/png"
                 width="130pt" height="150pt"
                 alt="Thumbnail of "
                 style="border: 1pt solid #ccc; background-color: #f9f9f9;" />
            <p style="margin: 10pt 0 5pt 0; font-weight: bold;"></p>
            <p style="margin: 0; font-size: 9pt; color: #666;">
                 pages
            </p>
        </div>
    </template>
</div>

Barcode Labels

<!-- Model: {
    products: [
        { sku: "ABC123", barcode: byte[], name: "Widget A", price: 29.99 },
        { sku: "DEF456", barcode: byte[], name: "Widget B", price: 39.99 }
    ]
} -->

<div>
    <h2>Product Labels</h2>

    <template data-bind="">
        <div style="display: inline-block; width: 200pt; height: 150pt;
                    margin: 10pt; border: 1pt solid #000; padding: 10pt;">
            <div style="text-align: center;">
                <strong></strong>
            </div>
            <div style="text-align: center; margin: 10pt 0;">
                <img data-img-data=""
                     data-img-type="image/png"
                     width="150pt" height="60pt"
                     alt="Barcode for " />
            </div>
            <div style="text-align: center;">
                <p style="margin: 0; font-family: monospace;"></p>
                <p style="margin: 5pt 0 0 0; font-size: 16pt; font-weight: bold;">
                    $
                </p>
            </div>
        </div>
    </template>
</div>

Image Comparison Layout

<!-- Model: {
    comparison: {
        before: { data: byte[], type: "image/jpeg" },
        after: { data: byte[], type: "image/jpeg" }
    }
} -->

<div>
    <h2>Before and After Comparison</h2>

    <div style="display: flex; justify-content: space-around; margin: 20pt 0;">
        <div style="text-align: center;">
            <img data-img-data=""
                 data-img-type=""
                 width="280pt" height="210pt"
                 alt="Before"
                 style="border: 2pt solid #ccc;" />
            <p style="font-weight: bold; margin-top: 10pt; color: #666;">Before</p>
        </div>

        <div style="text-align: center;">
            <img data-img-data=""
                 data-img-type=""
                 width="280pt" height="210pt"
                 alt="After"
                 style="border: 2pt solid #28a745;" />
            <p style="font-weight: bold; margin-top: 10pt; color: #28a745;">After</p>
        </div>
    </div>
</div>

ID Card with Embedded Photo

<!-- Model: {
    card: {
        photo: byte[], name: "Jane Smith", id: "ID-456789",
        department: "Research", issued: "2024-01-01", expires: "2025-01-01"
    }
} -->

<div style="width: 400pt; height: 250pt; border: 3pt solid #336699;
            border-radius: 10pt; padding: 20pt; background-color: #f0f8ff;">
    <div style="display: flex;">
        <img data-img-data=""
             data-img-type="image/jpeg"
             width="120pt" height="150pt"
             alt=""
             style="border: 2pt solid #336699; margin-right: 20pt;" />

        <div style="flex: 1;">
            <h1 style="margin: 0 0 10pt 0; color: #336699;">
                
            </h1>
            <p style="margin: 5pt 0; font-size: 12pt;">
                <strong>Department:</strong> 
            </p>
            <p style="margin: 5pt 0; font-family: monospace; font-size: 14pt;">
                <strong>ID:</strong> 
            </p>
            <hr style="margin: 15pt 0;"/>
            <p style="margin: 5pt 0; font-size: 9pt; color: #666;">
                Issued: <br/>
                Expires: 
            </p>
        </div>
    </div>
</div>

Image Grid from API

<!-- Model: {
    apiImages: [
        { bytes: byte[], format: "png", id: "img-1" },
        { bytes: byte[], format: "jpeg", id: "img-2" },
        { bytes: byte[], format: "png", id: "img-3" },
        { bytes: byte[], format: "jpeg", id: "img-4" }
    ]
} -->

<div>
    <h2>Image Collection</h2>

    <div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 15pt;">
        <template data-bind="">
            <div style="border: 1pt solid #ddd; padding: 10pt; text-align: center;">
                <img data-img-data=""
                     data-img-type="image/"
                     width="250pt" height="200pt"
                     alt="Image "
                     style="border: 1pt solid #ccc;" />
                <p style="margin-top: 5pt; font-size: 9pt; color: #666;">
                     ()
                </p>
            </div>
        </template>
    </div>
</div>

Dynamic Logo Variations

<!-- Model: {
    logos: {
        color: byte[], grayscale: byte[], inverted: byte[]
    }
} -->

<div>
    <h2>Logo Variations</h2>

    <div style="text-align: center;">
        <div style="display: inline-block; margin: 15pt;">
            <img data-img-data=""
                 data-img-type="image/png"
                 width="150pt" height="75pt"
                 alt="Color Logo"
                 style="border: 1pt solid #ddd; padding: 10pt; background-color: #fff;" />
            <p style="margin-top: 5pt;">Color</p>
        </div>

        <div style="display: inline-block; margin: 15pt;">
            <img data-img-data=""
                 data-img-type="image/png"
                 width="150pt" height="75pt"
                 alt="Grayscale Logo"
                 style="border: 1pt solid #ddd; padding: 10pt; background-color: #fff;" />
            <p style="margin-top: 5pt;">Grayscale</p>
        </div>

        <div style="display: inline-block; margin: 15pt;">
            <img data-img-data=""
                 data-img-type="image/png"
                 width="150pt" height="75pt"
                 alt="Inverted Logo"
                 style="border: 1pt solid #ddd; padding: 10pt; background-color: #000;" />
            <p style="margin-top: 5pt;">Inverted</p>
        </div>
    </div>
</div>

Certificate with Seal Image

<!-- Model: {
    certificate: {
        recipient: "John Doe", course: "Advanced PDF Development",
        date: "2024-01-15", seal: byte[]
    }
} -->

<div style="border: 10pt double #336699; padding: 40pt; text-align: center;">
    <h1 style="font-size: 32pt; margin-bottom: 30pt;">Certificate of Completion</h1>

    <p style="font-size: 16pt; margin: 20pt 0;">This certifies that</p>

    <h2 style="font-size: 28pt; margin: 20pt 0; color: #336699;">
        
    </h2>

    <p style="font-size: 16pt; margin: 20pt 0;">has successfully completed</p>

    <h3 style="font-size: 20pt; margin: 20pt 0;">
        
    </h3>

    <p style="font-size: 14pt; margin: 30pt 0;">
        Date: 
    </p>

    <div style="margin-top: 40pt;">
        <img data-img-data=""
             data-img-type="image/png"
             width="120pt" height="120pt"
             alt="Official Seal"
             style="opacity: 0.8;" />
    </div>
</div>

See Also