The best way to load pictures for photo gallery - java

I want to make some kind of a book(or some kind of a photo gallery) using jpg files of a scanned book.
the user gives the number of the page that he wants to go to , and clicks on the button to
see the page .
I need to know what is the best way to load the pictures.
i'm thinking of doing this for each page:
private ImageIcon image1= new ImageIcon ("1.jpg");
private ImageIcon image2 = new ImageIcon ("2.jpg");
....
and then put the pictures in an array and so on ...
but i got over 500 pictures and it is tedious to load pages like that .
so is there any other way?

Well, I can say the best way would be lazy loading plus pre-caching.
Lazy loading means you load the image only when the user needs it. For example:
img = 56; // suppose the user want to see page 56
if(images[img] != null) { // images is an array with the images
images[img] = new ImageIcon (img + ".jpg");
}
Besides, you can guest that when the user see a page they will see the next ones (pre-caching). So you can also load the following X pages.
PRELOAD = 10; // number of pages to preload
img = 56;
for(int i = 0; i < PRELOAD; i++) {
if(images[img+i] != null) {
images[img+i] = new ImageIcon ((img + i) + ".jpg");
}
}
Besides, it's you may think that in the beginning the user will always look at the firsts pages. So you can pre-load the first X pages in the start of your program.

Related

GridView only create Images when they would be visible

Hei there
So I have the following problem. I have around 1500 images of playing cards. I want to display them in a "Gallery" where you could scroll through them. I was able to create a GridView with the ImageCell object and I was also able to add images to it. Now my problem is that if I add all Image's at once logically Java crashes because of a heap error. I have the image url's (local files) in a list. How could I implement that it only load lets say 15 images. If I then scroll it loads the next 15 and unloads the old ones. So it would only load the images of the actual visible images and not all 1500. How would I do this? I am completely out of ideas.
The Platform.runLater() is needed because some sort of issue with ControlsFX
Here my code:
public void initialize() {
GridView<Image> gridView = new GridView<>();
gridView.setCellFactory(gridView1 -> new ImageGridCell(true));
Image image = new Image("C:\\Users\\nijog\\Downloads\\cardpictures\\01DE001.png");
gridView.setCellWidth(340);
gridView.setCellHeight(512);
//Platform.runLater(()-> {
// for (int i = 0; i < 5000; i++){
// gridView.getItems().add(image);
// }
//});
Platform.runLater(() -> gridView.getItems().addAll(createImageListFromCardFiles()));
borderPane.setCenter(gridView);
}
protected List<Image> createImageListFromCardFiles(){
List<Image> imageViewList = new ArrayList<>();
App.getCardService().getCardArray().stream()
//.filter(Card::isCollectible)
.sorted(Comparator.comparingInt(Card::getCost))
.sorted(Comparator.comparing(Card::isChampion).reversed())
.skip(0)
//.limit(100)
.forEach(card -> {
try {
String url = String.format(App.pictureFolderPath +"%s.png", card.getCardCode());
imageViewList.add(new Image(url));
} catch (Exception e) {
System.out.println("Picture file not found [CardCode = " + card.getCardCode() + "]");
App.logger.writeLog(Logger.Operation.EXCEPTION, "Picture file not found [CardCode = " + card.getCardCode() + "]");
}
});
return imageViewList;
}
You might not need to use the strategy you describe. You're displaying the images in cells of size 340x512, which is 174,080 pixels. Image storage is 4 bytes per pixel, so this is 696,320 bytes per image; 1500 of them will consume about 1GB. You just need to make sure you load the image at the size you are displaying it (instead of its native size):
// imageViewList.add(new Image(url));
imageViewList.add(new Image(url, 340, 512, true, true, true));
If you need an image at full size later (e.g. if you want the user to select an image from your grid view and display it in a bigger pane), you'd just need to reload it from the url.
If you do need to implement the strategy you describe, GridView supports that out of the box. Just keep a list of the URLs, instead of the Images, and use a custom GridCell to load the image as needed. This will consume significantly less memory, at the cost of a lot more I/O (loading the images) and CPU (parsing the image format).
Make the items for the GridView the image urls, stored as Strings.
Then you can do something like:
GridView<String> gridView = new GridView<>();
gridView.getItems().addAll(getAllImageURLs());
gridView.setCellFactory(gv -> new GridCell<>() {
private final ImageView imageView = new ImageView();
{
imageView.fitWidthProperty().bind(widthProperty());
imageView.fitHeightProperty().bind(heightProperty());
imageView.setPreserveRatio(true);
}
#Override
protected void updateItem(String url, boolean empty) {
super.updateItem(url, empty);
if (empty || url == null) {
setGraphic(null);
} else {
double w = getGridView().getCellWidth();
double h = getGridView().getCellHeight();
imageView.setImage(new Image(url, w, h, true, true, true));
setGraphic(imageView);
}
}
});
protected List<String> getAllImageURLs(){
return App.getCardService().getCardArray().stream()
// isn't the first sort redundant here?
.sorted(Comparator.comparingInt(Card::getCost))
.sorted(Comparator.comparing(Card::isChampion).reversed())
.map(card -> String.format(App.pictureFolderPath +"%s.png", card.getCardCode()))
.collect(Collectors.toList());
}

