Saving an Object containing Bitmap - android

I'm working on an android application (first application-beginner) and I'm trying to save data when the app closes to load again.
The data I want to store is a list of books, and each book contains info (author, date, etc) and a bitmap containing the book's picture. I tried using GSON to convert the list to JSON and store in SharedPreferences but that caused problems because of the bitmap.
How should I save the file and retrieve it again when the app launches ?
This is a brief version of the code
Library Class
public class Library {
private ArrayList<Entry> library ;
public Library () {
library = new ArrayList<Entry>();
}
public void addEntry( Entry entry ) {
library.add(entry);
}
public void removeEntry ( Entry entry ) {
if (library.contains(entry))
library.remove(entry);
else Log.d ( "Library" , "Entry Not Found");
}
public ArrayList<Entry> getLibrary() {
return library;
}
#Override
public String toString() {
return "Library{" +
"library=" + library +
'}';
}
}
Entry Class
public class Entry {
Book book ;
final LocalDate borrowDate;
LocalDate dueDate;
//some methods for application
}
Book Class
public class Book implements Parcelable {
private String title;
private String author;
private String isbn ;
private double rating;
private int ratingCount;
private int pageCount;
private transient Bitmap image;
private String overview;
//some methods
}

Don't put the bitmap in sharedpreferences. Save it in file.
If you need to persist the bitmap, you can assign it to a static field.
You can also convert it to a 64 bit String.. but that is bad design (and I think it is a very slow and expensive operation!):
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.PNG, 100, baos); //bm is the bitmap object
byte[] b = baos.toByteArray();
String encoded = Base64.encodeToString(b, Base64.DEFAULT);
^ Save that to SharedPreferece. Now to decode:
byte[] imageAsBytes = Base64.decode(encoded.getBytes());
ImageView image = (ImageView)this.findViewById(R.id.ImageView);
image.setImageBitmap(BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length));

Use Picasso and load the urls directly instead of downloading and saving as bitmap
Picasso.with(mContext)
.load("imageURL here")
.placeholder(R.drawable.default_pic)
.error(R.drawable.error_pic)
.resizeDimen(100, 100)
.centerCrop()
.into(holderOrderHistory.mIcon);

Related

Why won't my images not load in Recyclerview

