mirror of
				https://github.com/Frooodle/Stirling-PDF.git
				synced 2025-10-25 11:17:28 +02: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-xwd:$imageioVersion" | ||||
| 
 | ||||
|     // Image metadata extractor | ||||
|     implementation "com.drewnoakes:metadata-extractor:2.19.0" | ||||
| 
 | ||||
|     implementation "commons-io:commons-io:2.17.0" | ||||
|     implementation "org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0" | ||||
|     //general PDF | ||||
|  | ||||
| @ -1,7 +1,5 @@ | ||||
| package stirling.software.SPDF.EE; | ||||
| 
 | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.context.annotation.Bean; | ||||
| import org.springframework.context.annotation.Configuration; | ||||
| @ -20,6 +18,6 @@ public class EEAppConfig { | ||||
| 
 | ||||
|     @Bean(name = "runningEE") | ||||
|     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 io.micrometer.common.util.StringUtils; | ||||
| 
 | ||||
| import jakarta.annotation.PostConstruct; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import stirling.software.SPDF.model.ApplicationProperties; | ||||
| @ -59,7 +60,4 @@ public class InitialSetup { | ||||
|             applicationProperties.getLegal().setPrivacyPolicy(defaultPrivacyUrl); | ||||
|         } | ||||
|     } | ||||
|      | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -203,7 +203,8 @@ public class SecurityConfiguration { | ||||
|             } | ||||
| 
 | ||||
|             // Handle SAML | ||||
|             if (applicationProperties.getSecurity().isSaml2Activ() && applicationProperties.getSystem().getEnableAlphaFunctionality()) { | ||||
|             if (applicationProperties.getSecurity().isSaml2Activ() | ||||
|                     && applicationProperties.getSystem().getEnableAlphaFunctionality()) { | ||||
|                 http.authenticationProvider(samlAuthenticationProvider()); | ||||
|                 http.saml2Login( | ||||
|                                 saml2 -> | ||||
|  | ||||
| @ -45,7 +45,6 @@ public class UserService implements UserServiceInterface { | ||||
| 
 | ||||
|     @Autowired DatabaseBackupInterface databaseBackupHelper; | ||||
| 
 | ||||
| 
 | ||||
|     // Handle OAUTH2 login and user auto creation. | ||||
|     public boolean processOAuth2PostLogin(String username, boolean autoCreateUser) | ||||
|             throws IllegalArgumentException, IOException { | ||||
| @ -360,8 +359,8 @@ public class UserService implements UserServiceInterface { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 	@Override | ||||
| 	public long getTotalUsersCount() { | ||||
| 		return userRepository.count(); | ||||
| 	} | ||||
|     @Override | ||||
|     public long getTotalUsersCount() { | ||||
|         return userRepository.count(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -29,12 +29,12 @@ public class PostHogService { | ||||
|     private final ApplicationProperties applicationProperties; | ||||
|     private final UserServiceInterface userService; | ||||
| 
 | ||||
| 
 | ||||
|     @Autowired | ||||
|     public PostHogService( | ||||
|             PostHog postHog, | ||||
|             @Qualifier("UUID") String uuid, | ||||
|             ApplicationProperties applicationProperties, @Autowired(required = false) UserServiceInterface userService) { | ||||
|             ApplicationProperties applicationProperties, | ||||
|             @Autowired(required = false) UserServiceInterface userService) { | ||||
|         this.postHog = postHog; | ||||
|         this.uniqueId = uuid; | ||||
|         this.applicationProperties = applicationProperties; | ||||
| @ -138,9 +138,8 @@ public class PostHogService { | ||||
|             } | ||||
|             metrics.put("application_properties", captureApplicationProperties()); | ||||
| 
 | ||||
|              | ||||
|             if(userService != null) { | ||||
|             	metrics.put("total_users_created", userService.getTotalUsersCount()); | ||||
|             if (userService != null) { | ||||
|                 metrics.put("total_users_created", userService.getTotalUsersCount()); | ||||
|             } | ||||
| 
 | ||||
|         } catch (Exception e) { | ||||
|  | ||||
| @ -1,30 +1,46 @@ | ||||
| package stirling.software.SPDF.utils; | ||||
| 
 | ||||
| import java.awt.geom.AffineTransform; | ||||
| import java.awt.image.AffineTransformOp; | ||||
| import java.awt.image.BufferedImage; | ||||
| import java.awt.image.DataBuffer; | ||||
| import java.awt.image.DataBufferByte; | ||||
| import java.awt.image.DataBufferInt; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| 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 { | ||||
| 
 | ||||
|     private static final Logger logger = LoggerFactory.getLogger(PdfUtils.class); | ||||
| 
 | ||||
|     static BufferedImage convertColorType(BufferedImage sourceImage, String colorType) { | ||||
|         BufferedImage convertedImage; | ||||
|         switch (colorType) { | ||||
|             case "greyscale": | ||||
|                 convertedImage = | ||||
|                         new BufferedImage( | ||||
|                                 sourceImage.getWidth(), | ||||
|                                 sourceImage.getHeight(), | ||||
|                                 BufferedImage.TYPE_BYTE_GRAY); | ||||
|                 convertedImage = new BufferedImage( | ||||
|                         sourceImage.getWidth(), | ||||
|                         sourceImage.getHeight(), | ||||
|                         BufferedImage.TYPE_BYTE_GRAY); | ||||
|                 convertedImage.getGraphics().drawImage(sourceImage, 0, 0, null); | ||||
|                 break; | ||||
|             case "blackwhite": | ||||
|                 convertedImage = | ||||
|                         new BufferedImage( | ||||
|                                 sourceImage.getWidth(), | ||||
|                                 sourceImage.getHeight(), | ||||
|                                 BufferedImage.TYPE_BYTE_BINARY); | ||||
|                 convertedImage = new BufferedImage( | ||||
|                         sourceImage.getWidth(), | ||||
|                         sourceImage.getHeight(), | ||||
|                         BufferedImage.TYPE_BYTE_BINARY); | ||||
|                 convertedImage.getGraphics().drawImage(sourceImage, 0, 0, null); | ||||
|                 break; | ||||
|             default: // full color | ||||
| @ -59,4 +75,49 @@ public class ImageProcessingUtils { | ||||
|             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(); | ||||
| 
 | ||||
|         // 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"); | ||||
|         float expectedPageWidth = Float.parseFloat(dimensions[0]); | ||||
|         float expectedPageHeight = Float.parseFloat(dimensions[1]); | ||||
| @ -407,7 +408,7 @@ public class PdfUtils { | ||||
|                         addImageToDocument(doc, pdImage, fitOption, autoRotate); | ||||
|                     } | ||||
|                 } else { | ||||
|                     BufferedImage image = ImageIO.read(file.getInputStream()); | ||||
|                     BufferedImage image = ImageProcessingUtils.loadImageWithExifOrientation(file); | ||||
|                     BufferedImage convertedImage = | ||||
|                             ImageProcessingUtils.convertColorType(image, colorType); | ||||
|                     // Use JPEGFactory if it's JPEG since JPEG is lossy | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user