How to crop the image within a print screen?

I am developing an application that chooses an image of a wound and displays it on the application screen. with this, the user marks the region of interest of the wound, so that later the algorithm can recognize and process the region of interest. I'm doing this using the lib implementation 'com.github.gcacace: signature-pad: 1.2.1' to demarcate the region and then I'm saving the screen's "printscreen" so I can save the markup along with the image of the wound.
How I wish the image will look
Exit:
However, I want to cut the printscreen according to the image of the wound to send to the server to process the image. Can someone help me cut out the wound image after marking.
private fun saveImage(myBitmap: Bitmap?): String? {
try {
// image naming and path to include sd card appending name you choose for file
val mPath = Environment.getExternalStorageDirectory().toString() + "/imagesignature.jpg"
// create bitmap screen capture
val v1 = window.decorView.rootView
v1.isDrawingCacheEnabled = true
val bitmap = Bitmap.createBitmap(v1.drawingCache)
v1.isDrawingCacheEnabled = false
val imageFile = File(mPath)
val outputStream = FileOutputStream(imageFile)
val quality = 100
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream)
outputStream.flush()
outputStream.close()
//setting screenshot in imageview
val filePath = imageFile.path
val ssbitmap = BitmapFactory.decodeFile(imageFile.absolutePath)
imagem.setImageBitmap(ssbitmap)
} catch (e: Throwable) {
// Several error may come out with file handling or DOM
e.printStackTrace()
}
return ""
}
I am still a learner so for an easy way to crop an image I would suggest using this library:
https://github.com/ArthurHub/Android-Image-Cropper
This is where you can crop the image as per your requirement and store the image on the server
If you have the coordinates of the rectangle you want to save:
Bitmap croppedBmp = Bitmap.createBitmap(originalBmp, rectanglePositionX, rectanglePositionY, rectangleWidth, rectangleHeight);
Or you can try:
BitmapFactory.decodeStream(InputStream is, Rect outPadding, Options opts)
or
BitmapFactory.decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts)
where in the Rect outPadding you will set the coordinates of the rectangle you want to save.
As far as I know, I don't think it's possible to crop and image. In order to crop, you need to find the dimensions for the part that you want. I don't think you can tell the program the dimensions of what you want and then crop everything else off, as far as my knowledge goes. It might be possible to print an image, but I don't think Java can crop. Other coding programs might work better for this.

Keep dimension of new image when replacing old image using docx4j