Glide won't load the images I have linked with the products on my recycler view. The images should be pulled from my PHP MySQL database. Not really sure what I did wrong. Please help
I've tried a few solutions I found on the web but none of them worked for me.
private String image;
The above is the string identifier from my product list
//loading the image
Glide.with(mCtx)
.load(product.getImage())
.into(holder.imageView);
holder.textViewPlateNumber.setText(product.getPlatenumber());
holder.textView1.setText(product.getMake());
holder.textView2.setText(product.getModel());
holder.textView3.setText(product.getYear());
holder.textViewName.setText(product.getName());
holder.textDate.setText(product.getDate());
holder.recyclerid.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String platenumber = productList.get(position).getPlatenumber();
String make = productList.get(position).getMake();
String model = productList.get(position).getModel();
String year = productList.get(position).getYear();
String name = productList.get(position).getName();
String date = productList.get(position).getDate();
String vin = productList.get(position).getVin();
String displacement = productList.get(position).getDisplacement();
String fueltype = productList.get(position).getFueltype();
String transmission = productList.get(position).getTransmission();
String mileage = productList.get(position).getMileage();
String ownerorcompany =
productList.get(position).getOwnerorcompany();
String homeorcompanyaddress =
productList.get(position).getHomeorcompanyaddress();
String contactnumber =
productList.get(position).getContactnumber();
String emailaddress = productList.get(position).getEmailaddress();
String facebook = productList.get(position).getFacebook();
String image = productList.get(position).getImage();
The above is the code I used to show the images of each item off my adapter.
<de.hdodenhof.circleimageview.CircleImageView
android:id="#+id/imageView"
android:layout_width="0dp"
android:layout_height="0dp"
android:src="#drawable/car_avatar"
app:civ_border_color="#color/cta"
app:civ_border_width="2dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/guideline17"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
The above is how the image should be laid out in my xml file. The rest of the items saved on my php sql show up on the list except the images. Here is what my php file looks like:
$vehicle = array();
while ($row=mysqli_fetch_array($sql)) {
$temp = array();
$temp['id'] = $row['VehicleID'];
$temp['platenumber'] = $row['PlateNumber'];
$temp['make'] = $row['Make'];
$temp['model'] = $row['Model'];
$temp['year'] = $row['Year'];
$temp['name'] = $row['OwnerorCompany'];
$temp['date'] = $row['AddDate'];
$temp['image'] = $row['vehicleImage'];
$temp['vin'] = $row['Vin'];
$temp['displacement'] = $row['Displacement'];
$temp['fueltype'] = $row['FuelType'];
$temp['transmission'] = $row['Transmission'];
$temp['mileage'] = $row['Mileage'];
$temp['ownerorcompany'] = $row['OwnerorCompany'];
$temp['homeorcompanyaddress'] = $row['HomeorCompanyAddress'];
$temp['contactnumber'] = $row['ContactNumber'];
$temp['emailaddress'] = $row['EmailAddress'];
$temp['facebook'] = $row['FacebookID'];
array_push($vehicle, $temp);
}
echo json_encode($vehicle);
//}
?>
And this is how the images are saved on my database:
$photo = $_POST['photo'];
$id=uniqid();
$path = "vehicle_upload/$id.jpeg";
$finalpath = "http://192.168.0.10/widevalueautoInc
2/server/api/".$path;
When I run the app, all goes well except the images not showing up on the list. This is the java code I used to save the image and the size.
private void addVehicle(String stringImage) {
}
public String getStringImage(Bitmap bitmap){
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream);
byte[] imageByteArray = byteArrayOutputStream.toByteArray();
String encodedImage = Base64.encodeToString(imageByteArray,
Base64.DEFAULT);
return encodedImage;
}
}
remove circular imageview and use default image view, to use circle crop .. use Glide circle crop function....
Glide.with(context).load("dddd").apply(RequestOptions.circleCropTransform()).into(imageview);
Just make a common method as below in your utility class as below :
public static void setCircularImageToGlide(final Context context, final CircularImageView imageView, String imageUrl) {
Glide.with(context).load("" + imageUrl).asBitmap().placeholder(R.drawable.ic_photo_placeholder).transform(new CircleTransform(context)).into(new BitmapImageViewTarget(imageView) {
#Override
protected void setResource(Bitmap resource) {
RoundedBitmapDrawable circularBitmapDrawable =
RoundedBitmapDrawableFactory.create(context.getResources(), resource);
circularBitmapDrawable.setCircular(true);
imageView.setImageDrawable(circularBitmapDrawable);
}
});
}
I have passed CircularImageView as an argument to method single you are using CircularImageView instead of simple ImageView.
Call it as below wherever you need to set image in to your CircularImageView as below :
CommonUtil.setCircularImageToGlide(YOUR_CONTEXT, YOUR_CIRCULAR_IMAGE_VIEW, "" + YOUR_IMAGE_URL);
Am using below dependency :
implementation 'com.github.bumptech.glide:glide:3.7.0'

Post an image along some form data Retrofit to WCF Rest

