mirror of
				https://github.com/Frooodle/Stirling-PDF.git
				synced 2025-11-01 01:21:18 +01:00 
			
		
		
		
	extract and apply the image orientation from exif data in imageToPdf (#2073)
This commit is contained in:
		
							parent
							
								
									bac81c930d
								
							
						
					
					
						commit
						e0b77ca274
					
				@ -179,6 +179,9 @@ dependencies {
 | 
				
			|||||||
    runtimeOnly "com.twelvemonkeys.imageio:imageio-webp:$imageioVersion"
 | 
					    runtimeOnly "com.twelvemonkeys.imageio:imageio-webp:$imageioVersion"
 | 
				
			||||||
    // runtimeOnly "com.twelvemonkeys.imageio:imageio-xwd:$imageioVersion"
 | 
					    // runtimeOnly "com.twelvemonkeys.imageio:imageio-xwd:$imageioVersion"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Image metadata extractor
 | 
				
			||||||
 | 
					    implementation "com.drewnoakes:metadata-extractor:2.19.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    implementation "commons-io:commons-io:2.17.0"
 | 
					    implementation "commons-io:commons-io:2.17.0"
 | 
				
			||||||
    implementation "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0"
 | 
					    implementation "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0"
 | 
				
			||||||
    //general PDF
 | 
					    //general PDF
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,5 @@
 | 
				
			|||||||
package stirling.software.SPDF.EE;
 | 
					package stirling.software.SPDF.EE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import org.slf4j.Logger;
 | 
					 | 
				
			||||||
import org.slf4j.LoggerFactory;
 | 
					 | 
				
			||||||
import org.springframework.beans.factory.annotation.Autowired;
 | 
					import org.springframework.beans.factory.annotation.Autowired;
 | 
				
			||||||
import org.springframework.context.annotation.Bean;
 | 
					import org.springframework.context.annotation.Bean;
 | 
				
			||||||
import org.springframework.context.annotation.Configuration;
 | 
					import org.springframework.context.annotation.Configuration;
 | 
				
			||||||
@ -20,6 +18,6 @@ public class EEAppConfig {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    @Bean(name = "runningEE")
 | 
					    @Bean(name = "runningEE")
 | 
				
			||||||
    public boolean runningEnterpriseEdition() {
 | 
					    public boolean runningEnterpriseEdition() {
 | 
				
			||||||
    	return licenseKeyChecker.getEnterpriseEnabledResult();
 | 
					        return licenseKeyChecker.getEnterpriseEnabledResult();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -9,6 +9,7 @@ import org.springframework.core.annotation.Order;
 | 
				
			|||||||
import org.springframework.stereotype.Component;
 | 
					import org.springframework.stereotype.Component;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import io.micrometer.common.util.StringUtils;
 | 
					import io.micrometer.common.util.StringUtils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import jakarta.annotation.PostConstruct;
 | 
					import jakarta.annotation.PostConstruct;
 | 
				
			||||||
import lombok.extern.slf4j.Slf4j;
 | 
					import lombok.extern.slf4j.Slf4j;
 | 
				
			||||||
import stirling.software.SPDF.model.ApplicationProperties;
 | 
					import stirling.software.SPDF.model.ApplicationProperties;
 | 
				
			||||||
@ -59,7 +60,4 @@ public class InitialSetup {
 | 
				
			|||||||
            applicationProperties.getLegal().setPrivacyPolicy(defaultPrivacyUrl);
 | 
					            applicationProperties.getLegal().setPrivacyPolicy(defaultPrivacyUrl);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -203,7 +203,8 @@ public class SecurityConfiguration {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Handle SAML
 | 
					            // Handle SAML
 | 
				
			||||||
            if (applicationProperties.getSecurity().isSaml2Activ() && applicationProperties.getSystem().getEnableAlphaFunctionality()) {
 | 
					            if (applicationProperties.getSecurity().isSaml2Activ()
 | 
				
			||||||
 | 
					                    && applicationProperties.getSystem().getEnableAlphaFunctionality()) {
 | 
				
			||||||
                http.authenticationProvider(samlAuthenticationProvider());
 | 
					                http.authenticationProvider(samlAuthenticationProvider());
 | 
				
			||||||
                http.saml2Login(
 | 
					                http.saml2Login(
 | 
				
			||||||
                                saml2 ->
 | 
					                                saml2 ->
 | 
				
			||||||
 | 
				
			|||||||
@ -45,7 +45,6 @@ public class UserService implements UserServiceInterface {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    @Autowired DatabaseBackupInterface databaseBackupHelper;
 | 
					    @Autowired DatabaseBackupInterface databaseBackupHelper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Handle OAUTH2 login and user auto creation.
 | 
					    // Handle OAUTH2 login and user auto creation.
 | 
				
			||||||
    public boolean processOAuth2PostLogin(String username, boolean autoCreateUser)
 | 
					    public boolean processOAuth2PostLogin(String username, boolean autoCreateUser)
 | 
				
			||||||
            throws IllegalArgumentException, IOException {
 | 
					            throws IllegalArgumentException, IOException {
 | 
				
			||||||
@ -360,8 +359,8 @@ public class UserService implements UserServiceInterface {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@Override
 | 
					    @Override
 | 
				
			||||||
	public long getTotalUsersCount() {
 | 
					    public long getTotalUsersCount() {
 | 
				
			||||||
		return userRepository.count();
 | 
					        return userRepository.count();
 | 
				
			||||||
	}
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -29,12 +29,12 @@ public class PostHogService {
 | 
				
			|||||||
    private final ApplicationProperties applicationProperties;
 | 
					    private final ApplicationProperties applicationProperties;
 | 
				
			||||||
    private final UserServiceInterface userService;
 | 
					    private final UserServiceInterface userService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Autowired
 | 
					    @Autowired
 | 
				
			||||||
    public PostHogService(
 | 
					    public PostHogService(
 | 
				
			||||||
            PostHog postHog,
 | 
					            PostHog postHog,
 | 
				
			||||||
            @Qualifier("UUID") String uuid,
 | 
					            @Qualifier("UUID") String uuid,
 | 
				
			||||||
            ApplicationProperties applicationProperties, @Autowired(required = false) UserServiceInterface userService) {
 | 
					            ApplicationProperties applicationProperties,
 | 
				
			||||||
 | 
					            @Autowired(required = false) UserServiceInterface userService) {
 | 
				
			||||||
        this.postHog = postHog;
 | 
					        this.postHog = postHog;
 | 
				
			||||||
        this.uniqueId = uuid;
 | 
					        this.uniqueId = uuid;
 | 
				
			||||||
        this.applicationProperties = applicationProperties;
 | 
					        this.applicationProperties = applicationProperties;
 | 
				
			||||||
@ -138,9 +138,8 @@ public class PostHogService {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            metrics.put("application_properties", captureApplicationProperties());
 | 
					            metrics.put("application_properties", captureApplicationProperties());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            
 | 
					            if (userService != null) {
 | 
				
			||||||
            if(userService != null) {
 | 
					                metrics.put("total_users_created", userService.getTotalUsersCount());
 | 
				
			||||||
            	metrics.put("total_users_created", userService.getTotalUsersCount());
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        } catch (Exception e) {
 | 
					        } catch (Exception e) {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,30 +1,46 @@
 | 
				
			|||||||
package stirling.software.SPDF.utils;
 | 
					package stirling.software.SPDF.utils;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.awt.geom.AffineTransform;
 | 
				
			||||||
 | 
					import java.awt.image.AffineTransformOp;
 | 
				
			||||||
import java.awt.image.BufferedImage;
 | 
					import java.awt.image.BufferedImage;
 | 
				
			||||||
import java.awt.image.DataBuffer;
 | 
					import java.awt.image.DataBuffer;
 | 
				
			||||||
import java.awt.image.DataBufferByte;
 | 
					import java.awt.image.DataBufferByte;
 | 
				
			||||||
import java.awt.image.DataBufferInt;
 | 
					import java.awt.image.DataBufferInt;
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					import java.io.InputStream;
 | 
				
			||||||
import java.nio.ByteBuffer;
 | 
					import java.nio.ByteBuffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import javax.imageio.ImageIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					import org.springframework.web.multipart.MultipartFile;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.drew.imaging.ImageMetadataReader;
 | 
				
			||||||
 | 
					import com.drew.imaging.ImageProcessingException;
 | 
				
			||||||
 | 
					import com.drew.metadata.Metadata;
 | 
				
			||||||
 | 
					import com.drew.metadata.MetadataException;
 | 
				
			||||||
 | 
					import com.drew.metadata.exif.ExifSubIFDDirectory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class ImageProcessingUtils {
 | 
					public class ImageProcessingUtils {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static final Logger logger = LoggerFactory.getLogger(PdfUtils.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static BufferedImage convertColorType(BufferedImage sourceImage, String colorType) {
 | 
					    static BufferedImage convertColorType(BufferedImage sourceImage, String colorType) {
 | 
				
			||||||
        BufferedImage convertedImage;
 | 
					        BufferedImage convertedImage;
 | 
				
			||||||
        switch (colorType) {
 | 
					        switch (colorType) {
 | 
				
			||||||
            case "greyscale":
 | 
					            case "greyscale":
 | 
				
			||||||
                convertedImage =
 | 
					                convertedImage = new BufferedImage(
 | 
				
			||||||
                        new BufferedImage(
 | 
					                        sourceImage.getWidth(),
 | 
				
			||||||
                                sourceImage.getWidth(),
 | 
					                        sourceImage.getHeight(),
 | 
				
			||||||
                                sourceImage.getHeight(),
 | 
					                        BufferedImage.TYPE_BYTE_GRAY);
 | 
				
			||||||
                                BufferedImage.TYPE_BYTE_GRAY);
 | 
					 | 
				
			||||||
                convertedImage.getGraphics().drawImage(sourceImage, 0, 0, null);
 | 
					                convertedImage.getGraphics().drawImage(sourceImage, 0, 0, null);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case "blackwhite":
 | 
					            case "blackwhite":
 | 
				
			||||||
                convertedImage =
 | 
					                convertedImage = new BufferedImage(
 | 
				
			||||||
                        new BufferedImage(
 | 
					                        sourceImage.getWidth(),
 | 
				
			||||||
                                sourceImage.getWidth(),
 | 
					                        sourceImage.getHeight(),
 | 
				
			||||||
                                sourceImage.getHeight(),
 | 
					                        BufferedImage.TYPE_BYTE_BINARY);
 | 
				
			||||||
                                BufferedImage.TYPE_BYTE_BINARY);
 | 
					 | 
				
			||||||
                convertedImage.getGraphics().drawImage(sourceImage, 0, 0, null);
 | 
					                convertedImage.getGraphics().drawImage(sourceImage, 0, 0, null);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            default: // full color
 | 
					            default: // full color
 | 
				
			||||||
@ -59,4 +75,49 @@ public class ImageProcessingUtils {
 | 
				
			|||||||
            return data;
 | 
					            return data;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static double extractImageOrientation(InputStream is) throws IOException {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            Metadata metadata = ImageMetadataReader.readMetadata(is);
 | 
				
			||||||
 | 
					            ExifSubIFDDirectory directory = metadata.getFirstDirectoryOfType(ExifSubIFDDirectory.class);
 | 
				
			||||||
 | 
					            if (directory == null) {
 | 
				
			||||||
 | 
					                return 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            int orientationTag = directory.getInt(ExifSubIFDDirectory.TAG_ORIENTATION);
 | 
				
			||||||
 | 
					            switch (orientationTag) {
 | 
				
			||||||
 | 
					                case 1:
 | 
				
			||||||
 | 
					                    return 0;
 | 
				
			||||||
 | 
					                case 6:
 | 
				
			||||||
 | 
					                    return 90;
 | 
				
			||||||
 | 
					                case 3:
 | 
				
			||||||
 | 
					                    return 180;
 | 
				
			||||||
 | 
					                case 8:
 | 
				
			||||||
 | 
					                    return 270;
 | 
				
			||||||
 | 
					                default:
 | 
				
			||||||
 | 
					                    logger.warn("Unknown orientation tag: {}", orientationTag);
 | 
				
			||||||
 | 
					                    return 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } catch (ImageProcessingException | MetadataException e) {
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static BufferedImage applyOrientation(BufferedImage image, double orientation) {
 | 
				
			||||||
 | 
					        if (orientation == 0) {
 | 
				
			||||||
 | 
					            return image;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        AffineTransform transform = AffineTransform.getRotateInstance(
 | 
				
			||||||
 | 
					                Math.toRadians(orientation),
 | 
				
			||||||
 | 
					                image.getWidth() / 2.0,
 | 
				
			||||||
 | 
					                image.getHeight() / 2.0);
 | 
				
			||||||
 | 
					        AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
 | 
				
			||||||
 | 
					        return op.filter(image, null);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public static BufferedImage loadImageWithExifOrientation(MultipartFile file)
 | 
				
			||||||
 | 
					            throws IOException {
 | 
				
			||||||
 | 
					        BufferedImage image = ImageIO.read(file.getInputStream());
 | 
				
			||||||
 | 
					        double orientation = extractImageOrientation(file.getInputStream());
 | 
				
			||||||
 | 
					        return applyOrientation(image, orientation);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -194,7 +194,8 @@ public class PdfUtils {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        pdfDocument.close();
 | 
					        pdfDocument.close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Assumes the expectedPageSize is in the format "widthxheight", e.g. "595x842" for A4
 | 
					        // Assumes the expectedPageSize is in the format "widthxheight", e.g. "595x842"
 | 
				
			||||||
 | 
					        // for A4
 | 
				
			||||||
        String[] dimensions = expectedPageSize.split("x");
 | 
					        String[] dimensions = expectedPageSize.split("x");
 | 
				
			||||||
        float expectedPageWidth = Float.parseFloat(dimensions[0]);
 | 
					        float expectedPageWidth = Float.parseFloat(dimensions[0]);
 | 
				
			||||||
        float expectedPageHeight = Float.parseFloat(dimensions[1]);
 | 
					        float expectedPageHeight = Float.parseFloat(dimensions[1]);
 | 
				
			||||||
@ -407,7 +408,7 @@ public class PdfUtils {
 | 
				
			|||||||
                        addImageToDocument(doc, pdImage, fitOption, autoRotate);
 | 
					                        addImageToDocument(doc, pdImage, fitOption, autoRotate);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    BufferedImage image = ImageIO.read(file.getInputStream());
 | 
					                    BufferedImage image = ImageProcessingUtils.loadImageWithExifOrientation(file);
 | 
				
			||||||
                    BufferedImage convertedImage =
 | 
					                    BufferedImage convertedImage =
 | 
				
			||||||
                            ImageProcessingUtils.convertColorType(image, colorType);
 | 
					                            ImageProcessingUtils.convertColorType(image, colorType);
 | 
				
			||||||
                    // Use JPEGFactory if it's JPEG since JPEG is lossy
 | 
					                    // Use JPEGFactory if it's JPEG since JPEG is lossy
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user