I need to add an image to my docx file. The image is a png image of a signature that is to placed behind text in the signature line of a certificate to be downloaded by the user as a docx, a pdf or jpg. The first problem I encountered is that you can only add inline image using the latest version of docx4j (v6.1.2) and creating an image Anchor is currently disabled (see BinaryPartAbstractImage.java: line 1029). That's a problem since the signature image is not inline, it supposed to appear behind the name on the signature line. Instead of inserting one myself, my workaround is to place a placeholder image:
These images are mapped as image1.png and image2.png, respectively, on /word/media directory of the docx uncompressed version. The program then replaces these with the name, position, and actual png of the signature every time a certificate is generated.
The problem is that the images are scaled the same dimension as the placeholder image, where in fact it should look like this:
How can I get to keep the image dimension of the image after replacing, or at least the aspect ratio? Here is how I replace the placeholder image with the new image:
File approveBySignatureImage = new File(...);
final String approvedByImageNodeId = "rId5";
replaceImageById(approvedByImageNodeId,
"image1.png", approveBySignatureImage);
This is the actual method where the replacing happens:
public void replaceImageById(String id, String placeholderImageName, File newImage) throws Exception {
Relationship rel = document.getMainDocumentPart().getRelationshipsPart().getRelationshipByID(id);
BinaryPartAbstractImage imagePart;
if(FilenameUtils.getExtension(placeholderImageName).toLowerCase() == ContentTypes.EXTENSION_BMP) {
imagePart = new ImageBmpPart(new PartName("/word/media/" + placeholderImageName));
}
else if([ContentTypes.EXTENSION_JPG_1, ContentTypes.EXTENSION_JPG_2].contains(FilenameUtils.getExtension(placeholderImageName).toLowerCase())) {
imagePart = new ImageJpegPart(new PartName("/word/media/" + placeholderImageName));
}
else if(FilenameUtils.getExtension(placeholderImageName).toLowerCase() == ContentTypes.EXTENSION_PNG) {
imagePart = new ImagePngPart(new PartName("/word/media/" + placeholderImageName));
}
InputStream stream = new FileInputStream(newImage);
imagePart.setBinaryData(stream);
if(FilenameUtils.getExtension(newImage.getName()).toLowerCase() == ContentTypes.EXTENSION_BMP) {
imagePart.setContentType(new ContentType(ContentTypes.IMAGE_BMP));
}
else if([ContentTypes.EXTENSION_JPG_1, ContentTypes.EXTENSION_JPG_2].contains(FilenameUtils.getExtension(newImage.getName()).toLowerCase())) {
imagePart.setContentType(new ContentType(ContentTypes.IMAGE_JPEG));
}
else if(FilenameUtils.getExtension(newImage.getName()).toLowerCase() == ContentTypes.EXTENSION_PNG) {
imagePart.setContentType(new ContentType(ContentTypes.IMAGE_PNG));
}
imagePart.setRelationshipType(Namespaces.IMAGE);
final String embedId = rel.getId();
rel = document.getMainDocumentPart().addTargetPart(imagePart);
rel.setId(embedId);
}
You'll need to set the dimensions (or possibly just remove what you have?) on your placeholder image.
For help in doing that:-
docx4j inspects the image to work that out at https://github.com/plutext/docx4j/blob/master/src/main/java/org/docx4j/openpackaging/parts/WordprocessingML/BinaryPartAbstractImage.java#L512 using org.apache.xmlgraphics ImageInfo.
See also CxCy:https://github.com/plutext/docx4j/blob/master/src/main/java/org/docx4j/openpackaging/parts/WordprocessingML/BinaryPartAbstractImage.java#L1164
https://github.com/plutext/docx4j/blob/master/src/main/java/org/docx4j/openpackaging/parts/WordprocessingML/BinaryPartAbstractImage.java#L815 shows scaling to maintain aspect ratio.

Java : Determine if String is an URL(without www or http), take its screenshot

I am working on a Spring-MVC webapplication in which we are trying to get a screenshot of an URL. Currently I am using PhantomJS for that task, but it's too slow(>10seconds). Also, the URL's have to be with http/https and www for detecting that it's an URL. As this is a chat application, there can be simple URL's which users add like helloworld.com. Any help would be nice. Thank you.
Code:
String[] words = message.split(" ");
for( String item : words ){
boolean val = ResourceUtils.isUrl(item);
if(val){
urlIdentifier = calcUrl(item);
break;
}else {
System.out.println("Url false is "+item);
}
}
if(urlIdentifier!=null){
replies.setPreviewIdentifier(urlIdentifier);
input.put("preview_identifier",urlIdentifier);
}
Method to calculate screenshot :
private String calcUrl(String website){
try {
String identifier = String.valueOf(new BigInteger(130, random).toString(32));
String previewLocation = msg + "chatthumbs/" + identifier ;
Process proc = Runtime.getRuntime().exec("phantomjs --ssl-protocol=any " +
"/home/deploy/phantom/rasterizepdf.js " +" "+website+" " +previewLocation);
proc.waitFor();
BufferedImage image = ImageIO.read(new File("/home/akshay/testme.png"));
if(image!=null){
if (image.getWidth() > image.getHeight()) {
image = Scalr.resize(image, Scalr.Mode.FIT_TO_HEIGHT, 250, 250);
} else {
image = Scalr.resize(image, Scalr.Mode.FIT_TO_WIDTH, 250, 250);
}
image = Scalr.crop(image, 250, 250);
ImageIO.write(image, "png", new File(previewLocation));
}
return identifier;
}catch (Exception e){
e.printStackTrace();
}
return null;
}
Any help would be nice. Thank you.
(a) I think the process of taking a screen shot is taking time. Is this code running on the same device as the chat screen? Why not use java.awt.Robot to take the screen shot ? or just save the text why do you need a screen shot?
(b) Is the system too busy/ Use on a SSD to see if faster?
(c) But curious as to the end application, is this part of a web app? How will your code run on the client systems? Or will you java agent be installed on all user systems that monitors the web page and takes screen shots? Then why use a web page, use a java app to chat, and parse the text as typed.
Parsing the text. What if user types/ pastes a long message? Are you parsing everything once or on change? Think of ways to improve that if it seems to be a problem. Ignore if not the immediate issue now.
Also if the msg is too long the parsing can take a lot of time. maybe process after every key press or change event (if paste) keep local js copy of previous text to get diff?