This is my method that is used to send some form data, but i want to send an image also, is this possible using this same method and adding it using an image property in the class or it is more reasonable sending it using another method separatly.
#POST("PostBanderolDataJSON")
Call<ReportPostData> PostData(#Body ReportPostData reportdata);
This is my class:
public class ReportPostData {
private int Id;
private String Banderolnr;
private String Pharmacy;
private String Place;
private String LocationLongitude;
private String LocationLatitude;
}
Use Multi Part
For example
#Multipart
#POST("/v1/upload/sell-image")
Call<CustomerUploadImageResponse> signUp(
#Header(KEY_X_AUTH) String authToken,
#Part List<MultipartBody.Part> signUpDataList
);
To Generate signUpDataList Use like
List<MultipartBody.Part> signUpDataList = new ArrayList<>();
signUpDataList.add(MultipartBody.Part.createFormData("qid", "1333"));
signUpDataList.add(MultipartBody.Part.createFormData("ut", "xyz");
String path = customerImageUploadData.getImageUrl();
Bitmap bitmap = ImageUtil.getBitmap(mActivity, path);
if (null != bitmap) {
MultipartBody.Part part = MultipartBody.Part.createFormData(
"img",
"profile.jpg",
RequestBody.create(null, ImageUtil.getBytesFromBitmapFullQuality(bitmap))
);
signUpDataList.add(part);
}

How can I read xml on android with unity?

So here's my code, it works perfectly fine in unity editor but not on android, it only reads the first line of the xml file.
I don't know what is wrong with it.
The file exists on the phone but it only reads the first line.
In the unity editor it works perfectly fine.
Thank for your help.
using System.Xml;
using System.Xml.Serialization;
public class Mission
{ [XmlAttribute("id")]
public int Id;
public string description;
public int ordre;
}
Here is the class that loads the xml
using System.IO;
using System.Xml.Serialization;
using System.Collections.Generic;
[XmlRoot("Missionss")]
public class Missions{
[XmlArray("Missions"), XmlArrayItem("Mission")]
public List<Mission> Mission_List;
private Missions(){}
public static Missions LoadFromFile(string filepath){
XmlSerializer serializer = new XmlSerializer(typeof(Missions));
using(FileStream stream = new FileStream(filepath, FileMode.Open))
{
return serializer.Deserialize(stream) as Missions;
}
}
public void Save (string path)
{
XmlSerializer serializer = new XmlSerializer (typeof(Missions));
using (FileStream stream = new FileStream (path, FileMode.Create)) {
serializer.Serialize (stream, this);
}
}
}
and finally:
public void LoadXML(){
string filename="/phases.xml";
string filename1="/missions.xml";
phases = Phases.LoadFromFile(Application.persistentDataPath + filename);
missions = Missions.LoadFromFile (Application.persistentDataPath + filename1);
}
public void save(){
phases.Save(Application.streamingAssetsPath + "phases.xml");
missions.Save(Application.streamingAssetsPath + "missions.xml");
}
dont you need "\" written somewhere? lets say: phases.Save(Application.streamingAssetsPath +"\\"+ "phases.xml");

Load image from binary base64

EDIT: This is a bug in Android version <4.3 Kitkat. It relates to the libjpeg library in Android, which can't handle JPEGs with missing EOF/EOI bits, or apparently with metadata/EXIF data that it doesn't like.
https://code.google.com/p/android/issues/detail?id=9064
ORIGINAL QUESTION:
I have an issue when loading an image in my app.
My endpoint sends JSON which contains a BASE64 encoded image. Depending on the REST call, these images can be PNG or JPG. Some of the JPG files suffer from an issue where they are missing an EOF bit at the end. The PNG files work, and some JPG files work, but unfortunately a lot of these JPG files with the issue are present in the Oracle DB (stored as BLOB). I don't have control of the DB.
I have been looking through Google bugs here:
https://code.google.com/p/android/issues/detail?id=9064
and here:
https://code.google.com/p/android/issues/detail?id=57502
The issue is also seen where the encoding is CYMK using a custom ICC profile.
Decoding the image the standard way returns false:
byte[] imageAsBytes = Base64.decode(base64ImageString, Base64.DEFAULT);
return BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length);
According to the bug reports above, the built in JPG parser in Android is to blame.
I'm trying to figure out a workaround for my device, which is stuck on 4.2.2. I have no other option on this OS version.
I thought it might be a good idea to try and use an image loader library like Universal Image Loader, but it requires I either have the image stored locally, or stored on a URL. As I get the data in BASE64 from the REST server, I can't use this. An option is to support decodeByteArray in a custom class that extends BaseImageDecoder, as stated by the dev at the bottom here: https://github.com/nostra13/Android-Universal-Image-Loader/issues/209
Here's where I get stuck. I already have a custom image decoder to try handle the issue of the missing EOF marker in the JPG file, but I don't know how to edit it to add support for decodeByteArray.
Here is my CustomImageDecoder:
public class CustomImageDecoder extends BaseImageDecoder {
public CustomImageDecoder(boolean loggingEnabled) {
super(loggingEnabled);
}
#Override
protected InputStream getImageStream(ImageDecodingInfo decodingInfo) throws IOException {
InputStream stream = decodingInfo.getDownloader()
.getStream(decodingInfo.getImageUri(), decodingInfo.getExtraForDownloader());
return stream == null ? null : new JpegClosedInputStream(stream);
}
private class JpegClosedInputStream extends InputStream {
private static final int JPEG_EOI_1 = 0xFF;
private static final int JPEG_EOI_2 = 0xD9;
private final InputStream inputStream;
private int bytesPastEnd;
private JpegClosedInputStream(final InputStream iInputStream) {
inputStream = iInputStream;
bytesPastEnd = 0;
}
#Override
public int read() throws IOException {
int buffer = inputStream.read();
if (buffer == -1) {
if (bytesPastEnd > 0) {
buffer = JPEG_EOI_2;
} else {
++bytesPastEnd;
buffer = JPEG_EOI_1;
}
}
return buffer;
}
}
}
By the way, using the above custom class, I am trying to load my byte array like this:
byte[] bytes = Base64.decode(formattedB64String, Base64.NO_WRAP);
ByteArrayInputStream is = new ByteArrayInputStream(bytes);
String imageId = "stream://" + is.hashCode();
...
ImageLoader imageLoader = ImageLoader.getInstance();
imageLoader.displayImage(imageId, userImage, options);
and I get this error:
ImageLoader: Image can't be decoded [stream://1097215584_656x383]
Universal Image loader does not allow the stream:// schema, so I created a custom BaseImageDownloader class that allows it:
public class StreamImageDownloader extends BaseImageDownloader {
private static final String SCHEME_STREAM = "stream";
private static final String STREAM_URI_PREFIX = SCHEME_STREAM + "://";
public StreamImageDownloader(Context context) {
super(context);
}
#Override
protected InputStream getStreamFromOtherSource(String imageUri, Object extra) throws IOException {
if (imageUri.startsWith(STREAM_URI_PREFIX)) {
return (InputStream) extra;
} else {
return super.getStreamFromOtherSource(imageUri, extra);
}
}
}
So if anyone can help me create a better CustomImageDecoder that handles a BASE64 encoded string, or a byte[] containing an image so I can use decodeByteArray, I would be grateful!
Thank you.
UnversalImageLoader uses the following schemes to decode the files
"h t t p ://site.com/image.png" // from Web
"file:///mnt/sdcard/image.png" // from SD card
"file:///mnt/sdcard/video.mp4" // from SD card (video thumbnail)
"content://media/external/images/media/13" // from content provider
"content://media/external/video/media/13" // from content provider (video thumbnail)
"assets://image.png" // from assets
"drawable://" + R.drawable.img // from drawables (non-9patch images)
your scheme is stream://
Hope that helps.
Just to close this off:
The issue here is actually a bug in Android <4.3 where Android can't display images that either aren't closed properly (missing end bytes) or contain certain metadata that, for some reason, it doesn't like. I'm not sure what metadata this is, however. My issue was with JPEGs not being terminated properly.
The bug is fixed in Android 4.3 anyway.

DBFlow (Save Image As Blob)

I been trying to save my image(As Blob to the database using DBFlow).
I'm getting an error like this..
Error:(90, 30) error: incompatible types
required: Blob
found: byte[]
I Used some tutorial for converting image to byte and save it to database with column blob.
try {
FileInputStream fileInputStream = new FileInputStream(imageURL);
byte[] image = new byte[fileInputStream.available()];
fileInputStream.read(image);
ImageModel imageModel = new ImageModel();
imageModel.latitude = "12345";
imageModel.img = image;
imageModel.save();
} catch (IOException e) {
e.printStackTrace();
}
And lastly my ImageModel.class,
import com.raizlabs.android.dbflow.annotation.Column;
import com.raizlabs.android.dbflow.annotation.PrimaryKey;
import com.raizlabs.android.dbflow.annotation.Table;
import com.raizlabs.android.dbflow.data.Blob;
import com.raizlabs.android.dbflow.structure.BaseModel;
/**
* Created by Galvez on 11/17/2015.
*/
#Table(databaseName = AppDatabase.dbName)
public class ImageModel extends BaseModel {
#Column
#PrimaryKey(autoincrement = true)
long getId;
#Column
String latitude;
#Column
Blob img;
}
What's supposed to be the problem? Am I wrong converting image to blob?
You have the right idea. The Blob class indicates that you want to use BLOB as the underlying database column type. And you are correct in thinking that a byte array is way to store data in the Blob. You just have a small implementation issue: the Blob object acts as a wrapper around a byte array. In Java, you can't cast or coerce the byte[] into a Blob; you need to use the Blob object's methods instead.
So your line of code above should be
imageModel.img = new Blob(image);
To retrieve image data back out, you might do something like
byte[] imageData = imageModel.img.getBlob();
Bitmap image = BitmapFactory.decodeByteArray(imageData, 0, imageData.length);

Categories

Resources