This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 4 years ago.
So i am making this Lending Library program and everything seems to work fine except when deleting the last item in my listview, i have looked over it for about 3 hours now and cannot figure it out! for some reason it only does it when i delete that last item. please help, here is my code.
LendingLibraryGUI
import java.io.IOException;
import javafx.application.*;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.stage.Stage;
public class LendingLibraryGUI extends Application {
LendingLibrary LendingLibrary = new LendingLibrary(); //Creating an Object to access total numbers of items
MediaItems Media = new MediaItems(); // creating an array of object to access MediaItems class and allowing it to hold 100 items
private ListView<String> library = new ListView<String>(); //Creates Listview
ObservableList<String> libraryList = FXCollections.<String>observableArrayList(); //Creates a list to use in the Listview
#Override
public void start(Stage primaryStage) throws Exception {
BorderPane display = new BorderPane(); //Main display
GridPane buttons = new GridPane(); //location to display buttons
TextField outPut = new TextField(); //Text field to show inventory
Insets padding = new Insets(10); //creates Insets for padding
buttons.setPadding(padding); //padding around grid pane
buttons.setHgap(10); //Horizontal gap
libraryList = LendingLibrary.load(); //Loads contents from a txt file back into the listview
library.setItems(libraryList); //inputs list of data into the listview
for (int i =0; i !=4;i++) { //Loop to create Buttons
String[] actionButtons = {"Add","Check Out","Check In","Delete"};//String to store Button names
Button temp = new Button(actionButtons[i]); //creates a temp button
temp.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE); //sets the size of buttons
buttons.add(temp, i, 0); //add buttons to grid pane
GridPane.setHgrow(temp, Priority.ALWAYS);
GridPane.setVgrow(temp, Priority.ALWAYS);
if (temp.getText().equals("Add")) { //if add button is pushed
temp.setOnAction((e) -> {
try {
add();
} catch (IOException e1) {
e1.printStackTrace();
}
});
}
else if (temp.getText().equals("Delete")) { //if delete button is pushed
library.getSelectionModel().selectedItemProperty().addListener(ov -> { //gets the selected item from the listview
temp.setOnAction((e) -> {
if(libraryList.isEmpty()) {
}
else {
try {
deleteLibrary();
} catch (IOException e1) {
e1.printStackTrace();
}
}
});
});
}
else if (temp.getText().equals("Check Out")){ //if check out button is pushed
library.getSelectionModel().selectedItemProperty().addListener(ov -> { //gets the selected item from the listview
String name = library.getSelectionModel().getSelectedItem().toString(); //stores selected listview data into a string
temp.setOnAction((e) -> { { // when checkout button is pushed
if (name.contains(" is currently on loaned to ")) {
errorMessage("Currently on Loan");
}
else {
inputGUI("Who did you loan this to?");
}
}
});
});
}
else if (temp.getText().equals("Check In")) {
library.getSelectionModel().selectedItemProperty().addListener(ov -> { //gets the selected item from the listview
String name = library.getSelectionModel().getSelectedItem().toString(); //stores selected listview data into a string
temp.setOnAction((e) -> { { // when checkout button is pushed
if (!name.contains(" is currently on loaned to ")) { //Catch if the item is not on loan
errorMessage("Not on Loan");
}
else {
try {
checkIn();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
});
});
}
}
outPut.setEditable(false); //no editing
outPut.setFont(Font.font("monospace", FontWeight.BOLD, 20)); //sets fonts
outPut.setMinHeight(300);//sets minimum height
display.setTop(library); //sets output in display on top
display.setCenter(buttons); //sets buttons on center
Scene scene = new Scene(display); //creates new scene
primaryStage.setTitle("Lending Library"); //sets title of GUI
primaryStage.setScene(scene); //adds scene to GUI
primaryStage.setMinHeight(500); //Minimum height
primaryStage.setMinWidth(400);//Minimum Width
primaryStage.show();//Displays GUI to user
}
public static void main(String[] args) {
launch(args);
}
private void add() throws IOException { //adding items to the library
inputGUI("Title:"); //input method
try {
LendingLibrary.Save(library); //updates save of media
} catch (IOException e1) {
e1.printStackTrace();
}
}
private void inputGUI(String input) { //input method to put information into the list
Stage secondaryStage = new Stage();
BorderPane border = new BorderPane();
VBox titlePane = new VBox(8);
HBox buttonLayout = new HBox(8);
Label lblTitle = new Label(input);
Button save = new Button("Save");
Button close = new Button("Close");
Insets padding = new Insets(10);
TextField txt = new TextField("");
close.setOnAction((e) -> secondaryStage.close());; //close button closes secondary stage
save.setOnAction(new EventHandler<ActionEvent>() { //Save button to save information
#Override
public void handle(ActionEvent e) {
if (txt.getText().trim().isEmpty()) { //if text field is empty do nothing
errorMessage("Please Enter Data into the text area"); //tells user to enter data in text field
}
else {
if (input.equals("Title:")) { //gets the title of media
Media.setTitle(txt.getText()); //sets title of media
secondaryStage.close();
inputGUI("Format:"); //calls inputGUI to get format of media
}
else if (input.equals("Format:")) { //gets the format of media
Media.setFormat(txt.getText()); //sets format of media
secondaryStage.close();
addToLibrary(); //adds media to library
}
else if (input.equals("Who did you loan this to?")) { //gets information on who borrowed the media
Media.setLoan(txt.getText()); //sets loaned out
secondaryStage.close();
inputGUI("When did you loan it(date)?"); //gets date when media was borrowed
}
else if (input.equals("When did you loan it(date)?")) { //gets date when media was borrowed
Media.setDate(txt.getText());//sets date when media was borrowed
secondaryStage.close();
checkOut(); //checks out media from library
}
}
try {
LendingLibrary.Save(library); //updates save of media
} catch (IOException e1) {
e1.printStackTrace();
}
}
});
buttonLayout.getChildren().addAll(close,save);
titlePane.setPadding(padding);
titlePane.getChildren().addAll(lblTitle,txt,buttonLayout);
border.setCenter(titlePane);
BorderPane.setAlignment(titlePane, Pos.CENTER);
Scene scene = new Scene(border); //creates new scene
secondaryStage.setTitle("Input"); //sets title of GUI
secondaryStage.setScene(scene); //adds scene to GUI
secondaryStage.setMinHeight(200); //Minimum height
secondaryStage.setMinWidth(350);//Minimum Width
secondaryStage.setMaxHeight(200); //Minimum height
secondaryStage.setMaxWidth(350);//Minimum Width
secondaryStage.show();//Displays GUI to user
}
private void addToLibrary() { //adding media to library
String total; //string to hold name and format of media
total = Media.getTitle();
total = total + " ("+ Media.getFormat() +")";
libraryList.add(total); //adds media to list
library.setItems(libraryList); //adds list to library
}
private void deleteLibrary() throws IOException { //deletes media from library
int selectedItem = library.getSelectionModel().getSelectedIndex(); //gets selected item in library list
libraryList.remove(selectedItem); //removes media from list
LendingLibrary.Save(library); //updates save of media
}
private void checkOut(){ //checkout method for media
String name = library.getSelectionModel().getSelectedItem().toString(); //grabs name of media selected
int selectedItem = library.getSelectionModel().getSelectedIndex(); //grabs location of media in list
libraryList.remove(selectedItem); //removes selected media
libraryList.add(name + " | is currently on loaned to " + Media.getLoan() + " on " + Media.getDate()); //add media back to list
}
private void checkIn() throws IOException { //check in method for media
String temp = library.getSelectionModel().getSelectedItem().toString(); //grabs name of media selected
String data = temp.substring(temp.indexOf("|") -1); //splits data up
temp = temp.replace(data, ""); //removes checked out
int selectedItem = library.getSelectionModel().getSelectedIndex(); //grabs location of media
libraryList.remove(selectedItem); //removes media
libraryList.add(temp); //adds data back in
try {
LendingLibrary.Save(library); //updates save of media
} catch (IOException e1) {
e1.printStackTrace();
}
}
private void errorMessage(String message) { //displays error messages
Stage errorStage = new Stage();
BorderPane border = new BorderPane();
VBox titlePane = new VBox(8);
HBox buttonLayout = new HBox(8);
Label lblTitle = new Label(message); //displays reason of error
Button close = new Button("Close");
Insets padding = new Insets(10);
close.setOnAction((e) -> errorStage.close());;
buttonLayout.getChildren().addAll(close);
buttonLayout.setAlignment(Pos.CENTER);
titlePane.setPadding(padding);
titlePane.getChildren().addAll(lblTitle,buttonLayout);
titlePane.setAlignment(Pos.CENTER);
border.setCenter(titlePane);
BorderPane.setAlignment(titlePane, Pos.CENTER);
Scene scene = new Scene(border); //creates new scene
errorStage.setTitle("Error"); //sets title of GUI
errorStage.setScene(scene); //adds scene to GUI
errorStage.setMinHeight(200); //Minimum height
errorStage.setMinWidth(350);//Minimum Width
errorStage.setMaxHeight(200); //Minimum height
errorStage.setMaxWidth(350);//Minimum Width
errorStage.show();//Displays GUI to user
}
}
LendingLibrary
import java.io.*;
import java.util.*;
import java.util.stream.Collectors;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.ListView;
public class LendingLibrary{
public void Save(ListView<String> library) throws IOException { //saves library as text file
String joined = library.getItems().stream()
.map(Object::toString)
.collect(Collectors.joining(", "));
File file = new File("LendingLibrary.txt");//Creates the text file Calc
file.createNewFile(); //if file doesnt exist it will create it (if it does nothing will happen)
if(file.exists()) { //if the file exists
PrintWriter output = new PrintWriter(file);
output.println(joined);
if(!file.exists()) { //if file doesn't exist
System.out.println("Error creating file");
}
output.close();
}
}
#SuppressWarnings("resource")
public ObservableList<String> load() throws FileNotFoundException { //loads information into program
ObservableList<String> libraryList = FXCollections.<String>observableArrayList(); //creates a list
File file = new File ("LendingLibrary.txt"); //access the file
if(file.exists()) { //if file does exist
Scanner input = new Scanner(file);
input.useDelimiter(","); //Separates data by a comma
while (input.hasNext()) { //while the list has data
String temp = input.next(); //stores data into a string
temp = temp.trim(); //trims spaces from beginning of data
if (temp.equals("")) {
}
else {
libraryList.addAll(temp); //stores data into the list
}
}
}
else if(!file.exists()) { //if does not file exist
}
return libraryList; //returns list to use in the listview
}
}
MediaItems
public class MediaItems {
private String title;
private String format;
private String loanedTo;
private String dateLoaned;
public void setTitle(String name) {title = name;}
public void setFormat(String type) {format = type;}
public String getTitle() {return title;}
public String getFormat() {return format;}
public void setLoan(String loaned) {loanedTo = loaned;}
public String getLoan() {return loanedTo; }
public void setDate(String date) {dateLoaned = date;}
public String getDate() {return dateLoaned;}
}
Not sure if it matters but here is the exception it throws, it doesnt actually crash the program or anything just an error it throws when i delete the last item...
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at LendingLibraryGUI.lambda$3(LendingLibraryGUI.java:85)
at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:349)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.ReadOnlyObjectPropertyBase.fireValueChangedEvent(ReadOnlyObjectPropertyBase.java:74)
at javafx.beans.property.ReadOnlyObjectWrapper.fireValueChangedEvent(ReadOnlyObjectWrapper.java:102)
at javafx.beans.property.ObjectPropertyBase.markInvalid(ObjectPropertyBase.java:112)
at javafx.beans.property.ObjectPropertyBase.set(ObjectPropertyBase.java:146)
at javafx.scene.control.SelectionModel.setSelectedItem(SelectionModel.java:102)
at javafx.scene.control.MultipleSelectionModelBase.lambda$new$34(MultipleSelectionModelBase.java:67)
at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:137)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.ReadOnlyIntegerPropertyBase.fireValueChangedEvent(ReadOnlyIntegerPropertyBase.java:72)
at javafx.beans.property.ReadOnlyIntegerWrapper.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:102)
at javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:113)
at javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:147)
at javafx.scene.control.SelectionModel.setSelectedIndex(SelectionModel.java:68)
at javafx.scene.control.MultipleSelectionModelBase.clearSelection(MultipleSelectionModelBase.java:682)
at javafx.scene.control.ListView$ListViewBitSetSelectionModel$2.onChanged(ListView.java:1222)
at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
at javafx.collections.ModifiableObservableListBase.remove(ModifiableObservableListBase.java:183)
at LendingLibraryGUI.deleteLibrary(LendingLibraryGUI.java:266)
at LendingLibraryGUI.lambda$2(LendingLibraryGUI.java:72)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Node.fireEvent(Node.java:8413)
at javafx.scene.control.Button.fire(Button.java:185)
at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:96)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3757)
at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:394)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$353(GlassViewEventHandler.java:432)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:431)
at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
at com.sun.glass.ui.View.notifyMouse(View.java:937)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$147(WinApplication.java:177)
at java.lang.Thread.run(Unknown Source)
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at LendingLibraryGUI.lambda$5(LendingLibraryGUI.java:107)
at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:349)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.ReadOnlyObjectPropertyBase.fireValueChangedEvent(ReadOnlyObjectPropertyBase.java:74)
at javafx.beans.property.ReadOnlyObjectWrapper.fireValueChangedEvent(ReadOnlyObjectWrapper.java:102)
at javafx.beans.property.ObjectPropertyBase.markInvalid(ObjectPropertyBase.java:112)
at javafx.beans.property.ObjectPropertyBase.set(ObjectPropertyBase.java:146)
at javafx.scene.control.SelectionModel.setSelectedItem(SelectionModel.java:102)
at javafx.scene.control.MultipleSelectionModelBase.lambda$new$34(MultipleSelectionModelBase.java:67)
at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:137)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.ReadOnlyIntegerPropertyBase.fireValueChangedEvent(ReadOnlyIntegerPropertyBase.java:72)
at javafx.beans.property.ReadOnlyIntegerWrapper.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:102)
at javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:113)
at javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:147)
at javafx.scene.control.SelectionModel.setSelectedIndex(SelectionModel.java:68)
at javafx.scene.control.MultipleSelectionModelBase.clearSelection(MultipleSelectionModelBase.java:682)
at javafx.scene.control.ListView$ListViewBitSetSelectionModel$2.onChanged(ListView.java:1222)
at javafx.collections.WeakListChangeListener.onChanged(WeakListChangeListener.java:88)
at com.sun.javafx.collections.ListListenerHelper$Generic.fireValueChangedEvent(ListListenerHelper.java:329)
at com.sun.javafx.collections.ListListenerHelper.fireValueChangedEvent(ListListenerHelper.java:73)
at javafx.collections.ObservableListBase.fireChange(ObservableListBase.java:233)
at javafx.collections.ListChangeBuilder.commit(ListChangeBuilder.java:482)
at javafx.collections.ListChangeBuilder.endChange(ListChangeBuilder.java:541)
at javafx.collections.ObservableListBase.endChange(ObservableListBase.java:205)
at javafx.collections.ModifiableObservableListBase.remove(ModifiableObservableListBase.java:183)
at LendingLibraryGUI.deleteLibrary(LendingLibraryGUI.java:266)
at LendingLibraryGUI.lambda$2(LendingLibraryGUI.java:72)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Node.fireEvent(Node.java:8413)
at javafx.scene.control.Button.fire(Button.java:185)
at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:96)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3757)
at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:394)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$353(GlassViewEventHandler.java:432)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:431)
at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
at com.sun.glass.ui.View.notifyMouse(View.java:937)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$147(WinApplication.java:177)
at java.lang.Thread.run(Unknown Source)
Any Help would be greatly appreciated!! Thanks in advance!
Change:
String name = library.getSelectionModel().getSelectedItem().toString();
To:
String name = library.getSelectionModel().getSelectedItem();
library.getSelectionModel().getSelectedItem() is null -- i.e. you are dereferencing a null pointer!
Related
I have been working on an app that requires me to get information such as a Place Name and a PLace Photo from google PLaces Api and set it into a RecyclerView. I am stuck because I managed to get the code to work with no errors but the RecyclerView is empty. What is wrong with my code?
I am stuck because I don't know where the problem is. When I run the code, all the fetchs work and the tags show up in the Log so I am completely lost. My first thought is that I am displaying the code wrong but then I have no recourse to step forward and change it to something else because I am not sure if it would be better or worse.
This is the Fragment for the RecyclerView Item:
public class VenueList extends Fragment{
ArrayList<VenueItem> vIL = new ArrayList<>();
private PlacesClient placesClient;
private Context contextForPlaces;
place ids for the places I am currently using
String[] clubs = {"ChIJO_uSYKNZwokRAC7RLeB0oZ8", "ChIJAQBEylJYwokRLbnrAchQImk",
"ChIJU_26rfpYwokRTNf2K1-7p8E", "ChIJ38hxfnhZwokRx1HSFLj790w", "ChIJBwnlGrdZwokRpf61pMm860c"
, "ChIJpSIzqrhZwokR1KnVMoVty_g", "ChIJMRV7375ZwokRAfltF6Y-wYw", "ChIJYabdHPhYwokRPmAV8GtM3gs",
"ChIJi2dSjQRZwokRuXUKcv4riVc", "ChIJKaKVI79ZwokRN8WicODOIAw", "ChIJwXI8Fb5ZwokRr4JjG4HxSP8",
"ChIJ6bU_E4ZZwokR2ZDbY_IhhrI"};
#Override
public void onAttach(Context context) {
super.onAttach(context);
contextForPlaces = context;
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.menu_venue, container, false);
RecyclerView vRV = view.findViewById(R.id.view_venue);
List<Place.Field> placeFields = Arrays.asList(Place.Field.NAME, Place.Field.PHOTO_METADATAS);
if (!Places.isInitialized()) {
Places.initialize(contextForPlaces, "AIzaSyCKGd3fqmtsDklRGMhnkuIy1GS-j6gRBh8");}
placesClient = Places.createClient(contextForPlaces);
vRV.setHasFixedSize(true);
RecyclerView.LayoutManager vLM = new LinearLayoutManager(this.getActivity());
RecyclerView.Adapter vAdapter = new VenueAdapter(vIL);
// run through each photo to make sure it has a place attached to it then insert each photo and place into the vIL
//createBitmap for fetchPhoto
for (String club : clubs) {
FetchPlaceRequest request = FetchPlaceRequest.newInstance(club, placeFields);
placesClient.fetchPlace(request).addOnSuccessListener((response) -> {
Place place = response.getPlace();
PhotoMetadata photoMetadata = place.getPhotoMetadatas().get(0);
String attributions = photoMetadata.getAttributions();
FetchPhotoRequest photoRequest = FetchPhotoRequest.builder(photoMetadata).setMaxHeight(200).build();
placesClient.fetchPhoto(photoRequest).addOnSuccessListener((fetchPhotoResponse) -> {
Bitmap bitmap = fetchPhotoResponse.getBitmap();
vIL.add(new VenueItem(/*Photo*/bitmap, place/*Name*/));
Log.i(TAG, "Photo Should Be Up: ");
}).addOnFailureListener((exception) -> {
if (exception instanceof ApiException) {
ApiException apiException = (ApiException) exception;
int statusCode = apiException.getStatusCode();
// Handle error with given status code.
Log.e(TAG, "Place not found: " + exception.getMessage());
}
});
Log.i(TAG, "Place found: " + place.getName());
}).addOnFailureListener((exception) -> {
if (exception instanceof ApiException) {
ApiException apiException = (ApiException) exception;
int statusCode = apiException.getStatusCode();
// Handle error with given status code.
Log.e(TAG, "Place not found: " + exception.getMessage());
}
});
}
vRV.setLayoutManager(vLM);
vRV.setAdapter(vAdapter);
return view;
}
This is the part of the RecyclerView Adapter I changed. I used to be a getResourse for the image because the image was from the drawable folder
public void onBindViewHolder(#NonNull VenueViewHolder venueViewHolder, int i) {
VenueItem currentItem = vIAL.get(i);
if(currentItem.getVenueImageResource() == null){
venueViewHolder.vIV.setImageResource(R.drawable.ic_android);
}else
venueViewHolder.vIV.setImageBitmap(currentItem.getVenueImageResource());
venueViewHolder.vTV.setText((CharSequence) currentItem.getVenueDescription());
}
The Item itself which I also had to change a bit from its original. I made the string a Place and the int a Bitmap. I thought that would work.
public class VenueItem {
private Bitmap venueImageResource;
private Place venueDescription;
public VenueItem(Bitmap vIR, Place description) {
venueImageResource = vIR;
venueDescription = description;
}
public Bitmap getVenueImageResource() {
return venueImageResource;
}
public Place getVenueDescription() {
return venueDescription;
}
}
I want to be able to request a place name and a photo of the place using the placesClient and precent it in the for of a RecyclerView. I know the place Ids are correct because the Log returns the names of all the places. But they do not show up on the RecyclerView
I figured out the answer myself.
vRV.setLayoutManager(vLM);
vRV.setAdapter(vAdapter);
I just had to put these two lines into the for loop under the list item so that each item could escape before meing erased
I am faced with a problem with my java-csv-mysql gui application that i am working on.
i will breakdown the application in the following functions:
1. select a CSv using a JFileChooser,
2. reading the csv
3. importing the csv to Mysql table
4. displaying the csv contents once they are imported into the Table.
I have managed to get it to do the following functions.
1. select a csv file
2. read through the csv file...-reads only one row
3. display read records
I have problems when it come to the following
1. reading 'all' the records in the csv
2. uploading to the csv.
the Error I get is an ArrayIndexOutofBoundsException:3
which is due to the reading of the csv.
the csv has the following format:
2018/01/25,58,294616/0
2018/01/27,102,298970/0
the csv needs to do the following while it reads the csv
1. read the csv,
2. separate the last column which is to be seprated by a'/'.
this will result in there being 4 columns instead of 3.
here is the Code that I have so far.
public class Payment_import_v4 extends JFrame{
private JTable table;
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable(){
public void run()
{
createAndshowGUI();
}
});
}
private static void createAndshowGUI(){
Payment_import_v4 form = new Payment_import_v4();
form.setVisible(true);
}
public Payment_import_v4(){
//form frame
super("Payment Import");
setSize(900,600);
setLocation(500,280);
getContentPane().setLayout(null);
//Label Result
final JLabel lblResult = new JLabel("Result",JLabel.CENTER);
lblResult.setBounds(150,22,370,14);
getContentPane().add(lblResult);
//Table
table = new JTable();
getContentPane().add(table);
//Table Model
final DefaultTableModel model = (DefaultTableModel)table.getModel();
model.addColumn("PayDate");
model.addColumn("Ammount");
model.addColumn("LinkId");
model.addColumn("BranchNo");
//ScrollPane
JScrollPane scroll = new JScrollPane(table);
scroll.setBounds(84,98,506,79);
getContentPane().add(scroll);
//Button Open
JButton btnOpen = new JButton("Select File");
btnOpen.setBounds(268,47,135,23);
btnOpen.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ae){
JFileChooser fileOpen = new JFileChooser();
FileFilter filter = new FileNameExtensionFilter("CSV file","csv");
fileOpen.addChoosableFileFilter(filter);
int ret = fileOpen.showDialog(null,"Choose file");
if(ret == JFileChooser.APPROVE_OPTION){
File file = fileOpen.getSelectedFile();//gets selectedFile.
try {
BufferedReader br = new BufferedReader(new FileReader(file));
int row = 0;
//if (br.readLine() != null) {line = br.readLine();
while ((br.readLine()) != null) {
String line = br.readLine();// br string variable
String[] rawRow = line.split(",");
String lastEntry = rawRow[rawRow.length - 1];//this contains the LinkId/branchNo
String[] properLastEntry = lastEntry.split("/");//this contains the LinkId/branchNo split into two columnms
String[] oneRow = new String[rawRow.length + 1];
System.arraycopy(rawRow, 0, oneRow, 0, rawRow.length - 1);
System.arraycopy(properLastEntry, 0, oneRow, oneRow.length - properLastEntry.length, properLastEntry.length);
model.addRow(new Object[0]);
model.setValueAt(rawRow[0], row, 0);
model.setValueAt(rawRow[1], row, 1);
model.setValueAt(rawRow[2], row, 2);
model.setValueAt(rawRow[3], row, 3);
row++;
}
br.close();
//}
} catch (IOException ex) {
ex.printStackTrace();
}
lblResult.setText(fileOpen.getSelectedFile().toString());
}
}
});
getContentPane().add(btnOpen);
//btn Save
JButton btnSave = new JButton("Save");
btnSave.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ea){
SaveData();
}
});
btnSave.setBounds(292,228,89,23);
getContentPane().add(btnSave);
}
private void SaveData(){
Connection connect = null;
Statement stmt = null;
try{
//DriverManager Loader
Class.forName("com.mysql.jdbc.Driver");
//connection string url.. the port//schema name//username//password
//this is the test Server ;oginDetails
connect = DriverManager.getConnection("jdbc:mysql://localhost:3306/riskfin", "root", "riskfin");//-------------> this is for the localhost server
stmt = connect.createStatement();
for(int i = 0;i<table.getRowCount();i++)
{
String PayDate = table.getValueAt(i,0).toString();
String Ammount = table.getValueAt(i,1).toString();
String LinkID = table.getValueAt(i,2).toString();
String BranchNo = table.getValueAt(i,3).toString();
String sql = "Insert into temp_payment_import "
+"VALUES('"+LinkID+"','"
+Ammount+"','"
+PayDate+"','"
+BranchNo+"')";
stmt.execute(sql);
}
JOptionPane.showMessageDialog(null,"Data imported Successfully");
}catch(Exception ex){
JOptionPane.showMessageDialog(null,ex.getMessage());
ex.printStackTrace();
}
try{
if(stmt!= null){
stmt.close();
connect.close();
}
}catch(SQLException e){
System.out.println(e.getMessage());
e.printStackTrace();
}
}
}
here is the exception I get.
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 3
at payment_import_v4.Payment_import_v4$2.actionPerformed(Payment_import_v4.java:120)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2022)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2348)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
at java.awt.Component.processMouseEvent(Component.java:6533)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3324)
at java.awt.Component.processEvent(Component.java:6298)
at java.awt.Container.processEvent(Container.java:2236)
at java.awt.Component.dispatchEventImpl(Component.java:4889)
at java.awt.Container.dispatchEventImpl(Container.java:2294)
at java.awt.Component.dispatchEvent(Component.java:4711)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4888)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4525)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4466)
at java.awt.Container.dispatchEventImpl(Container.java:2280)
at java.awt.Window.dispatchEventImpl(Window.java:2746)
at java.awt.Component.dispatchEvent(Component.java:4711)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:90)
at java.awt.EventQueue$4.run(EventQueue.java:731)
at java.awt.EventQueue$4.run(EventQueue.java:729)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
You went to great lengths to write very accurate array manipulation code to deal with having two separators in your CSV data. But you never actually used the oneRow array. Change this:
model.addRow(new Object[0]);
model.setValueAt(rawRow[0], row, 0);
model.setValueAt(rawRow[1], row, 1);
model.setValueAt(rawRow[2], row, 2);
model.setValueAt(rawRow[3], row, 3); // ArrayIndexOutOfBoundsException
to this:
model.addRow(new Object[0]);
model.setValueAt(oneRow[0], row, 0);
model.setValueAt(oneRow[1], row, 1);
model.setValueAt(oneRow[2], row, 2);
model.setValueAt(oneRow[3], row, 3);
By definition, rawRow will only have 3 elements in it, because the final 2 terms will still appear as a single term (the term not yet having been split again on /).
I am using a ValueConverter to get the thumbnail for an m4 file that was recorded by directly with WinRT's MediaCapture. After much debugging and alternate approaches, I've settle on the converter code below. I am getting the following error The component cannot be found. (Exception from HRESULT: 0x88982F50) on the GetThumbnailAsync method.
I have confirmed that the thumbnail is being shown for the video in the Xbox Video app and the file explorer app when I use CopyTo(KnownFolders.VideosLibrary).
The converter seems to work fine when it's an external video file, but not with one of my app's mp4s. Is there something wrong with my converter or can you reproduce this?
SEE UPDATE 1 I try to get the thumbnail when the file is first created, same error occurs.
public class ThumbnailToBitmapImageConverter : IValueConverter
{
readonly StorageFolder localFolder = ApplicationData.Current.LocalFolder;
BitmapImage image;
public object Convert(object value, Type targetType, object parameter, string language)
{
if (Windows.ApplicationModel.DesignMode.DesignModeEnabled)
return "images/ExamplePhoto2.jpg";
if (value == null)
return "";
var fileName = (string)value;
if (string.IsNullOrEmpty(fileName))
return "";
var bmi = new BitmapImage();
bmi.SetSource(Thumb(fileName).Result);
return bmi;
}
private async Task<StorageItemThumbnail> Thumb(string fileName)
{
try
{
var file = await localFolder.GetFileAsync(fileName)
.AsTask().ConfigureAwait(false);
var thumbnail = await file.GetScaledImageAsThumbnailAsync(ThumbnailMode.ListView, 90, ThumbnailOptions.UseCurrentScale)
.AsTask().ConfigureAwait(false);
return thumbnail;
}
catch (Exception ex)
{
new MessageDialog(ex.Message).ShowAsync();
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
UPDATE 1
I decided to go back to where I save the video to a file and grab the thumbnail there, then save it to an image for use later. I get the same error, here is the code for grabbing and saving the thumbnail after the video is saved:
var thumb = await videoStorageFile.GetThumbnailAsync(ThumbnailMode.ListView);
var buffer = new Windows.Storage.Streams.Buffer(Convert.ToUInt32(thumb.Size));
var thumbBuffer = await thumb.ReadAsync(buffer, buffer.Capacity, InputStreamOptions.None);
using (var str = await thumbImageFile.OpenAsync(FileAccessMode.ReadWrite))
{
await str.WriteAsync(thumbBuffer);
}
I have not tested this out, but It should work. In your model that you are binding to, replace the property for your thumbnail with a new class named Thumbnail. Bind to that property rather than your video location. When the video location changes, create a new thumbnail.
public class VideoViewModel : INotifyPropertyChanged
{
public string VideoLocation
{
get { return _location; }
set
{
_location = value;
Thumbnail = new Thumbnail(value);
OnPropertyChanged();
}
}
public Thumbnail Thumbnail
{
get { return _thumbnail; }
set
{
_thumbnail = value;
OnPropertyChanged();
}
}
}
The Thumbnail class. This is just a shell, ready for you to fill out the rest
public class Thumbnail : INotifyPropertyChanged
{
public Thumbnail(string location)
{
Image = GetThumbFromVideoAsync(location);
}
private Task<BitMapSource> GetThumbFromVideoAsync(string location)
{
BitMapSource result;
// decode
// set it again to force
Image = Task.FromResult(result);
}
public Task<BitMapSource> Image
{
get { return _image; }
private set
{
_image = value;
OnPropertyChanged();
}
}
}
You can still have a value converter in place. It would check if the task has completed, if it has not, then show some default image. If the task has faulted, it can show some error image:
public class ThumbnailToBitmapImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var thumbnail = value as Thumbnail;
if (thumbnail == null) return GetDefaultBitmap();
if (thumbnail.Image.IsCompleted == false) return GetDefaultBitmap();
if (thumbnail.Image.IsFaulted) return GetBadImage();
return thumbnail.Image.Result;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
private BitMapSource GetDefaultBitmap()
{
// load a default image
}
private BitMapSource GetBadImage()
{
// load a ! image
}
}
Hi I want to develop an app that takes photo and uploads to Google Drive. I found the master(source code) from Github today which is by Google https://github.com/googledrive/android-quickstart
This is very useful. But I found some problems that If i Press back button the application still does not finish it's activity. By default it always opens camera and taking photo and saving it to the Google Drive.Its doing the same thing again and again.If I want to exit the app I cannot until I press Home button. Any solution? Also There is another problem: after taking photo it shows a dialog windows asking where to save the image and what will be the image name.The problem is if I press cancel button it shows the same dialog again and again. If I press Ok then it doesnot show the dialog but If I press cancel it shows the same dialog again. I want to get rid of it when I press cancel. Any solution? This is the code :
package com.randb.uploadtogdrive;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import android.app.Activity;
import android.content.Intent;
import android.content.IntentSender;
import android.content.IntentSender.SendIntentException;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.drive.Drive;
import com.google.android.gms.drive.DriveApi.ContentsResult;
import com.google.android.gms.drive.MetadataChangeSet;
public class MainActivity extends Activity implements ConnectionCallbacks,
OnConnectionFailedListener {
private static final String TAG = "android-drive-quickstart";
private static final int REQUEST_CODE_CAPTURE_IMAGE = 1;
private static final int REQUEST_CODE_CREATOR = 2;
private static final int REQUEST_CODE_RESOLUTION = 3;
private GoogleApiClient mGoogleApiClient;
private Bitmap mBitmapToSave;
/**
* Create a new file and save it to Drive.
*/
private void saveFileToDrive() {
// Start by creating a new contents, and setting a callback.
Log.i(TAG, "Creating new contents.");
final Bitmap image = mBitmapToSave;
Drive.DriveApi.newContents(mGoogleApiClient).setResultCallback(new ResultCallback<ContentsResult>() {
#Override
public void onResult(ContentsResult result) {
// If the operation was not successful, we cannot do anything
// and must
// fail.
if (!result.getStatus().isSuccess()) {
Log.i(TAG, "Failed to create new contents.");
return;
}
// Otherwise, we can write our data to the new contents.
Log.i(TAG, "New contents created.");
// Get an output stream for the contents.
OutputStream outputStream = result.getContents().getOutputStream();
// Write the bitmap data from it.
ByteArrayOutputStream bitmapStream = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.PNG, 100, bitmapStream);
try {
outputStream.write(bitmapStream.toByteArray());
} catch (IOException e1) {
Log.i(TAG, "Unable to write file contents.");
}
// Create the initial metadata - MIME type and title.
// Note that the user will be able to change the title later.
MetadataChangeSet metadataChangeSet = new MetadataChangeSet.Builder()
.setMimeType("image/jpeg").setTitle("myPhoto.png").build();
// Create an intent for the file chooser, and start it.
IntentSender intentSender = Drive.DriveApi
.newCreateFileActivityBuilder()
.setInitialMetadata(metadataChangeSet)
.setInitialContents(result.getContents())
.build(mGoogleApiClient);
try {
startIntentSenderForResult(
intentSender, REQUEST_CODE_CREATOR, null, 0, 0, 0);
} catch (SendIntentException e) {
Log.i(TAG, "Failed to launch file chooser.");
}
}
});
}
#Override
protected void onResume() {
super.onResume();
if (mGoogleApiClient == null) {
// Create the API client and bind it to an instance variable.
// We use this instance as the callback for connection and connection
// failures.
// Since no account name is passed, the user is prompted to choose.
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Drive.API)
.addScope(Drive.SCOPE_FILE)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
// Connect the client. Once connected, the camera is launched.
mGoogleApiClient.connect();
}
#Override
protected void onPause() {
if (mGoogleApiClient != null) {
mGoogleApiClient.disconnect();
}
super.onPause();
}
#Override
public void onBackPressed(){
Toast.makeText(MainActivity.this,"Going Somehwere?", Toast.LENGTH_LONG).show();
finish();
}
#Override
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
switch (requestCode) {
case REQUEST_CODE_CAPTURE_IMAGE:
// Called after a photo has been taken.
if (resultCode == Activity.RESULT_OK) {
// Store the image data as a bitmap for writing later.
mBitmapToSave = (Bitmap) data.getExtras().get("data");
}
break;
case REQUEST_CODE_CREATOR:
// Called after a file is saved to Drive.
if (resultCode == RESULT_OK) {
Log.i(TAG, "Image successfully saved.");
mBitmapToSave = null;
// // Just start the camera again for another photo.
// startActivityForResult(new Intent(MediaStore.ACTION_IMAGE_CAPTURE),
// REQUEST_CODE_CAPTURE_IMAGE);
}
break;
}
}
#Override
public void onConnectionFailed(ConnectionResult result) {
// Called whenever the API client fails to connect.
Log.i(TAG, "GoogleApiClient connection failed: " + result.toString());
if (!result.hasResolution()) {
// show the localized error dialog.
GooglePlayServicesUtil.getErrorDialog(result.getErrorCode(), this, 0).show();
return;
}
// The failure has a resolution. Resolve it.
// Called typically when the app is not yet authorized, and an
// authorization
// dialog is displayed to the user.
try {
result.startResolutionForResult(this, REQUEST_CODE_RESOLUTION);
} catch (SendIntentException e) {
Log.e(TAG, "Exception while starting resolution activity", e);
}
}
#Override
public void onConnected(Bundle connectionHint) {
Log.i(TAG, "API client connected.");
if (mBitmapToSave == null) {
// This activity has no UI of its own. Just start the camera.
startActivityForResult(new Intent(MediaStore.ACTION_IMAGE_CAPTURE),
REQUEST_CODE_CAPTURE_IMAGE);
return;
}
saveFileToDrive();
}
#Override
public void onConnectionSuspended(int cause) {
Log.i(TAG, "GoogleApiClient connection suspended");
}
This should take care of you 'thumbnail' problem. Basically, replace the bitmap mBitmapToSave with a file '_picFl'. The code below is modified, the var names are different, but it does essentially what you're asking for.
private File _picFl;
private GoogleApiClient _gac;
#Override public void onConnected(Bundle connectionHint) {
if (_picFl == null)
takePic();
else
save2GooDrv();
}
//-----------------------------------------------------------------------------------------------
private void takePic() {
Intent icIt = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (icIt.resolveActivity(getPackageManager()) != null) try {
_picFl = new File(getCcheDir(), tm2FlNm(null));
if (_picFl != null) {
icIt.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(_picFl));
startActivityForResult(icIt, RC_GETIMAGE);
}
} catch (Exception e) {le(e);}
}
//-----------------------------------------------------------------------------------------------
private synchronized void save2GooDrv() {
Drive.DriveApi.newContents(_gac).setResultCallback(new ResultCallback<ContentsResult>() {
#Override public void onResult(ContentsResult rslt) {
if (rslt.getStatus().isSuccess()) try {
OutputStream os = rslt.getContents().getOutputStream();
os.write(file2Bytes(_picFl));
MetadataChangeSet metadataChangeSet = new MetadataChangeSet.Builder()
.setMimeType("image/jpeg").setTitle(_picFl.getName()).build();
_picFl.delete();
_picFl = null;
IntentSender intentSender = Drive.DriveApi
.newCreateFileActivityBuilder()
.setInitialMetadata(metadataChangeSet)
.setInitialContents(rslt.getContents())
.build(_gac);
try {
startIntentSenderForResult( intentSender, RC_CREATOR, null, 0, 0, 0);
} catch (SendIntentException e) {le(e);}
} catch (Exception e) {le(e);}
}
});
}
//***********************************************************************************************
public String getCcheDir() {
Context actx = getApplicationContext();
return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ||
!Environment.isExternalStorageRemovable() ?
actx.getExternalCacheDir().getPath() : actx.getCacheDir().getPath();
}
//***********************************************************************************************
public byte[] file2Bytes(File file) {
byte[] buf = null;
RandomAccessFile raFl = null;
if (file != null) try {
raFl = new RandomAccessFile(file, "r");
buf = new byte[(int)raFl.length()];
raFl.readFully(buf);
} catch (Exception e) {le(e);}
finally {
if (raFl != null) try {
raFl.close();
} catch (Exception e) {le(e);}
}
return buf;
}
//***********************************************************************************************
public String tm2FlNm(Long milis) { // time -> yymmdd-hhmmss
try {
return new SimpleDateFormat("yyMMdd-HHmmss",Locale.US)
.format((milis == null) ? new Date() : new Date(milis));
} catch (Exception e) {le(e);}
return null;
}
//***********************************************************************************************
public void le(Exception e){
try {
Log.e("_", (e==null) ? "NULL" : Log.getStackTraceString(e));
}catch (Exception f) { try { Log.e("_", "ERR on err");} catch (Exception g) {} }
}
Here is a quick fix for your problem. Back button from both the activities you're talking about (camera, creator) returns 'Activity.RESULT_CANCELED', so just kill your activity (using finish()) when you don't get 'Activity.RESULT_OK'.
switch (requestCode) {
case REQUEST_CODE_CAPTURE_IMAGE:
// Called after a photo has been taken.
if (resultCode == Activity.RESULT_OK) {
// Store the image data as a bitmap for writing later.
mBitmapToSave = (Bitmap) data.getExtras().get("data");
} else
finish();
break;
case REQUEST_CODE_CREATOR:
// Called after a file is saved to Drive.
if (resultCode == RESULT_OK) {
Log.i(TAG, "Image successfully saved.");
mBitmapToSave = null;
// // Just start the camera again for another photo.
// startActivityForResult(new Intent(MediaStore.ACTION_IMAGE_CAPTURE),
// REQUEST_CODE_CAPTURE_IMAGE);
} else
finish();
break;
}
But in general, 'quickstart' is usually just a proof-of-concept, not something you should build you app on.
This question already has answers here:
Can itextsharp.xmlworker render embedded images?
(2 answers)
Closed 5 years ago.
I'm doing a PDF report in which I have to insert some html fragments. I'm done with iText5 and my code is:
Paragraph paragraph = new Paragraph();
HTMLWorker htmlWorker = new HTMLWorker(docPDF);
htmlWorker.parse(new StringReader(...html string in here....));
Everything is working fine but when in the html code there is a tag with the source in base64 like this
<img alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUh......" />
it displays the following error:
ExceptionConverter: java.io.FileNotFoundException: C:\data:image\png;base64,iVBORw0KGgoAAAANSUhEUgAAAOUAAADpCAIAAABUaWc6AAAgAElEQVR4nO2deXxTZdr3z8wDtK6AioAsohVFAesGMgjCIOrIzIBLBwd8B+ZFh0FnZNDRF3kUpoNsIooOCLi0jApaShegi3Sj+56kW5ZmOznZ0+xNQtM2bfP+cZfD6cnZsxZzfX5\QJuepCff3rnu674WyB+3uI0eg6L9AuIWNxYW5zVuo8nivMZtNFmc17iNJrvWePX5fDqDAUiqgMVyJZnQh9lstmi\6rgxtVHPKwBUIodFsEZm9iCuAc4Sq40iWCORw0aTKdq\VtyIbVTy6nZ7EI1WLIfFWmMwgNLgqzUKlWqxXAkjarfbE+1fOm5+\6jj1WgyCRVI+BilkERjFcths9kS7Xvws7bRwavX6xXLlVKjPSqk4iQ12sVxnyFKFuu86gwGkRwO0jENk2Rmj1CBwIja5\NF+z79XCx2ebXZbEJEH3UoKaT3DJguD5ouD2qclxGdCVapYRhWqVSGKxbnOOQWi7z6fD6xAlbYe6JOJCqDZ9DeO+jsG+ruG+odGGL7G5lMJhiGEQTxer3huGM\H4s5Xo0mk0RjjTqgiGvAeHnQ2TfU4xtijSe59fX1aTSa0F3vZ2exxatMqYrusqp1D1i9g+7+IfZrKAtDECTuKnCzWOHV5\OJ5NEJVAFZega9YYV0pFmtVrvdHrGnu2YsJnj1er1hjfxTSOcZcPUPDUYO1KvW19eHIEgUnng0W\R59Xq9UQms6jwD7v5ocDrS4r4BK4syrz6fL\JBK4Nn8LIv+qSiFvcNmFs0efX5fCJYE0lS1a4BZ190Pv2pLe4bMLRo8hrhTADT5cEIbqhY2OXLl8H5QhxZWosar1IFHGEfwDswRKbLviFnHyPZewfBmRat9B4WL08kh+NHCUwsOryazZaYOr6KBcmM3VIFHJW3YxRZFHj1+XwxcoIVg5JorBqtLvJvymixKPAa3XOBUSGhMp4hTmyR5lWj1UWdhlEhmdkjkcfdA7xFlFefzyczdkcdhVEksdoYL4fEWkR5hRF11AkYdVLYe+ILLWqR49Xn80UrSeAakFhtjHu0\kjyGuGA67UnmdkTDx1EkNfYqBYc7RLJf9ZFChHiFdFoo\5OXzOSaKw\201YhHiNe66hlczsQTTayLx3MWWR4DUecw2TxHJlBN6+mLJI8Bqtjiw\BwkR\c\KnQ07rz6fL57aElZJNFan0xnu9zFGLOy8xs8IIiCZ2fMz6Y8Udl7jzkBkpLD3yJSqcL+bUbew8xqbra+uVYnk8LVdvRheXnUGQ9Tfwp+bru0dWHh5jTsDUZHUaL9Wd2Bh5DUeGcBK6egt5DUDZZQXA6FfKeQ110jlQEpHbxxZMgsjr2azJeqUxI5aNEYUU2oJQ5RoITN2X3vdwMPIazxnAKuy9g6GvDYqQxYBVNh7rrFj2zDyKo4nEGKUW1vNkNdKUWdon1qhunbaGoSR1wj3bolliU1OhrBmlBdf5PND\gKuGWTDyGs88oqqTqZgzmt2TWU4XsO1gWy4eL2WNlsSc3eDAoad\ZyvgI0JMFEwIQKxySm3XSb+1ujP5woXrwrVtRB5VTp6K0WdgKHz9bXcdu5KR29mZSkrXjmHCBoUcGZlaVbVpWYV8WZ3tCMbLl6vgaYYDQo4q+oSFqPMytI6mYLVRYRGO\PIAKrilha2yCodvRf5fOxF8psaJGaC6vlRjWy4eI3xUUTUatEYz9fXksFExgEqibm7Uakubmlhu6zilFV1qaStrVmlJft8R9Wut2bXVAZeAfyBBXoyoxfZcPE6SjtkiU1OJr5m4EKrdPTyEX25UMQ8bsVKeY11VRIZ4aJbJZFR\yyhJwMj6jC99WG1cPE6GqthGxQwK4Yu8vntemuVRJbf1BAORmkXXanVzfypK0Wd2G2cwt4zGlNmw8Vr1OHjIA6O5uhSdk1lq64L\X1lZs+oO7ANC68+ny\q8MV5JVReYx32V5aZPaOrNDwsvDqdzqjDx0G0juA1oOKWFtxvPboyueK8XlWNVB51nsItwuQEicY6WlK8w8LrKC0r+Dnw2kCShCRE9KOikCYsvI7SBhnNKm3UeQq3WjSkjXbEo6FrZ1h4HaWHsWHl9Uxl+dma+pymdlTZDYLsBj7636y65syqinDzKjZRuWqxX2Eb5\Wq+Ig+lIBWlOTUC3J5kgstqoIOU4HQwlB5bdpcniS7rulMRVnIeaXOpFHYe2K8ZScpr3a73XDFLBZ2UbpRymu73ho8EGerq3N5kvx2A3NAqdht1ZwXKLPreWcqy4N\bVlVl2hvgsLeE8tBWVJeHQ5H4BdNJhM6iQ+GYRRoj2dE6+dRyisuX4SVilp4PKRTd9lWr7aFhNRAnRcoc+oFwYCLC76SSWq0x2wvb2Je9Xo9h2sBdmEYVml1XT2DxsuDUUeQubgdFmRVlfE1Ml2PzdTvBGrtcgSiJjDaqmBrkcRSILR8mVcXJLjneNKz1VyyFLKqLlH7r6hiNlxAzKtWG7IitYEhv3dgyNk35OgdNHhilGA0yZW5ztVVtuoUWFJN\U691wmgxKqk04o+oE7Sdvfs2RAErVr75\VvvLv7xJlcvo7zcptd18QB2XY9o1Sk2AwXEPDq8Xj6+vrC95T9g34wr9UUGwsw27BrZmUpXyPDYopKZLUHglUut2IfU9PRBGFs8rQZu0+cCcZJYLvWZlaWYrMIKBSDJTQEvKpUqki+gt6BoR7fkKOX3YDgUIltDOuioEHjMRPCaup3VsMEzms1PGIN3n1oPxRgb+05EoyHkMuTsAomMEQ2BvdeBLxardbIvw7UegeGnH1DIfEc5LbL1InVzHtYAAdA1IWQkWrqd2q9zkKRNRCmBs0IXlc8uxJLatKcebtPnDlw8lyQTm1emz6rjkWVWGZlKVnNDFZSoz2mjmrxvBoMhqi8jkAbGPJ7fENW76DWzZFXdL+f11h3kc+vkcqbVdp2vRXk27fqupjn\1eIBBSkAoltBDutAqFFYLzKq9plSkhMxPI698H5EARt3r4nSF6BzjWLWH1cMEFWqIyhzG48rwgScy6L3+\vGxyys3QYqIP\WVWXmMNaJxcaeu20vGp6iHltN9uxvM5Lno\ldV7y\CZZe9qFouBhFZodSpdTZtOdqyOojSFTgwJu11uBGhQw2sarRiov5DWDwoTYOfcawavX6w3rTit46x0YMvfQuwqws5+wnomtsqvLZDYdLamoyuV4f6BcbtX0OLCPefTxBVhe77nv3ufXvqR2mYRmB6E7wVzoEyHuLlbIUgiEbBX2nhjJORzBa4R3WpzNN+h39A5qyP0EDvEpQlg7LVrmsJr6nQLjiP1Wrcpq7MM\Zveh\Un3zkZ5ffTxBe\sfA9o6473tv7r0IGT57jFaJWu4Zia3uvU9dgKmmpCgizwGYQIl5B8yG0Er2zPXSNgIHwL5OwblqVn0HSZNJrLqvkPmTIrS1mtrMMLm8eJ0sPXD7utUrM6pyR\89bXFy9bcvuUyRAEJV5xYWfNmrVly5ZZs2YFRgxuuGn8r55atXn7HuZbManDAdySMpkV8YQM2eyaSuDxx0JV7VVeIwwrSqGrf5hCe++g6fKw1EGEBfIa6zi\N59+m5ay8U+b\7mtQdbOFlagMpm1UGQVWe2mfmdOSf7za19KSEz85ZgxWBbLy8tbWlokEgm4FcuXLw\kNXHCRGyMduXzf6QFFzwpcKOLJVZjn1PjMYfEMaiSyMC91UV7O36V15DstKxWKziV7b7sRZfDrp5hCiMQYWVb44pTWl7OvXMfgCBo\ITxOSX5HHhtN9uVLueJU2nzkuePu\Gm2c+svn\1WhyvqampHpOx5sP\BTeNkFcIgm5Num\2M6sf2bBl7ouvTE1+bEzidZOnzVj\xrunKkSEvKrcDuy2D+zzNB7zRUGw5buZlaWgB4LM2B3d1IJhXn0+H8VOy+v1oqktKpUKhmEYhhEEQb8Y+CNRqeeW2y4H2aLiZME5mU33\NqXuCGrdpl2H9o\486ZN0+bOffFV1bsPJi04rlAEJcvXw6XFGasWupQyvzkvAIbd+NNdz7x68Vv7li+Y9\cF1+5Nem+G24av2rtnzPrFYSBCJRXsMSa+p2GXnshj\tnDhBa+BXd8NYwr3a7Hb5iZFlXrCwq\V1K2tqCeUuyqsoq2ho3b30d3cK\9NJLGXnZapeJCayff3Ps0ccX3Dj5juT1r67YeXDh5m03T5tJiGBiYqJNjZx7ZU2\x+2n4xW73N6\eu3yHfse2\T3W5PugyDoD6\9A5t+UCiyyrsdQrMD\S+62zP02oP3ZdGmG1E8p712+hEFn73aqlMMf6ZrpLsP7X9xbQpIqpw1a9a85Pmbt75+4lRau0YaSGpOST4g9f7Va1fsPLhi58H7Vr047sabKOArLy\P+79\kBec8zPmFdiYxOtmP7N6xc6DyetfTZwwcfpds7d\BWKLDbbBncOrOuxXWgIqvcMmo4YxfBW2HiN+GQY2NkfTC8gwhOsv775xrZt21BWJt0398bJd8y4c+bLG9Z\dPTTmo4mqVn9\NqXEidMnL92IyB10evvXH\b7bTYpaamnntlzdnnn\KYjKx4BTZ5bvLyHfuefPffE+9MgiBo5fN\JDw+wP06oi4kyD9pqdUN7rZYbQwTOdQWvv6EUWgGLzTaufmvxS1NZP7oxs2bsGvb1OTHFm7eBjZAiRMm\nLMmNnPrF6+Y9+KnQeXvLVz0n1zGQK3fPnyjFVLM1YtvfTeVg68QhB04+Q7Fr3+zvId+6Y9ugiCoDV\+isW1mIJ\pwCiK+RcYYVjRIMIxuN8FbY+mdFaXgBh5rszMpSuNtI4Zh+dPRT3KH\5LnJc1985ZENW5bv2LfkrZ0AX1a0JSYm\vi7ZQDZh6dP5cArBEFjEq8D6\r9q9dCEPTMC+tEVnutyiqy2gPPKVBx23udr6\F9TmMilcQLl6NJlNUeEXYN7PmIZ20e6mC6pLxE8Zzo4rMdi16EPD6wK2kV5542+3zFzxBfZ27lj29YufB2c+shiDonZ3v0f4uGo85u5p1JSNha8TIxwrCxavX6w0hghUd8JmyZqC08xU\ljSi\z1T1ixARiTMS61uXJ9hCmVVlVHks44IrGqkIM7FyhISE59f+9IPeVmB31o5cyoTXtFo66kK0YGT5w6cPLd5+571b7yL5fjWpPuefPffdy17GoKgk1mnaX8XHsLuvLpGKid7ayJ8ghDOeRtGqtxTVvqusPbY2WIyFfFluMczr8wmqxSgWGhxCVZkmK54duXn3xxr10iNfU6h2bFg6VO4x0y6LhHwOum6RMKLDGNNtJcqEFpy+bpHl6xAH5Y4YeLCzdtmPL7k9imTcUEMtct04lTaimdXjp8w\vm1L33+zbFWdSfz8FZeYx3F7Aap0R7JSq9RMM9I0uWmgPXY2eLsKnwPM4RZ\WB+Yw0rWFGVNle\v+dfi5ctufHm4aVx\oIn5i944vfr\vzmB3syLjUIjLbWLoe82yEw2kCM6YPPvw1k8cPFD9HyCkEQWcFMLl\3q6dWoQ\75Zgx969ee2vSfS9vWI99tZ9\cyzwmrOS7l6V8uKOj\bSOve0JYqiCFZ6hXNeXIhCBDUSLTWvJ\OrA38KdvbTxgqEJhU3Xq9+sOqYVm\n8nUTA+JcKbPvzFi1dELCOGpe5yQ\RnHllc\EftgELgoba6m5hVryQsXbPjblk+\TWPlCWAVsbKZcPoDSlVIeL1Q10HN67GzxXI7vm2JxNxNDeuFBo6LK1Yqt0NgtNWqrIGZr4Fa86e\4kC548brM1YtpYYJ2Aeff8scWQiCFi9bwpxX1Cbccsurb21FbxGamUUrsTZC4diIzjsWINYfShqK+DLYwWKW1de5l2h5bdXgd6+0gS2+mp3nCiSy2tvNpNEixOOUOR0Co61BY6uCrVWwVWC0Cc0OebdD63WWNlcHInLk1wsCvxho8xc8Qf3H8IfX\oH7kWZ5O1teIQh64KFk7F2iHfWBKjKHtOGdJ391tetyZ1e1oHh9V1gbSBihGuVGWliPnS3ObxRJutzYH6Ru7H+mogTbOkDpcgqMNoHRJnU45N0EYXbAYoXCikbjsVUuzIUrLoAgaE3SDIYkHckqJyS1pNNaBVvLZNb1b7yLfTzqxeaU5DPndey4cdgbxaTAC0hm7I7AxiuMvPr9fonGKrf3FjZ1nsgpxRF2Iqe0rFVB+JtLutw1Em1uTVvahUomsGL\DAqbOpvhLqnVTb24lnW0YDHCfZprvSMgM\Y5+XoCP7WkczjPlbk+Ovopjg\azRZqTz73AiGvaGK46Uqx+G9+85vc3NyFCxdKzWq2vEIQdCI7A71RJW1tzD8JI9BiI7y88qQI9af5DyUNYF2U23vrpfr8RtHJ\GpWjBLqv4U08XCFw4C+x\JufJ2gzHl1iZU5HSWdVL5pkcRSq7KCtFdaXqVmdUJCAit6UJt42+2EzWDq1SPyWj7\5tjJkyf9fn9qaiqIxbLlddfhj9EbxaRF3FWXwN4T7uzYMPKq1eplXR5atr7OvXSqqC54RrE6VVxCAWt2TRX2Da5V4XFEM0UaGW\C66k8FXB1gaNDXgXIKQFpPcOL9XLV73AjVeIZNdVobDi\ipeeDll\79ixYtWrjkiceXLLl\Pn3AGGspG\80IorCJpU53EtsGHnVGww611BI1ktWOpFVnHGJanEtabuaiqVyExRh83Q2sm8FrwMnz3HmddXaPwdesFiC51VqVo8dNxaCoF\84hcQBG3\+CtWz7JgyWIOIa3ILLHh5dXg8jOJRrFXEcV30\JojglatAr0rSUMoNaqrGTfCokmT2O6x8LZ5GkzCC8YmIqFTSubmXQvq2e5Y+YM7O0q5DUz5xVxDYjkYQwUhJFXp9NpcPlrOnURXl+\u0jDKxoZIOsgVCazkn0rJMJt5FnZJ6d\IrxmNWwT2xwgjiEw2r48X8GZVwiCcHeM7Xz78CUVhJ1XqZnehQ2l6JyB8\VXjwlw7QKwImzjylanKkS7T5xZ\8a76994Fz3rBxnWnG39G+8SPlexBH9mMedKiuOvf5vC9lm+L8ofEatmWS0i1hrDFNsKO69a1yDbsBT+8\1C5Zmy5pP5Vbivg+SsH0oasF\85jzN4lonE6JRqmIJ6QoazOL6ZV7d33Z9DPKnfjlmzMQ7k6YmP3b\6rWPbfo7qEGY8fgSDqROv2v2\AVPYHktFFn5epvM6UADcJoeh9DsAG0SPzn90\S7ZkMQ9LddH7N9LmyIIKO8uKy9gxWviGtAqgjLxiu88SyDy693DWFPChjqVFFdWatCgFjRg9ZAPxh7dwSItbxDkV3d+EMpVWQgo7wY22MQjf+HREeyylc+\8dxCQm3Jt2XtOK5RzZsWfT6OwDQFTsPPrbp7\evXnvXsqfvWvb0nU\8mgOvuJ5whSIrNu6Gk97rFNscHxw6On\BE5n1iiB5za0lyNCgXWLDQVTY11eDy1\RoWLC6Imc0tyatkY58YAoQl5hZ3+Lxshqijs22zUkEYBTFaK\7fp4+pwHpj26CNSvgiquRzZsmf3M6qnJj028MwnXf4Cb\eG1f2CfF3ir1Pr8m2MLn3yqQGhh+1yBeVsMWxyPkCZkXdpRCxevbrdHaXQAXoX6bmpST+ZXV3TA1EkFOF6\uVDMto4go7z4TEUJ7h1lG2HFkZqy+a27lz29cPM2sIgu3LwtacVzN06+I3g6Aw2bCMvwXO2jo58u\vVTHCJor29\J\Du5dZWlwtFLRpjFJNgwsKr1+uVaS0AVoPLr3MNkZ1yfVdYWy9l5MvjeP2hlB2pw5utgJwsLdHEAVqlFwme\O2Ldy17+sl3\w1Kq6c9ugjbQSgchqa8MD8Efmfne+Bnf\HLX7J6LmyWFqGKW1oalWq0XDZiS2zoefX5fFLEgMIKFOjCfp17qaKDRYIsjtcfKYMApHe5lRf4prabCYYOUOhvuz6edM+cxW\uAF4pWVOMkNvdc+YVCC2tXfRuAKrdh\a\vGH9sdOn7pjB7kXijrgoRJ0QE\IlNvS8SpRaHKwGl78S48KeyCkt4ssCM1aplVvThuWVA6wZ5cUFLR24XBYQKGCSvVogtGTWK5787YvYdhVhQpPQJt52O7ZVNyvNuDMSvMJ2T7iXWI68ytQmg8sv01o6YV2nHFaqEL3B4PP5xHIkEFaDyy\UOVFXlaEDgBMubsWN13M8aZHEEritljroN17pRYLpcx5YuHnb4jd3TJ6bHCYoqY0s1zG6vKqcvRK1uqWtnscrF8EKlXPEShTaxrFceJUriaGkkL576OvcSyfzq3FZqsyFy0Pgxut5gRLAx9PZcDnXgVkvuFjVnfMfWfLWzuT1r4Zks481Jv1ggJ2vbeTG6+Jl7CK+zHmtbuPzBZU8XjkqQWutzDAimBDCahnWvLrdHpXZy5ZXg8tf0iJnVVYQDl4vtKhQBMvlVsRz9R1FPKQHsOlFghtuuXX5jn2gLUXIbcbjS6ibbaH2waGjkeGVdr+F6lJ9GRZWVO2SVnShDWGbAta8ihUaDrB2wjqRnHs5l9zei8v4Dp7XAqGlUGTFNpkiTHDJrFdMu+c+EKjiRCN095x5oHr2D6\9A5zNgjYCn5z+6UhWOQRBiRMmMvxLeGLlqsjwShjPYsUrj1cuN9lCvsSy4xXREOylaCVTm7xer0ar48yr0IiP4IaEVyDsJqa1a8TQi1y+bsrMWUve2knRbggckz753AuAxbf2HAE4knUVxgkc285+ZjWTvIJxCQmwg1Fzz1jgVaq7ulEJVV4sC159Pp\S6GILq1iOgNQHn88nMxPtHxmoGe4KCa+o\4pbZbFBA+yMwl89ter+1WspYL17zjzOA2CBQDD\xsl3LHlrJxPPOC07iwOvL29Yz4pX2r4EbHmVmT0hyYBhwatEDnNwA7CvUiTn2GSzrFUREl5zeRJCaLAlJejxwebte6YmPwaa\BDauIQEshpAVrp7zjwIghi6HGs3\t9w8DrxttvnPvLost88k7LxT1t3\m9aXk7wvEqQER5gSIZ4MeXVaOpiC6tCY8X9SXF2Cc6W8\G8cjovyGloJYMGVF9pvcMDXnafODPpnjmgiRqZkaX2sRVo\TLpvrkrdh6k9QqmTp\Jgdd2jfSHvKx3dr63eNkSoHd2vvf+nn\llOSXNlUDFyizqorDLaXgVawacR4UkrMDprx6vV40H4CJlEZXYLNFbi4B7OgPzEjkdh6bXc8jgwZM0dZ7nQVCS3qR4KaJt1IfXD26ZEVIYMUtsUy8AmzvlpCoXm3L7zCzmpjMhFeREt\XLPizAxb+gNHUpbX3MeRVqyWOEnNwCQKd12Nni78voskbJFRWbQMFNOBcvkBowfZRI7S7Z8\+qUMfQl6BFzt5bjLaGZPC3n6fvmkmW4ktLEY\M+RVKBfj3srgu3Kziw\IFCqGeyyyK3BwCUpa5ATJh9lFaXnF3xWVMG+dmVFefKaSyt0EA1Ve\gu+UQrObp8yubS5WtPjoEj35iAQKACzOqi9gocWPBZaWI19zksSZch57ZAJA99Nm80WOV79JOkBOFG3XWbbZ\NMWTNFLmKrxi402utkCuqGLqjyO8wU0PxQVEENK4RpsKp0hbLGC8Rix914E+jZTX2CkFklqIKtjbrhnjTBwKr3OqthG9vB3rmVJfnVpcV1pXVNl8h4bRXyAt9NcXB1B6x5pXVkJXSRNjGbVvGwoz+wNwxWJS1Xq42Vjt5yIc19JwzBonqQrpk1roE1OjwoJFq19s8QBCWteG7FzoOPbNhC8TL+tutj7A9SFBpQS+sdzvXJqqNJJi5uaamRyvkKuLGtngxQ2i0X4hqQGbu5sur3c8sfoIgVaO19tOXnNpuNOa9VQjV1rvd3hbXYx9NONTrXTBrGp61zwvVVBQom4xsn0HPzl2PGgEIaMEiD0HC7vSKJBXu2zFCIx4m2rjlbU0t937BdYGVGS0t7I2dkNVodJ1b9\pDzSru4AhOriYteAsWk9YsQ42DAzn5qjzanXkDISnqRILA\K9ZWPLuScHCcsc+JdiMM3qPFxraW79hH5siOS0jAnVPgpm3RSum6GmnObzecqaDavxLWb8kMXXxBNRNkcRuvYNIJuPDaSX5wYLPZmVxBoWIUJWi\koVIrcKmTuxPFbe0UG25KsoIQcE2qiZcWRlOOTT1O1XuoLZioJkr8AoWv7ljTOJ1hC8J15uoCsZ3eaF2A7Ce93m+jHpxJauPVTl7O2RCtsgq7D1er5cDeH5uvAaWDwwvrkqm0TWfz6ew99DyyrCw9kROKTb7m3bkcV6rBofIl3l11LCy\ajV9DgY5oATegVzkh\75ZgxoP57\tqNZBHZu+fMW\Gu6CDBq7rG7Vw3RWy63nUd6xFQ\V5KEFUTJBt72xXXSn84nzWxWW\Rba4woiG+XVoA7HYxTX9QkVmWfMlgRIot7IVN4EDW1pD20wzp6kdhwhFwHX3of3ctjJg380N2S\z6m64afyYxOtA1U3y+lfJVllg4xISfvuHdczPEXDLf2ZVBcXtyqwspe3vojA7mPgGbWKBWAVLdcZ2GcdZc6x5hRHifEKtvY\VIk89oEtquQwSXvPrhB1qO\F5b1dPCU+WfqHi2NnitAuVUsvVTtDU5d1na2qxw60JJ2FAEDRl2syCanw9LVtxbsK1+8SZcQkJiRMmLnlrJ6i8ZZIj++jjC37Io0mIwRVT5LXRzNJh2D9LYe5m6M6iamoqa2qqEgga29oEXV1dYeGVrOJFrGCxuA5fSkv6KXOmrPn0xXq13Wdw+f97KiM1NVWMWMjW9cJ68bGzxbk1Vzvr0g6HWbkmBR26Qri4PvncC5n1iiBDm0Ccu3K8tecIdGXuJpj3ybBSfF7y\JySfLLXg6ukyGlsp75XdTIFE14R1wBs97BFFsNuudvtDj2vZCmFUrmK7aXIZnYWNnXm1wl1jkFw5aKK+tTU1G9Pn\kq7b+pVxsicGcAAB6hSURBVOzgx4fOFZYiFq\B5W+Ran\MLdx\6LP\HPuytl2KuAZaNDSni\u+ShuXkLD7xJn0IsG4kQ2EJ952O4oySCoIRkG25ACr7JjE68Dk7yff\TfzEbWLly0JnCau6RnxevI7zGcqy6nvFe08I6yUVpegtZYbsjxeQ4h5NZtJFzkOo0QDd11Sy+WiZmluZevVD32jO+2\p1ID7JNPP0tNTd23\0CHwniusBT9+v6PDirtvUpHL\V78MOlUgiCxiUkPIYZ4zZ52ow\b\sA6yoUXMnb4izqsjCGviz4BLg16T7gzjJvZzR+wnic\41rbH+eTzOVhEMnItju4YysVkvzKc2OV6mcOH9AaXSxhRUYdkZXq8Z+Mr\69MV6dGXtUBg\3LMHR+qRYyekOofB5ZfqHD+ePbdv\4GqxjbsAzLzSxC6eRsZ5cVPrX4egqD\+Z\gSBo+l2z\7brY8LMa9ALNiqLK1abt++54abxEATNeHzJ4jd3sKokW7xsCRhkENjijvZYi0Ont+CQpVliWfJKEsmiSHChNqfTCUhFM1wlehcK6779BwJX1tTU1LT\ntLafeBhAon68Of\OfLFCfS7ez\6uKIDpp1ndDwrB4KgSVOnk3VURaVyc\RiQ3j0VSC0ZNYrwIEtBEGg5yF10ABrM+6cWSNqxy32tMcEGXSRLArJjBYOviwM08QNqHh1uz16g0EqV0nkCBmpQDKFii2pPp9PbzDIFKpSnhQNS312\Jv84oq8ovLvM7IOfnwoNTX1s\8crRNIwKc\1s4VlmJ9hgsXy7Hf\fzb7OzqRup3IqO8eNPb7zOpZuG2xIap43F6kWDNn\4K1lpWNnnaDFw1RE5DK9mdOZGdsevwx1\lZrLtVDzCu9Pp2W65aGtmSHlFuwsykZ5xP2Wz2dIph8UKDVoUrjR70YwWvqILsXhLq5vzisrzispLq5uHN3M6B8AXa2CzBVTDE+7bvx\91sdHv6EeuQFEkb4d\BIbvnbyYK19a8+ROeSFZYQGtpjDiyv5Tit54dUhYTePn5CQmFhYw+eGbLuklTmvra18Wn5Cw6tSpdYbDIGCEU2nHO6Uw52wTqGxkv14MV8GDgUonqJOIMHxyhONcKYzc\PBPux07sX0giJaWDPKizMry\LaGKVdszo9Ct\iSgju5u17fvXUqnvuY9T0feJtt6cXCQqEFooEwn9+mPrAQ1cb2GxP3ct5iWXlyFqt1gjxGqSUFu+xs8WnL9YTfhexeE9n5u7evRvHa\aFi9iHKYxuQHC9RM28uiu7rokJFqxO58O9uBLK1O9slreDIq0Vz65cvGwJWQ+iSVOn7\4y81+fH951+OMDXx8P9ATW\WXTpCmT0cf\+5PPOPMKHFkmsDY0VNLCGiu8Glz+nKqWzLLmwK\Xt3Tu27c\lcjS\nsq8PE65+D5uhqGsAIRFnkHw6uxL5SL65d5daChAWixQfiYkk7Sl3cy6\SGN7YBzyFpdtLCxQvXbVy3fdf27bu2v\nOm2tS1ixcvHDeg\MW\3rZur9sOvD18bS8nDXrR0xP3n3kc+ZTZIm9gs52Wl4lEtFo4lXW5QnktbFVhl1WP\vPUWyo9au0\wZep1ZCExYI1NnqauqigwKhpUHDwh9g26CTQqcqRNRZjhNvu\2T0z8Viqy4dmDtGunmra+Dx8xLnvfq668eTT+6fdf2NSlrsNrw2obUj1LTM9LTM9L3frp3TcqaSVMmP\jYo+j1wSyu4paWYHhVWl24Hls4NTeXMTzMjxVeDS5\qUCO\W8HbPpwz16A5pFjJ+oEEvB1cDwLXFXcFcR6O1tYgQIzYDjzKnM6Qri4Bo6gJ7QjWeXYc403\99bCYmJY8eOXbVm1fsfvr8mZc1tk26jvsJtk26blzxv3cZ1c+bM+emnn6ZMmQJB0Iy7Zv3zw1Rwi5gPPiYUXdphLRNYY4tXidGD\e+xE18DKHH7qg6FkZBXrcN3jvEUgwCVXGhBKLhh2Hg1tLBm1iuoF1dgIHcbzAuXmtWg9VDS7KQ1KWvmJc9jgjvWUlNT\X6\QSbdv3\nDlzZj9wP+hNlFV1ib6bNrkU5m4KXjulktHH6wj47L7dH36YmppaVEGwCUOX2A6FEf1iswLhCmtxRnnxmcoKCq+ACa\y7lDCynxxBXMNalXWZnn7vOT5EARdf8P1199wPVtSgUkkEq\dVvL2lpaWlsTE4dnhyQsXHPnxe7aDDpl7sfwWXkR51dr6pIgBhK60Wj0az0LDv+DoARwQSOQwdrrBiOs4h09ia3hCQCQ4esVJqnOgR1\Hv\wGLMCIrTezsjQYZCliBdg2hoRSuR0c5iBQi8niCkEQCKnmt+oJAwKPLlkBms+9fzjt+VfWYwNVgTZr1iy\39928oQ489SiRSOqxyZNmXzoZBrDSRvEgQJDF+lJAa86orwaTYySF3HXV6qQTlg34lLdw\48ey5wIgVVo3tcuwJAjju4rDZwomsGpF6xEU4YCXLysXZxNtuB49\8jn82O+XN6z\rqgefDevTZ9ZVYn+muv+sumGG28MvNp7773HO3qo6O+bjh8\HvjdcQkJuWW1nHlFXAMt5LW1TJIJqXj1+XxKFYI9iKKQXMl9xK3T6RQrNGjnGF33oMHl\+TTz\btP0C4uGJ9hryicpTazNx8nXMwo5xLU50RyPKkgfRQFEyHA9YCunoy1GbPfeiDz7\Feg7jJ4zfvPX1OpkUzRbI7zBjy19f3\4O2dX+88JvMlYtrTq4G\UEcJaQmPhtTgFnXkWwgoxXKTMXllG+i1arl8gRirYDnezzB3BmNltAZi1i8SIW74d79jS2y2n\ToA6FMbC0ursvIvfZeTQDufmhizZ4IAwwXqqQoTLyiWzlE1\v3nireDfN9508+5D+xthBFs6lt9hzqq9mqr26ltbyS416brEjFVLM1YtfekhqhTbYI5n5SYb+a6rngkn7PKzJKErLgg0MGJOYXT\54vj5fUtzL0RoIqmji9O5Rw7W3y6JATI4jpvEuYPhAnWAqFl8\Y9TGCdNHU6+u9Zsx8o6bSi\QSG1WHCwkqxskIQtGrWtIxVS3ctepD2eW8eP4EbsipnL1kgtrGpggkkoemvrbX3cUIUb263R6a1aO2+Dg1xzRaZFF09py\Wp12oPFVUVyGUBc9rxshzL00PAa+cK2BpBUq6ae2ZF18B\yBsm4xzA3Z8tJf6au88+kD607+akDCOyVNzRpYiSmAw0E+SYcerz+cja1HIYctFaKDfkdx0+adGifpKkiu1GiR6MD8x7UJlu86J0LUgYKgzFSXn+XLw3usDpnaFMBcbp8x6BUNn4LV3d0MQdPvUaYG95\Pa9Gdr6tHf5dNv0wg3WFhLf\pXi6dOwn5lwi23\GPX+9NIZs1NmjylRqgg41Jq9mzbsSvllY0ZBWXYr4tVMBmvbW0CWjxY12+RJcJ2hqhBvd\vN5stWntfZYfqu8JasuJYdFnNvpLo\XXuJXRYktjkDMkSm1FefJ4vKxBaAhfXBk24MloYjn+fk\xYZr1iTvJjgVc4L1Bim7mm5eXMuoemDfKsm294\cERGV5jx4378IvPa6RyqdnzwINUUbCke+csWrps0dJl23bs2rZj16HjaRkFZQt+9URCQuLew1+0a60Mo1qNjVW0bLDmlaylZkhcWNSkcpXWMQjaFKdfqDhf3d4sM3ao7UB8RVdhvRjbguBETilYWVHVSOUX+fwaqRyrFo2xXW9t11sv8vnMkc2p5xt6R8Sz9OFMF2QYGXho0ZN\3vZBYI\v3CZ8bfCCJYtpr7Zg8q03jB3RleOfH6bmNdahAdftqTTuBI7glzdsWrri6UPH03BuA2zvoTjook0pZM2rzUa84CmNrpAMVAAGZnvUSXRM+rsEtiRiItqab6xKWpsQd1c4MlrwtPF1DJm4\6EFEAQdOHnu6o+P3F0BHfiaIJIaaGNHDkRe95dNGeXFQqN9hOuptW56g6Y57qTJUw4dT6O+8xRRWB6vnMdrcDodZGBw6UdEFtgK7aRQpQrRu\zUzV8JWxQyV5WE3c6sQSkCvJbJwrW4phcJmOAF+hOuf+NddJt1ni8nbOi+46O9Y8cx2kKh9vuUlyluWo1QkfLKxpvHT8D+SNK9c7an7qVwZ0dwz6jogJhaLryStczohLn3SQw0r9erNLqEum7q\q\HzhZXCdXceEUYNNvCqaC5rtUQ1AAjap2qEIFZBtT21p4j6I\ktekpGmCdyM5gxevDCx6XMp4xUVjDZ\5gVEJFJwNeianlwivF1LhQRQmAgfLxn5o7KWBNu1AZzJhPxDXQrNKyTTzIaWgt6DCFj9oPPv+Wglq0mWZ+u4GiZhBoVcqLzGGdPnNWs5z7WD+GkqjVjHkt5\HKsUhw4dXt9pDxyrD\K0MDvrK86zIIV9H21+asVl0Xh1yZrNqGvDZt5Kl98rkXAKm01djfF+VPuOUWhrDePH5CGY9g4kDIRREiCAuvZP6AgVl\bebm8\lA9kJdJ+nGCxcW4CyxycktvetsTS2IeUWM2g8O\4eWVKBdhxmFxoCNHTt2waJFew9\Ee4lVml1MYe1ubkMi0TI+hOGaYlFT4BPFdUHwnqqqC6E9zGYdMQzleU5Da3hW24\+Cz95ddef+KpFckLF3xflM\wVa37yybmvL694+30jPQtW7fMuvvubTt2cXBMGQq2e5jz2tR0CcsDO16ZDJNXmb0cemmRmd4wfDwhItp4Ydu+BimJuZszrFhlVlXl1AvO8aQhYLfDdKFFldvUQTtcgEzLfvMMc14hCFq4eOH7H76fnpG+JmXNzLtm0UamYp1X6i4vqGRqU6hisdj2yBebpDhesT1fg1SrriskvOK9herq3KaOCy0qhvheaFHl8iQ5Da1nqznX9lzVHTNnkH30U1A7c9bMvZ\uPZp+dOHihctWPos7oIowr7g6bxa8kjV7I0Y26AxD1NBiBNjSi914cQ67EoptYIubzlSUna2pP1tTn1XXnNPQktPYDv7LbXYrrchyBtakrKFdax9e8PDeT\e+\+H7c+fP55xASCiGHQmAcE1fWMw7Zj6ME2y8mDcpojbsXHDsiVd+oyiEN5F2cNeo0\dF+YQgjp8w\mj6UVpewTKcsi7laPrRNSlr9n32RahudadGy8wTKEMQFQ4Gpry63R5WvIIT2pDECuTKEeGIvDoh4LVGElSFMU7n6uqiTlho9em3aWQLZ+pHqUx4Rfnevmv72zvefvq3vw9J6IDJeUFzczVhhQwLf4Dh8NgRXoHWwnlyDWq44wndlTyYZrgrVLC265w\lHEZoBzL2rrzfwn5W7dx3bqN6yAISrp3TrNctz1176TJU2ip3fDahsMnDs9LfojhoSuFWoVN1BsskaiDDAYWvPp8PrK6VgpJEUOQyKIhApxXgGYPBilJlzvtQmW46Ym8yKoJDh45CPoSHEk\jd6EQ8fTqJMGIQhatWbV4ROHkx95NJgdmMrZT+WtCnlKmCoeyi4+EIgOM8fAEQyyhJW6Z0uDqoW\+tlk7D6ZX\1VbvTxCrlSNv4pkLmZs2amZ6QnzU5KSEwMjLBmFJQtW\ksBbLLVy7fvmv7oqXLON9w6sYZcpMNRqimH4ZsPkxYHYPAoG97Jywdme3GGdZjZ4tP5BSfCkXVV0yJMHNg1ZpVez\dC0HQpjf+QXZbynjClFc2JpCUyAJ3Yu9hjtsvis2WoLUWcQ0oVFS11qx5ZXJkQIys2sQZ2cC4b6ccNppMTIYkkqlRbsSlJaTnF\3IuBFnIa+5XW9tUMCsUr+DV1bVpZK2tmaVtkVjPF9PdY6weMXyQNpAO62ExETanVOzXLdtx65A13bs2LF7P927YNEibgdgFI20hIrO0PPq9\uVKkSKGFCJFcNNiWm9W4XGyu3oC99Ww+VXqhA\+UQkWpW1KohHe2YXffsTDTGZFaW4kVSws79FYywXiqjn1AWjvMa6KokMl0ANO\spUngDW7mMnzD+y++\nHrHVIrFFSep2XPoeNr0mbNwTsWWrVuYXwQris2W3GQLC69k5vV6aZFVmb1KyhdEaJKACcvoRYSIntX9gh39JS1y6oTar3KLz5D03ciqqhBS+iFSq7tRqS5uaQmyORJ2KaVuvyo02rNrCPaLgZlZa1LWHDxyEIIgDvH\Z3434ojh7R1v33PvPWw3XhSNNfmC4cFJ1PknoeTV7\d7vd7AtTBQEqWWlW8QOBEc5dXt9sgYfzCBkUm0BQtny\mwo79OpsCNpi9r72A1f6JV11Up6qSeb0+oSlEn9V8FngNHb2B5T6AzcPjE4ZR1Kc\8bg2HdRFXvzVz1swNr23YdeATVheh6O+CDvAWy6lGxISYV7\f7\P5mCCrNLqYn9nijgywvPr9fkRDf3DQrnNeqOtgUgp2qqgOTQCX2y6D0vCsqkt8lgs5KmbF5VcHLmRVXeL2RK26LrDQZlaWfns+Dwdr0uyko+lHx08Yzy3JtVmOLyxbt3Hd9JmzWF2EonJLZrREh1c\Y2RBqEuuRGiTY5QqKl79I+fO4SS1XCbzVglhxY6mRzkIpiF6nUzBanHlNqIN\QOrFHXKbZczCspweG3ZumXdxnXLVj7L+eK4AO3UO6bOeWDOVz9kM\xxikgWX1CNjpqPAq9+v9\n8zFM5gJOrUQOUxzearV6al59Pl\g9ORGuREdQ8cZ1uBFO8wWu7hmlBfzVEGdeR46nvbM79bg9vVPr3r68InDY8eOxXWvYKVdBz7B\Q3MeWBOyisbGf44RWSgQ3Z1yY8Or36\v5PT+a1ShZjNFtylAs8pAjdtNpsNhLfadc4ivgzbnYCJTuZXhwNWxDUgt12mhHXEOfCZ8mKhUsHhWaRmz97DXxCeUd026bbUj1JnzprJnC1CtWutgUHZqdOmM\lZ6tHdLW310edVoiQtS6SVQmPtVKiUKsRms\uJjrhwvHq9XkSjbVNq2WKK6kxZaA7MCEW55RqxuJ6vKuULKlUs2wIX1vCT7p0TSCoEQWPHjk39KHVe8rzpM2cFXzLw+5SXA6\PxCEWKWXUCS4yQ1eUeeWQbEC26EoRo8E94otihbZTDoMAsExtQr\Oh83ceP2hpCF8vFKeKYzgtaSulMcrlyAqhlfOKCh7eMHjhKRCEHT9Dddv2bplXvI8zu3ZAv8wAp+F9qxL5eylnRrX3tkeZV7Z5h+GSpUdKg68nsxnPTiduSpFnYSwninHJ4XVNV0Cn48qJ71zcuh4GtmpKYD1\Q\ff3jBw6GCFShwiaVNJ6BdXIFgew8SyfMCrFHUfEdA52raYopXscmJ9vD6qaHmfFXp+arSc1Wl56pKwL+B8qtLA9cbQknNHlwAn3BlnXrH1IcXPB58BiBWzXId7o\k5vETKDwNhbmbevgWKhGsQFwDIc53YWhGU1cUedU6Bn8oaWCLbPh4RQXbexi+eej5ZKDatVbqLKqpd0ydlzwvITGRbTyfoV5\ezvuGSn+JJiPPBa01qqc\TrKspRw8RoYMQ2x3DQPUFq8IK07pnhl+MmI7poDvYJ2rZVsawVB0NixY6+\4fqJt0x8\e3t4WsjIDV7cPEysjkcbFu5SHVGm80WBV59Ph\DeBbF3O4g1a5x0PbewipUCeBkYrW4knkF1CvrAw8mR6DhBeIa+DanAOsVbNuxi+j39bD9fdvEAuqMqDDut\x+v9lswW7e8Z\a9j5wJOv1emFEI5YjYORGSJZYmdbSqVC1SZWIa6BGoqXoaHTsbPHXuZdC2MqATBStpSkkVl19YYERewiCJk2esmjpslde\Wtoq1hphc0oCMxJUDn76fpmEkunp+oaGF5egUnlqsBYgUJjBbFVnJnNFqlcRUE5hVRmr1ihUaoQ7FGZUIEgrgGp5TJZa87Cps4wnRTgRJ1aTyEQmzx3qQ7tE5+QmAj6WX\1Q3b4GrHQCnVkJ02egvsW3cBYYjU1V1AP4ooEr36\3+l0YjMKJHKYNmcALLoUQ5QMLr8Rc8HAUzFgPp8PzTksa1VgPYQzZc1CY3ck32Amk9UJte\QIUDGK5s2R4vOQEnNnpRXNoIXNvwLaq3V7XKhXMzt12zr7KSmIkK8AlOqEIXGqtXSjwFBLTDzdYS6h5dVavq9Xq9EM5ypKTR2nyqqO5lf3SjH5xtEQJyX2PqGkid\vYLwkzfqAsii9Qh5RfkcYRULhAqa3OiI8srBAjMJAyWW0yeAO51OtN4LdvQH2TI2GHFeYnm88o2v\SXwkzcWtG3HrqUrVkIQdPCTA9x+Nb6gErZ7qA+3\LHPK0UcV4\u25gt2FhkoyuFuVuqM4pVcJtYQHtQiXtT\zc1NeQNrUKi+x6Y+382rOf8pyhRqxG6wwJ\7POK7fdGGBygdQawFjvIYqVy9spNNgmiEsrFFElMqKQ6jpnj4ZPC3F1ccp72lQtaa9vEApxEsALNlzCaTNTvYKzz6vfTBGjZzlGy2WzM62ei8sYzQbZDJmSSYBAZSdRqJp8SLW31sJ3mztNWSY0CXjsVKpCHdTVWgIm8wgjruV9msyWYQvAIIMskcskXVJMd2EZMsN3TKuQx+bhnAqvMTN9tbRTwGg7TaHWxjCxs9zAMtrd3tkdroZUgKiYfBQxhRVwDQiTU82OvJYMR7lOQYgpZvqBaBCvgCP75SXX6NrGA4UaKIawIXeYrsJ8vr36\X6FCos5lSJDl8cr5gkqRUhZWalXOfqlOz+qUlTmsiGuAOjML2M+aV7\fDyPqWHYMOJwvtAqbQh5AkBktHTIhq9AbW1hlZg+TOM\PnVe\36\R6mI5YsCWV3S57ZAJpTo95xVX5eyXm2xCRWdLeyO318BqO0h7sgUszqvfD\LIYhVZhnsayhWXJ5SLJWq13GSjwBe2e+Qmm8zQBQ4y2KYCBor54oq4BqQKRmOw4rwOm81mi8GjBIR+mjWXpbdNLBDKxSJY0Srisz1jYy5WvyZ1mjZqcV6vmtPpDGy6EXUxDHDGmrAtBWjFJJIFLM7rCPN6vbGGLPP6J47LLT8sl20V8pj\jrRpA6jFecWb1+tl26MzrOKcSxpdYVsMUUth72HerDLOK4H5fD4RrIk6qUAUPShjeYkVKWVM\yAZOwP+OK9k5vP5QCFN1CVBVEz4aBU2hWnbxE0gP5CJZEoV8\clziuVce43H0IpzA7qkJZQLlaYu688uFuCqDhs0ZqbKRdgQTUazQWnXLRPgfZzpfnt7D2shgrGeaUxo8kki2yNV6Bge09gVYKgtZYibUDl7JXqjEK5OJhFt1XIkyAqhdlB+BRKq0uo6Az8W2oV8sh+JFAMjwlQi\NKb16vV6iMfnKMzGgBsdiW9kapTs+8hyFYdJkfUwnlYqnOyDDtC7vc8gXVzDvVAZFViZJZnFemJiFv4R0xqZz9zJcunBh266Du20UhpdXF9uxXrDayfRfivLKwGE+OoRVFdyDUf0Vd4QhIo6VqjUFocV7Zmc1mQ0vDR51Uzn7qWcOtwqZQ4ugeMF0eNF0etPcOOvuGcNKbrTAMwzCs1+sNV4z2\sd5ZW0+n08kj4lQFwfJjBaKxRVtcs1Kes+A1Tvo7BvyDgz1DgwFeXv7+vpUKhXZd+O8cjSZUjVKfQOyBgignSWTK5guDzr7hlz9Q96BocFg+cSb1+ulaPkW55W7mc2W0egb4DZe6OJKHeE3eAadfSFYPmlNq9VSfDfOa1Dm8\nEMXCmwFadGi2m\F8p1enlJlvg4qp1D1i9g+7+Id9ghO4nDNNkwcZ5DYEZTabYzJ3lLEvPoKt\KOxr6UjT6ejDBXFeQ2Ner3f0bsJQadwD9t7BiK2mWHM4HEyytOK8htI0Wl3UD2+5Sese6O4L\eaJofX19VksjA664ryG2EbdQqt1D7j7o8TpFUMQplkEcV7DYhqtLtbqFAKlcQ84o7emoka7x8JanNcwmkypiln3wOodjDqpfr\fZDIxby\pj\MabvN6vRSz7qOlrp5B78AQodz9+INTJnL0DoKj10BpnJdhFWIgMeaVMMDivEbCjCaTWB3r7kGYxCGphcLivEbOYtk9CJOoh8FysDivETWfzydVwDHbSyaUpNp7QruyAovzGgXzer1iufIaplZm9oQDVn+c1yia1+uVyOFrz0MQq2lmwAZjcV6jbwoVcs2kHwgVCKv4FFuL8xorhmi0sdOkg4NkZg\DHoPBWJzX2DKn0ymSj74NmQjWsGojwNnivMai+Xw+GFHHSIMZaom1Rubd2oK3OK8xbW63R6ZUxWYqglhrZDJxILQW53V0mNvtUaiQWGjbgbgGhIge0VBVrYTP4ryOMvN6vTCiFsnhyJeOyYzdQgVCOzIzrBbndRSb2+2BEbVYDoc1OUGsNUoVMEXNaiQtzus1YmDdFcuVYrlSqFRzjjDIzB4hohciepEchhE12\ypcFuc12vZjCaTzmAY5lgBAxBxEitgqQLWGQw69tl9kbc4r3EbTRbnNW6jyeK8xm00WZzXuI0m+\8gZ08fpVj9RQAAAABJRU5ErkJggg== (El nombre de archivo, el nombre de directorio o la sintaxis de la etiqueta del volumen no son correctos)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(Unknown Source)
at java.io.FileInputStream.<init>(Unknown Source)
at sun.net.www.protocol.file.FileURLConnection.connect(Unknown Source)
at sun.net.www.protocol.file.FileURLConnection.getInputStream(Unknown Source)
at java.net.URL.openStream(Unknown Source)
at com.lowagie.text.Image.getInstance(Unknown Source)
at com.lowagie.text.Image.getInstance(Unknown Source)
at com.lowagie.text.html.simpleparser.HTMLWorker.startElement(Unknown Source)
at com.lowagie.text.xml.simpleparser.SimpleXMLParser.processTag(Unknown Source)
at com.lowagie.text.xml.simpleparser.SimpleXMLParser.go(Unknown Source)
at com.lowagie.text.xml.simpleparser.SimpleXMLParser.parse(Unknown Source)
at com.lowagie.text.html.simpleparser.HTMLWorker.parse(Unknown Source)
at com.crc.tecnatom.gaddie.reports.ExamenInforme.imprimePDF(ExamenInforme.java:61)
at com.crc.tecnatom.gaddie.controllers.ExamenesController.descargarExamen(ExamenesController.java:114)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:213)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:126)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:96)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:617)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:578)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:225)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:999)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:565)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:309)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Here is the java implementation of custom image tag processor:
package com.example.itext.processor;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Element;
import com.itextpdf.text.Image;
import com.itextpdf.text.log.Level;
import com.itextpdf.text.log.Logger;
import com.itextpdf.text.log.LoggerFactory;
import com.itextpdf.text.pdf.codec.Base64;
import com.itextpdf.tool.xml.NoCustomContextException;
import com.itextpdf.tool.xml.Tag;
import com.itextpdf.tool.xml.WorkerContext;
import com.itextpdf.tool.xml.exceptions.LocaleMessages;
import com.itextpdf.tool.xml.exceptions.RuntimeWorkerException;
import com.itextpdf.tool.xml.html.HTML;
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;
public class ImageTagProcessor extends com.itextpdf.tool.xml.html.Image {
private final Logger logger = LoggerFactory.getLogger(getClass());
/*
* (non-Javadoc)
*
* #see com.itextpdf.tool.xml.TagProcessor#endElement(com.itextpdf.tool.xml.Tag, java.util.List, com.itextpdf.text.Document)
*/
#Override
public List<Element> end(final WorkerContext ctx, final Tag tag, final List<Element> currentContent) {
final Map<String, String> attributes = tag.getAttributes();
String src = attributes.get(HTML.Attribute.SRC);
List<Element> elements = new ArrayList<Element>(1);
if (null != src && src.length() > 0) {
Image img = null;
if (src.startsWith("data:image/")) {
final String base64Data = src.substring(src.indexOf(",") + 1);
try {
img = Image.getInstance(Base64.decode(base64Data));
} catch (Exception e) {
if (logger.isLogging(Level.ERROR)) {
logger.error(String.format(LocaleMessages.getInstance().getMessage(LocaleMessages.HTML_IMG_RETRIEVE_FAIL), src), e);
}
}
if (img != null) {
try {
final HtmlPipelineContext htmlPipelineContext = getHtmlPipelineContext(ctx);
elements.add(getCssAppliers().apply(new Chunk((com.itextpdf.text.Image) getCssAppliers().apply(img, tag, htmlPipelineContext), 0, 0, true), tag,
htmlPipelineContext));
} catch (NoCustomContextException e) {
throw new RuntimeWorkerException(e);
}
}
}
if (img == null) {
elements = super.end(ctx, tag, currentContent);
}
}
return elements;
}
}
Following code snippet registers the custom image tag processor and coverts an HTML document to PDF
public static void main(String[] args) {
convertHtmlToPdf();
}
private static void convertHtmlToPdf() {
try {
final OutputStream file = new FileOutputStream(new File("C:\\Test.pdf"));
final Document document = new Document();
final PdfWriter writer = PdfWriter.getInstance(document, file);
document.open();
final TagProcessorFactory tagProcessorFactory = Tags.getHtmlTagProcessorFactory();
tagProcessorFactory.removeProcessor(HTML.Tag.IMG);
tagProcessorFactory.addProcessor(new ImageTagProcessor(), HTML.Tag.IMG);
final CssFilesImpl cssFiles = new CssFilesImpl();
cssFiles.add(XMLWorkerHelper.getInstance().getDefaultCSS());
final StyleAttrCSSResolver cssResolver = new StyleAttrCSSResolver(cssFiles);
final HtmlPipelineContext hpc = new HtmlPipelineContext(new CssAppliersImpl(new XMLWorkerFontProvider()));
hpc.setAcceptUnknown(true).autoBookmark(true).setTagFactory(tagProcessorFactory);
final HtmlPipeline htmlPipeline = new HtmlPipeline(hpc, new PdfWriterPipeline(document, writer));
final Pipeline<?> pipeline = new CssResolverPipeline(cssResolver, htmlPipeline);
final XMLWorker worker = new XMLWorker(pipeline, true);
final Charset charset = Charset.forName("UTF-8");
final XMLParser xmlParser = new XMLParser(true, worker, charset);
final InputStream is = new FileInputStream("C:\\test.html");
xmlParser.parse(is, charset);
is.close();
document.close();
file.close();
} catch (Exception e) {
e.printStackTrace();
// TODO
}
}
It's possible to replace the built-in tags processors of iText(Sharp).
Here is the C# code with custom image tag processor which supports base64 images too. It's easy to convert it to java (base libraries iText and iTextSharp have the same API).
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.html;
using iTextSharp.text.html.simpleparser;
using iTextSharp.text.pdf;
namespace CustomHtmlWorkerTag
{
/// <summary>
/// Our custom HTML Tag to add an IElement.
/// </summary>
public class CustomImageHTMLTagProcessor : IHTMLTagProcessor
{
/// <summary>
/// Tells the HTMLWorker what to do when a close tag is encountered.
/// </summary>
public void EndElement(HTMLWorker worker, string tag)
{
}
/// <summary>
/// Tells the HTMLWorker what to do when an open tag is encountered.
/// </summary>
public void StartElement(HTMLWorker worker, string tag, IDictionary<string, string> attrs)
{
Image image;
var src = attrs["src"];
if (src.StartsWith("data:image/"))
{
// data:[<MIME-type>][;charset=<encoding>][;base64],<data>
var base64Data = src.Substring(src.IndexOf(",") + 1);
var imagedata = Convert.FromBase64String(base64Data);
image = Image.GetInstance(imagedata);
}
else
{
image = Image.GetInstance(src);
}
worker.UpdateChain(tag, attrs);
worker.ProcessImage(image, attrs);
worker.UpdateChain(tag);
}
}
class Program
{
static void Main(string[] args)
{
using (var pdfDoc = new Document(PageSize.A4))
{
PdfWriter.GetInstance(pdfDoc, new FileStream("Test.pdf", FileMode.Create));
pdfDoc.Open();
FontFactory.Register("c:\\windows\\fonts\\tahoma.ttf");
var tags = new HTMLTagProcessors();
// Replace the built-in image processor
tags[HtmlTags.IMG] = new CustomImageHTMLTagProcessor();
var html = "<img alt='' src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAodJREFUeNpsk0tME1EUhv87UwlCREhRFpi4cGMMRrTE4MaoxBhAsDyMssFHfCQu3BlXGuNKNy5NmqALoqEEMJWCgEUjYojllSpofIUNBNqmIKU6OnQennunUxvgJF86957z/+d27hkGigMlDJfOAmV7AcYsKGqIZljRSvhNE+CMTwEtXmBy2gQb7mCQJUBKkTIQYtfJYCNMAxO9hzq5CYmFiWFY6ISE9VFLRedc1SONeqwf+uJLuKreNPI9nltbLG0orhpqUCM90DRVoEbJ5MSLho1MMg1O0bHOuyoD9crCcxL+xa0HqwL+rEQHsb/CW89reO1aAyEuq+yp+zXvg66rgng8LrDXSmwYpUc8dZkmDsJNL+NCeVVXbWK+O32cpJ7E6OgkwuEwrl8phaHrVsfYD+x03XTPjN3nzZnD0HGxvPppTSLcLwo0I4lldRFK8jdCoZBlJquAbBnr0BD9GUTRvubahclW5qDukqkpIqlodGQ1At3UxZXaIUvauqsyjBV+jZJEJ3s83HO5j+UWI7E6C4mp2EQCTixyV2CvbbKzNmN2zNfHtbzPM3p4FOy/M5CXtwsOKZmmsOi2IHMvyyFhJhgY4BqutQ/aRRstocEngZzswnQnO+x1lqTjy8hIgNdyDc+x5nomxrKJhpcSp2lSrx48WlZhGArynG5hsLLoE7/jQ59f0aR7ZBkdbf7U6Ge+mKYaBvdx8wwZXjtWvfswfTrp3Over29J8NAXYO1t/v/7csZA5U5/Q35nH+aKt8OMR2POPSUFOyRmorvje3BiCt4b9zBANTmwGvP/aMoZRluJbURB8APmnPlQliNLzk8flxbeh9Du8eId5bYQ2SnxH36b/wQYABNFRsIaESsTAAAAAElFTkSuQmCC' />";
var styles = new StyleSheet();
styles.LoadTagStyle(HtmlTags.BODY, HtmlTags.FONTFAMILY, "tahoma");
styles.LoadTagStyle(HtmlTags.BODY, HtmlTags.ENCODING, "Identity-H");
PdfPCell pdfCell = new PdfPCell { Border = 0 };
pdfCell.RunDirection = PdfWriter.RUN_DIRECTION_LTR;
using (var reader = new StringReader(html))
{
var parsedHtmlElements = HTMLWorker.ParseToList(reader, styles, tags, null);
foreach (var htmlElement in parsedHtmlElements)
{
pdfCell.AddElement(htmlElement);
}
}
var table1 = new PdfPTable(1);
table1.AddCell(pdfCell);
pdfDoc.Add(table1);
}
Process.Start("Test.pdf");
}
}
}
the solution provided by Ajay Deshwal is a very good reference point to work on .png Base64 images in iText.
all i did was to goto my HTMLWOrker and edit the method startElement(String tag, HashMap h);
at this section of the method, if (tag.equals(HtmlTags.IMAGE)), blahblah.. just add anther check
if(src.startsWith("data:image/png;base64")){
final String base64Data = src.substring(src.indexOf(",") + 1);
try {
img = Image.getInstance(Base64.decode(base64Data));
} catch (Exception e) {
throw new ExceptionConverter(e);
}
}
Add the below width and height of the image in the above code of Ajay Deshwal which is working perfectly for me.
package com.example.itext.processor;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Element;
import com.itextpdf.text.Image;
import com.itextpdf.text.log.Level;
import com.itextpdf.text.log.Logger;
import com.itextpdf.text.log.LoggerFactory;
import com.itextpdf.text.pdf.codec.Base64;
import com.itextpdf.tool.xml.NoCustomContextException;
import com.itextpdf.tool.xml.Tag;
import com.itextpdf.tool.xml.WorkerContext;
import com.itextpdf.tool.xml.css.CssUtils;
import com.itextpdf.tool.xml.exceptions.LocaleMessages;
import com.itextpdf.tool.xml.exceptions.RuntimeWorkerException;
import com.itextpdf.tool.xml.html.HTML;
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext;
public class ImageTagProcessor extends com.itextpdf.tool.xml.html.Image {
private final CssUtils utils = CssUtils.getInstance();
private final Logger logger = LoggerFactory.getLogger(getClass());
/*
* (non-Javadoc)
*
* #see
* com.itextpdf.tool.xml.TagProcessor#endElement(com.itextpdf.tool.xml.Tag,
* java.util.List, com.itextpdf.text.Document)
*/
#Override
public List<Element> end(final WorkerContext ctx, final Tag tag,
final List<Element> currentContent) {
final Map<String, String> attributes = tag.getAttributes();
String src = attributes.get(HTML.Attribute.SRC);
List<Element> elements = new ArrayList<Element>(1);
if (null != src && src.length() > 0) {
Image img = null;
if (src.startsWith("data:image/png;base64")) {
final String base64Data = src.substring(src.indexOf(",") + 1);
try {
img = Image.getInstance(Base64.decode(base64Data));
} catch (Exception e) {
if (logger.isLogging(Level.ERROR)) {
logger.error(String.format(LocaleMessages.getInstance()
.getMessage(
LocaleMessages.HTML_IMG_RETRIEVE_FAIL),
src), e);
}
}
if (null != img) {
String width = attributes.get(HTML.Attribute.WIDTH);
float widthInPoints = utils.parsePxInCmMmPcToPt(width);
String height = attributes.get(HTML.Attribute.HEIGHT);
if (width == null || height == null)
img.setScaleToFitLineWhenOverflow(true);
else
img.setScaleToFitLineWhenOverflow(false);
float heightInPoints = utils.parsePxInCmMmPcToPt(height);
if (widthInPoints > 0 && heightInPoints > 0) {
img.scaleAbsolute(widthInPoints, heightInPoints);
} else if (widthInPoints > 0) {
heightInPoints = img.getHeight() * widthInPoints
/ img.getWidth();
img.scaleAbsolute(widthInPoints, heightInPoints);
} else if (heightInPoints > 0) {
widthInPoints = img.getWidth() * heightInPoints
/ img.getHeight();
img.scaleAbsolute(widthInPoints, heightInPoints);
}
}
if (img != null) {
try {
final HtmlPipelineContext htmlPipelineContext = getHtmlPipelineContext(ctx);
elements
.add(getCssAppliers()
.apply(
new Chunk(
(com.itextpdf.text.Image) getCssAppliers()
.apply(img,
tag,
htmlPipelineContext),
0, 0, true), tag,
htmlPipelineContext));
} catch (NoCustomContextException e) {
throw new RuntimeWorkerException(e);
}
}
}
if (img == null) {
elements = super.end(ctx, tag, currentContent);
}
}
return elements;
}
}