org.codice.alliance.transformer.nitf.image.NitfPreStoragePlugin.java Source code

Java tutorial

Introduction

Here is the source code for org.codice.alliance.transformer.nitf.image.NitfPreStoragePlugin.java

Source

/**
 * Copyright (c) Codice Foundation
 * <p/>
 * This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser
 * General Public License as published by the Free Software Foundation, either version 3 of the
 * License, or any later version.
 * <p/>
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details. A copy of the GNU Lesser General Public License
 * is distributed along with this program and can be found at
 * <http://www.gnu.org/licenses/lgpl.html>.
 */
package org.codice.alliance.transformer.nitf.image;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.text.ParseException;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;

import javax.activation.MimeTypeParseException;
import javax.imageio.ImageIO;
import javax.imageio.spi.IIORegistry;

import org.apache.commons.io.FilenameUtils;
import org.codice.alliance.transformer.nitf.MetacardFactory;
import org.codice.imaging.nitf.core.common.NitfFormatException;
import org.codice.imaging.nitf.fluent.NitfParserInputFlow;
import org.codice.imaging.nitf.render.NitfRenderer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.github.jaiimageio.jpeg2000.impl.J2KImageReaderSpi;
import com.google.common.io.ByteSource;

import ddf.catalog.content.data.ContentItem;
import ddf.catalog.content.data.impl.ContentItemImpl;
import ddf.catalog.content.operation.CreateStorageRequest;
import ddf.catalog.content.operation.UpdateStorageRequest;
import ddf.catalog.content.plugin.PreCreateStoragePlugin;
import ddf.catalog.content.plugin.PreUpdateStoragePlugin;
import ddf.catalog.data.Metacard;
import ddf.catalog.data.impl.AttributeImpl;
import ddf.catalog.data.types.Core;
import ddf.catalog.plugin.PluginExecutionException;
import net.coobird.thumbnailator.Thumbnails;

/**
 * This pre-storage plugin creates and stores the NITF thumbnail and NITF overview images.  The
 * thumbnail is stored with the Metacard while the overview is stored in the content store.
 */
public class NitfPreStoragePlugin implements PreCreateStoragePlugin, PreUpdateStoragePlugin {

    private static final String IMAGE_JPEG = "image/jpeg";

    private static final int THUMBNAIL_WIDTH = 200;

    private static final int THUMBNAIL_HEIGHT = 200;

    private static final String JPG = "jpg";

    private static final Logger LOGGER = LoggerFactory.getLogger(NitfPreStoragePlugin.class);

    private static final String OVERVIEW = "overview";

    private static final String OVERVIEW_FILENAME_PATTERN = "%s-%s.%s";

    static {
        IIORegistry.getDefaultInstance().registerServiceProvider(new J2KImageReaderSpi());
    }

    @Override
    public CreateStorageRequest process(CreateStorageRequest createStorageRequest) throws PluginExecutionException {
        if (createStorageRequest == null) {
            throw new PluginExecutionException("process(): argument 'createStorageRequest' may not be null.");
        }

        process(createStorageRequest.getContentItems());
        return createStorageRequest;
    }

    @Override
    public UpdateStorageRequest process(UpdateStorageRequest updateStorageRequest) throws PluginExecutionException {
        if (updateStorageRequest == null) {
            throw new PluginExecutionException("process(): argument 'updateStorageRequest' may not be null.");
        }

        process(updateStorageRequest.getContentItems());
        return updateStorageRequest;
    }

    private boolean isNitfMimeType(String rawMimeType) {
        try {
            return MetacardFactory.MIME_TYPE.match(rawMimeType);
        } catch (MimeTypeParseException e) {
            LOGGER.warn("unable to compare mime types: {} vs {}", MetacardFactory.MIME_TYPE, rawMimeType);
        }

        return false;
    }

    private void process(List<ContentItem> contentItems) {
        List<ContentItem> newContentItems = new LinkedList<>();
        contentItems.forEach(contentItem -> process(contentItem).ifPresent(newContentItems::add));
        contentItems.addAll(newContentItems);
    }

    private Optional<ContentItem> process(ContentItem contentItem) {
        Metacard metacard = contentItem.getMetacard();

        if (!isNitfMimeType(contentItem.getMimeTypeRawData())) {
            LOGGER.debug("skipping content item: filename={} mimeType={}", contentItem.getFilename(),
                    contentItem.getMimeTypeRawData());
            return Optional.empty();
        }

        try {
            BufferedImage renderedImage = renderImage(contentItem);

            if (renderedImage != null) {
                addThumbnailToMetacard(metacard, renderedImage);
                ContentItem overviewContentItem = createOverview(contentItem.getId(), renderedImage, metacard);

                return Optional.ofNullable(overviewContentItem);
            }
        } catch (IOException | ParseException | NitfFormatException | UnsupportedOperationException e) {
            LOGGER.warn(e.getMessage(), e);
        }

        return Optional.empty();
    }

    private BufferedImage renderImage(ContentItem contentItem)
            throws IOException, ParseException, NitfFormatException {

        final ThreadLocal<BufferedImage> bufferedImage = new ThreadLocal<>();

        if (contentItem != null && contentItem.getInputStream() != null) {
            NitfRenderer renderer = new NitfRenderer();

            new NitfParserInputFlow().inputStream(contentItem.getInputStream()).allData()
                    .forEachImageSegment(segment -> {
                        if (bufferedImage.get() == null) {
                            try {
                                bufferedImage.set(renderer.render(segment));
                            } catch (IOException e) {
                                LOGGER.error(e.getMessage(), e);
                            }
                        }
                    }).end();
        }

        return bufferedImage.get();
    }

    private void addThumbnailToMetacard(Metacard metacard, BufferedImage bufferedImage) {
        try {
            byte[] thumbnailImage = scaleImage(bufferedImage, THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT);

            if (thumbnailImage.length > 0) {
                metacard.setAttribute(new AttributeImpl(Core.THUMBNAIL, thumbnailImage));
            }
        } catch (IOException e) {
            LOGGER.error(e.getMessage(), e);
        }
    }

    private ContentItem createOverview(String id, BufferedImage image, Metacard metacard) {
        try {
            byte[] overviewBytes = scaleImage(image, image.getWidth(), image.getHeight());
            ByteSource source = ByteSource.wrap(overviewBytes);
            ContentItem contentItem = new ContentItemImpl(id, OVERVIEW, source, IMAGE_JPEG,
                    buildOverviewTitle(metacard.getTitle()), overviewBytes.length, metacard);

            metacard.setAttribute(new AttributeImpl(Core.DERIVED_RESOURCE_URI, contentItem.getUri()));

            return contentItem;
        } catch (IOException e) {
            LOGGER.error(e.getMessage(), e);
        }

        return null;
    }

    private String buildOverviewTitle(String title) {
        String rootFileName = FilenameUtils.getBaseName(title);
        return String.format(OVERVIEW_FILENAME_PATTERN, OVERVIEW, rootFileName, JPG);
    }

    private byte[] scaleImage(final BufferedImage bufferedImage, int width, int height) throws IOException {
        BufferedImage thumbnail = Thumbnails.of(bufferedImage).size(width, height).outputFormat(JPG)
                .imageType(BufferedImage.TYPE_3BYTE_BGR).asBufferedImage();

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ImageIO.write(thumbnail, JPG, outputStream);
        outputStream.flush();
        byte[] thumbnailBytes = outputStream.toByteArray();
        outputStream.close();
        return thumbnailBytes;
    }
}