IE caches and references old images for h:graphicImage

I have an web application that uses JSF for form submission. I have a user select an image from a list followed by filling out and submitting a form. I then use the selected image and form input to annotate the image with the information. I then process a pdf file using the annotated images and email it to the user. After processing, I give the user the option to navigate back to the image selection page, or use the same images and go back to the form. Here is the jsf/html for the form that allows the user to navigate to their new page:
<h:form id="form" method="post">
<div>
<h:commandButton value="images" action="#{artwork.backToArt}"/>
</div>
<div>
<h:commandButton value="Form" action="#{artwork.backToForm}"/>
</div>
<div>
<h:commandButton value="Upload" action="#{artwork.backToUpload}"/>
</div>
</h:form>
It seems that IE caches the annotated images and keeps those images on display regardless of my method calls.
Here are my methods:
public String backToArt()
{
log.info("========= Setting back to art page ==========");
this.backToForm();
this.selectedValue = "";
this.resizedArt = "";
this.backArt = "";
return "loginSuccess.xhtml";
}
public String backToUpload()
{ log.info("========= Setting back to upload ==========");
this.backToForm();
this.selectedValue = "";
this.resizedArt = "";
this.backArt = "";
return "CSVSubmit.xhtml";
}
public String backToForm()
{
log.info("============ Reseting all variables ==========");
String temp = null;
if (this.selectedValue != null)
{
temp = this.selectedValue;
temp=temp.substring(temp.lastIndexOf(Dir.getDir("\\")) + 1, temp.length() - 4);
this.selectedValue = temp;
}
log.info("Setting input variables");
//set all previous values to blank
//this.jobNum = "";
this.quantity = null;
this.headLine = null;
this.codeNum = null;
this.pass = null;
this.expir = null;
this.website = null;
log.info("Setting front art to old image");
//setting previous images to non-text
if (temp.length() > 0)
{
temp = this.resizedArt;
temp = "converted" + temp.substring(temp.lastIndexOf(Dir.getDir("\\")),temp.length() - 8)
+ ".jpg";
this.resizedArt=temp;
log.info("Setting back art to old image");
temp = this.backArt;
temp = "converted" + temp.substring(temp.lastIndexOf(Dir.getDir("\\")),temp.length() - 8)
+ ".jpg";
this.backArt = temp;
log.info("Deleting old text images");
//start to delete text images
File folderOne = new File(Env.textDestOne);
this.deleteFiles(folderOne);
File folderTwo = new File(Env.textDestTwo);
this.deleteFiles(folderTwo);
}
log.info("============ Reset Complete ==========");
return "FormSubmission.xhtml";
}
These methods reset the input variables and the images selected as well as deletes my annotated images depending on which button is pressed on that page. Looking at my logging, the methods are called and are processed, but no updating occurs for the images. When I process my pdf, the correct images and input are outputed, but what is viewed still shows old values. This means that my values are being stored properly and my methods are being called correctly. When I go to cancel and reprocess using Google Chrome, the images are updated properly.
Using all of this information, I have concluded that IE must be caching my images and not updating them with the correct values. I'm not sure how to override this, but I need to somehow clear the cache so that the images are updated to the correct values.
Edit: I noticed that when I refresh the page hitting F5, the pictures would update. Not sure what this means.

Categories

Resources