use of org.mycore.imagetiler.MCRTiledPictureProps in project mycore by MyCoRe-Org.
the class MCRTileCombineServlet method think.
/**
* prepares render process and gets IView2 file and combines tiles.
* The image dimensions and path are determined from {@link HttpServletRequest#getPathInfo()}:
* <code>/{zoomAlias}/{derivateID}/{absoluteImagePath}</code>
* where <code>zoomAlias</code> is mapped like this:
* <table>
* <caption>Mapping of zoomAlias to actual zoom level</caption>
* <tr><th>zoomAlias</th><th>zoom level</th></tr>
* <tr><td>'MIN'</td><td>1</td></tr>
* <tr><td>'MID'</td><td>2</td></tr>
* <tr><td>'MAX'</td><td>3</td></tr>
* <tr><td>default and all others</td><td>0</td></tr>
* </table>
*
* See {@link #init()} how to attach a footer to every generated image.
*/
@Override
protected void think(final MCRServletJob job) throws IOException, JDOMException {
final HttpServletRequest request = job.getRequest();
try {
String pathInfo = request.getPathInfo();
if (pathInfo.startsWith("/")) {
pathInfo = pathInfo.substring(1);
}
String zoomAlias = pathInfo.substring(0, pathInfo.indexOf('/'));
pathInfo = pathInfo.substring(zoomAlias.length() + 1);
final String derivate = pathInfo.substring(0, pathInfo.indexOf('/'));
String imagePath = pathInfo.substring(derivate.length());
LOGGER.info("Zoom-Level: {}, derivate: {}, image: {}", zoomAlias, derivate, imagePath);
final Path iviewFile = MCRImage.getTiledFile(MCRIView2Tools.getTileDir(), derivate, imagePath);
try (FileSystem fs = MCRIView2Tools.getFileSystem(iviewFile)) {
Path iviewFileRoot = fs.getRootDirectories().iterator().next();
final MCRTiledPictureProps pictureProps = MCRTiledPictureProps.getInstanceFromDirectory(iviewFileRoot);
final int maxZoomLevel = pictureProps.getZoomlevel();
request.setAttribute(THUMBNAIL_KEY, iviewFile);
LOGGER.info("IView2 file: {}", iviewFile);
int zoomLevel = 0;
switch(zoomAlias) {
case "MIN":
zoomLevel = 1;
break;
case "MID":
zoomLevel = 2;
break;
case "MAX":
zoomLevel = 3;
break;
}
HttpServletResponse response = job.getResponse();
if (zoomLevel > maxZoomLevel) {
switch(maxZoomLevel) {
case 2:
zoomAlias = "MID";
break;
case 1:
zoomAlias = "MIN";
break;
default:
zoomAlias = "THUMB";
break;
}
if (!imagePath.startsWith("/"))
imagePath = "/" + imagePath;
String redirectURL = response.encodeRedirectURL(MessageFormat.format("{0}{1}/{2}/{3}{4}", request.getContextPath(), request.getServletPath(), zoomAlias, derivate, imagePath));
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
response.setHeader("Location", redirectURL);
response.flushBuffer();
return;
}
if (zoomLevel == 0 && footerImpl == null) {
// we're done, sendThumbnail is called in render phase
return;
}
ImageReader reader = MCRIView2Tools.getTileImageReader();
try {
BufferedImage combinedImage = MCRIView2Tools.getZoomLevel(iviewFileRoot, pictureProps, reader, zoomLevel);
if (combinedImage != null) {
if (footerImpl != null) {
BufferedImage footer = footerImpl.getFooter(combinedImage.getWidth(), derivate, imagePath);
combinedImage = attachFooter(combinedImage, footer);
}
request.setAttribute(IMAGE_KEY, combinedImage);
} else {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
} finally {
reader.dispose();
}
}
} finally {
LOGGER.info("Finished sending {}", request.getPathInfo());
}
}
use of org.mycore.imagetiler.MCRTiledPictureProps in project mycore by MyCoRe-Org.
the class MCRIVIEWIIIFImageImpl method provide.
@Override
public BufferedImage provide(String identifier, MCRIIIFImageSourceRegion region, MCRIIIFImageTargetSize targetSize, MCRIIIFImageTargetRotation rotation, MCRIIIFImageQuality imageQuality, String format) throws MCRIIIFImageNotFoundException, MCRIIIFImageProvidingException, MCRIIIFUnsupportedFormatException, MCRAccessException {
long resultingSize = (long) targetSize.getHeight() * targetSize.getWidth() * (imageQuality.equals(MCRIIIFImageQuality.color) ? 3 : 1);
long maxImageSize = MCRConfiguration.instance().getLong(MAX_BYTES);
if (resultingSize > maxImageSize) {
throw new MCRIIIFImageProvidingException("Maximal image size is " + (maxImageSize / 1024 / 1024) + "MB. [" + resultingSize + "/" + maxImageSize + "]");
}
if (!SUPPORTED_FORMATS.contains(format.toLowerCase(Locale.ENGLISH))) {
throw new MCRIIIFUnsupportedFormatException(format);
}
Path tiledFile = tileFileProvider.getTiledFile(identifier);
MCRTiledPictureProps tiledPictureProps = getTiledPictureProps(tiledFile);
int sourceWidth = region.getX2() - region.getX1();
int sourceHeight = region.getY2() - region.getY1();
double targetWidth = targetSize.getWidth();
double targetHeight = targetSize.getHeight();
double rotatationRadians = Math.toRadians(rotation.getDegrees());
double sinRotation = Math.sin(rotatationRadians);
double cosRotation = Math.cos(rotatationRadians);
final int height = (int) (Math.abs(targetWidth * sinRotation) + Math.abs(targetHeight * cosRotation));
final int width = (int) (Math.abs(targetWidth * cosRotation) + Math.abs(targetHeight * sinRotation));
BufferedImage targetImage;
switch(imageQuality) {
case bitonal:
targetImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY);
break;
case gray:
targetImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
break;
case color:
default:
if (transparentFormats.contains(format)) {
targetImage = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
} else {
targetImage = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
}
}
// this value determines the zoom level!
double largestScaling = Math.max(targetWidth / sourceWidth, targetHeight / sourceHeight);
// We always want to use the the best needed zoom level!
int sourceZoomLevel = (int) Math.min(Math.max(0, Math.ceil(tiledPictureProps.getZoomlevel() - Math.log(largestScaling) / LOG_HALF)), tiledPictureProps.getZoomlevel());
// largestScaling is the real scale which is needed! zoomLevelScale is the scale of the nearest zoom level!
double zoomLevelScale = Math.min(1.0, Math.pow(0.5, tiledPictureProps.getZoomlevel() - sourceZoomLevel));
// this is the scale which is needed from the nearest zoom level to the required size of image
double drawScaleX = (targetWidth / (sourceWidth * zoomLevelScale)), drawScaleY = (targetHeight / (sourceHeight * zoomLevelScale));
// absolute region in zoom level this nearest zoom level
double x1 = region.getX1() * zoomLevelScale, x2 = region.getX2() * zoomLevelScale, y1 = region.getY1() * zoomLevelScale, y2 = region.getY2() * zoomLevelScale;
// now we detect the tiles to draw!
int x1Tile = (int) Math.floor(x1 / 256), y1Tile = (int) Math.floor(y1 / 256), x2Tile = (int) Math.ceil(x2 / 256), y2Tile = (int) Math.ceil(y2 / 256);
try (FileSystem zipFileSystem = MCRIView2Tools.getFileSystem(tileFileProvider.getTiledFile(identifier))) {
Path rootPath = zipFileSystem.getPath("/");
Graphics2D graphics = targetImage.createGraphics();
if (rotation.isMirrored()) {
graphics.scale(-1, 1);
graphics.translate(-width, 0);
}
int xt = (int) ((targetWidth - 1) / 2), yt = (int) ((targetHeight - 1) / 2);
graphics.translate((width - targetWidth) / 2, (height - targetHeight) / 2);
graphics.rotate(rotatationRadians, xt, yt);
graphics.scale(drawScaleX, drawScaleY);
graphics.translate(-x1, -y1);
graphics.scale(zoomLevelScale, zoomLevelScale);
graphics.setClip(region.getX1(), region.getY1(), sourceWidth, sourceHeight);
graphics.scale(1 / zoomLevelScale, 1 / zoomLevelScale);
LOGGER.info(String.format(Locale.ROOT, "Using zoom-level: %d and scales %s/%s!", sourceZoomLevel, drawScaleX, drawScaleY));
for (int x = x1Tile; x < x2Tile; x++) {
for (int y = y1Tile; y < y2Tile; y++) {
ImageReader imageReader = MCRIView2Tools.getTileImageReader();
BufferedImage tile = MCRIView2Tools.readTile(rootPath, imageReader, sourceZoomLevel, x, y);
graphics.drawImage(tile, x * 256, y * 256, null);
}
}
} catch (IOException e) {
throw new MCRIIIFImageProvidingException("Error while reading tiles!", e);
}
return targetImage;
}
use of org.mycore.imagetiler.MCRTiledPictureProps in project mycore by MyCoRe-Org.
the class MCRImageThumbnailGenerator method getThumbnail.
@Override
public Optional<BufferedImage> getThumbnail(MCRPath path, int size) throws IOException {
Path iviewFile = MCRImage.getTiledFile(MCRIView2Tools.getTileDir(), path.getOwner(), path.getFileName().toString());
MCRTiledPictureProps iviewFileProps = getIviewFileProps(iviewFile);
final double width = iviewFileProps.getWidth();
final double height = iviewFileProps.getHeight();
final int newWidth = width > height ? (int) Math.ceil(size * width / height) : size;
final int newHeight = width > height ? size : (int) Math.ceil(size * height / width);
// this value determines the zoom level!
final double scale = newWidth / width;
// We always want to use the the best needed zoom level!
int sourceZoomLevel = (int) Math.min(Math.max(0, Math.ceil(iviewFileProps.getZoomlevel() - Math.log(scale) / Math.log(1.0 / 2.0))), iviewFileProps.getZoomlevel());
// scale is the real scale which is needed! zoomLevelScale is the scale of the nearest zoom level!
double zoomLevelScale = Math.min(1.0, Math.pow(0.5, iviewFileProps.getZoomlevel() - sourceZoomLevel));
// this is the scale which is needed from the nearest zoom level to the required size of image
double drawScale = (newWidth / (width * zoomLevelScale));
try (FileSystem zipFileSystem = MCRIView2Tools.getFileSystem(iviewFile)) {
Path rootPath = zipFileSystem.getPath("/");
ImageReader imageReader = MCRIView2Tools.getTileImageReader();
BufferedImage testTile = MCRIView2Tools.readTile(rootPath, imageReader, sourceZoomLevel, 0, 0);
BufferedImage targetImage = getTargetImage(newWidth, newHeight, testTile);
Graphics2D graphics = targetImage.createGraphics();
graphics.scale(drawScale, drawScale);
for (int x = 0; x < Math.ceil(width * zoomLevelScale / 256); x++) {
for (int y = 0; y < Math.ceil(height * zoomLevelScale / 256); y++) {
BufferedImage tile = MCRIView2Tools.readTile(rootPath, imageReader, sourceZoomLevel, x, y);
graphics.drawImage(tile, x * 256, y * 256, null);
}
}
return Optional.of(targetImage);
}
}
use of org.mycore.imagetiler.MCRTiledPictureProps in project mycore by MyCoRe-Org.
the class MCRTilingAction method run.
/**
* takes a {@link MCRTileJob} and tiles the referenced {@link MCRImage} instance.
*
* Also this updates tileJob properties of {@link MCRTileJob} in the database.
*/
public void run() {
tileJob.setStart(new Date());
MCRImage image;
Path tileDir = MCRIView2Tools.getTileDir();
try {
image = getMCRImage();
image.setTileDir(tileDir);
} catch (IOException e) {
LOGGER.error("Error while retrieving image for job: {}", tileJob, e);
return;
}
MCRSession mcrSession = MCRSessionMgr.getCurrentSession();
mcrSession.setUserInformation(MCRSystemUserInformation.getSystemUserInstance());
Transaction transaction = null;
try (Session session = MCRHIBConnection.instance().getSession()) {
MCRTileEventHandler tileEventHandler = new MCRTileEventHandler() {
Transaction transaction;
@Override
public void preImageReaderCreated() {
transaction = session.beginTransaction();
}
@Override
public void postImageReaderCreated() {
// beside tileJob, no write access so far
session.clear();
if (transaction.getStatus().isOneOf(TransactionStatus.ACTIVE)) {
transaction.commit();
}
}
};
try {
MCRTiledPictureProps picProps = image.tile(tileEventHandler);
tileJob.setFinished(new Date());
tileJob.setStatus(MCRJobState.FINISHED);
tileJob.setHeight(picProps.getHeight());
tileJob.setWidth(picProps.getWidth());
tileJob.setTiles(picProps.getTilesCount());
tileJob.setZoomLevel(picProps.getZoomlevel());
} catch (IOException e) {
LOGGER.error("IOException occured while tiling a queued picture", e);
throw e;
}
transaction = session.beginTransaction();
session.update(tileJob);
transaction.commit();
} catch (Exception e) {
LOGGER.error("Error while getting next tiling job.", e);
if (transaction != null && transaction.getStatus().isOneOf(TransactionStatus.ACTIVE)) {
transaction.rollback();
}
try {
Files.deleteIfExists(MCRImage.getTiledFile(tileDir, tileJob.getDerivate(), tileJob.getPath()));
} catch (IOException e1) {
LOGGER.error("Could not delete tile file after error!", e);
}
} finally {
MCRSessionMgr.releaseCurrentSession();
mcrSession.close();
}
}
Aggregations