package jml.EditImage; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat; import android.graphics.BitmapFactory; import android.graphics.Color; import android.os.Environment; import android.util.Log; import android.media.MediaMetadataRetriever; import android.content.Context; import android.content.res.AssetManager; import com.google.appinventor.components.annotations.Asset; import com.google.appinventor.components.annotations.DesignerComponent; import com.google.appinventor.components.annotations.DesignerProperty; import com.google.appinventor.components.annotations.PropertyCategory; import com.google.appinventor.components.annotations.SimpleEvent; import com.google.appinventor.components.annotations.SimpleFunction; import com.google.appinventor.components.annotations.SimpleObject; import com.google.appinventor.components.annotations.SimpleProperty; import com.google.appinventor.components.common.ComponentCategory; import com.google.appinventor.components.common.PropertyTypeConstants; import com.google.appinventor.components.runtime.util.MediaUtil; import com.google.appinventor.components.runtime.*; import java.io.File; import java.util.Date; import java.util.Arrays; /* * thanks to Justus Raju for Image processor I used and complete it. */ @DesignerComponent(version = EditImage.VERSION, description = "Edit image and save it in file", category = ComponentCategory.EXTENSION, nonVisible = true, iconName = "https://community.appinventor.mit.edu/uploads/default/original/3X/e/f/ef2b8e04cc0705d730a63719841b696fdaf1dacf.png") @SimpleObject(external = true) public class EditImage extends AndroidNonvisibleComponent implements Component { public static final int VERSION =3 ; //changes according to name convention private ComponentContainer container; private Bitmap globalBitmap; boolean globalBitmapSet=false; private String imagePath=form.getExternalFilesDir("ImgChanged").getAbsolutePath()+"/tmp.png"; public EditImage(ComponentContainer container) { super(container.$form()); this.container = container; } /*************************************************************************************************************************************************************************************************** /** * Sets the Image * */ @DesignerProperty() @SimpleProperty(category = PropertyCategory.BEHAVIOR, description = "Sets the Image ") public void Image(@Asset({".png", ".jpeg", ".jpg",".gif"}) String filePath) { this.globalBitmap=DefineImage(filePath); this.globalBitmapSet=true; } /* @DesignerProperty() @SimpleProperty(category = PropertyCategory.BEHAVIOR,description = "") public String test(String filePath){ try{ Bitmap bitmap=DefineImage(filePath); //return "ok"; }catch(Exception e){ //StackTraceElements [] elements = e.getStackTrace(); StringWriter errors = new StringWriter(); e.printStackTrace(new PrintWriter(errors)); return errors.toString(); } return "fini"; } @DesignerProperty() @SimpleFunction(description = "") public String test(String image){ return image; } */ /****************************************************************************** /******************************************************************************* /** * Sets the Output Image path * */ @DesignerProperty() @SimpleProperty(category = PropertyCategory.BEHAVIOR,description = "Sets the Output Image path if not define is /ImgChanged/tmp.png ") public void OutputImagePath(@Asset({".png", ".jpeg", ".jpg",".gif"})String filePath) { filePath=defineDir(filePath); this.imagePath = filePath; } /** * Get the path of edited image * */ @SimpleProperty(description = "Save Image and return pathFile ", category = PropertyCategory.BEHAVIOR) public String ImagePath() { if(this.globalBitmapSet){ String fileSaved= saveBitmap(this.globalBitmap,this.imagePath); return fileSaved; } else{ return "null"; } } /** * Get the image width * */ @SimpleFunction(description = "return image Width") public int ImgWidth(@Asset({".png", ".jpeg", ".jpg",".gif"})String filePath) { filePath=defineDir (filePath); if (new File(filePath).exists()){ Bitmap bitmap=loadImage(filePath); int val=bitmap.getWidth(); return val; } else return 0; } /** * Get the image height * */ @SimpleFunction(description = "return image Height") public int ImgHeight(@Asset({".png", ".jpeg", ".jpg",".gif"})String filePath) { filePath=defineDir (filePath); if (new File(filePath).exists()){ Bitmap bitmap=loadImage(filePath); int val=bitmap.getHeight(); return val; } else return 0; } //************************************************************************************************************************************ Combine Images ********************************************************************************* /** * Takes imageA and imageB and returns imageC * * Such that RGBA of (point in imageC) = weight*(point in imageA) + (1 - weight)*(point in imageB) */ @SimpleFunction(description = "Takes imageA and imageB and returns combined image /n"+" weight*(point in imageA) + (1 - weight)*(point in imageB)") public String ImageCombine(@Asset({".png", ".jpeg", ".jpg",".gif"})String imageA, @Asset({".png", ".jpeg", ".jpg",".gif"})String imageB, float weight) { imageA = imageA == null ? "" : imageA; imageB = imageB == null ? "" : imageB; imageA=defineDir (imageA); imageB=defineDir (imageB); Bitmap bitmapA=loadImage(imageA); Bitmap bitmapB=loadImage(imageB); weight = Math.min(Math.max(0,weight),1); int maxW = Math.min(bitmapA.getWidth(), bitmapB.getWidth()); int maxH = Math.min(bitmapA.getHeight(), bitmapB.getHeight()); Bitmap bitmapC = Bitmap.createBitmap(maxW, maxH, Bitmap.Config.ARGB_8888); for (int x = 0; x < maxW; x++) { for (int y = 0; y < maxH; y++) { int colA = bitmapA.getPixel(x, y) ; int colB = bitmapB.getPixel(x, y) ; int aC = (int)(Color.alpha(colA)*weight + Color.alpha(colB)*(1.0-weight)); int rC = (int)(Color.red(colA)*weight + Color.red(colB)*(1.0-weight)); int gC = (int)(Color.green(colA)*weight + Color.green(colB)*(1.0-weight)); int bC = (int)(Color.blue(colA)*weight + Color.blue(colB)*(1.0-weight)); int colC = Color.argb(aC, rC, gC, bC); bitmapC.setPixel(x, y, colC); } } String fileSaved= saveBitmap(bitmapC,this.imagePath); return fileSaved ; } //************************************************************************************************************************************ Grey ********************************************************************************* /** * This is the grey function that averages the RGB value and assigns to each color component. */ @SimpleFunction (description = "Grey Image ") public String ImageGrey(@Asset({".png", ".jpeg", ".jpg",".gif"})String filePath) { Bitmap bitmap=DefineImage(filePath); String fileSaved= saveBitmap(Grey(bitmap),this.imagePath); return fileSaved ; } /** * Grey seted Image * */ @SimpleFunction (description = "Grey seted Image") public void SetGrey(float value) { if(this.globalBitmapSet){ this.globalBitmap =Grey(this.globalBitmap); } else{ } } public Bitmap Grey(Bitmap bmpInput){ int maxW = bmpInput.getWidth(); int maxH = bmpInput.getHeight(); Bitmap bmpOutput = Bitmap.createBitmap(maxW, maxH, Bitmap.Config.ARGB_8888); for (int x = 0; x < maxW; x++) { for (int y = 0; y < maxH; y++) { int colA = bmpInput.getPixel(x, y) ; int aC = Color.alpha(colA); int avgC = (int)((Color.red(colA) + Color.green(colA) + Color.blue(colA))/3); int colC = Color.argb(aC, avgC, avgC, avgC); bmpOutput.setPixel(x, y, colC); } } return bmpOutput; } //************************************************** Grey FIN ********************************************************************************* //********************************************************************************************************************************** Brigthness ********************************************************************************* /** * Change Brigthness of an image * * value [0,1}] <0.5 to dark, >0.5 to clair */ @SimpleFunction (description = "Change Brigthness of an image /n value <1 to dark, >1 to claire") public String ImageBrigthness(@Asset({".png", ".jpeg", ".jpg",".gif"})String filePath, float value) { Bitmap bitmap=DefineImage(filePath); value=Math.min(Math.max(value, 0),1); //encadre la value entre 0 et 1 Bitmap bitmapC =Brigthness(bitmap,value); String fileSaved= saveBitmap(bitmapC,this.imagePath); return fileSaved ;//image.getAbsolutePath(); } /** * Change Brigthness of Seted an image * * value [0,1}] <0.5 to dark, >0.5 to clair */ @SimpleFunction (description = "Change Brigthness set image /n value <1 to dark, >1 to claire") public void SetBrigthness(float value) { if(this.globalBitmapSet){ value=Math.min(Math.max(value, 0),1); //encadre la value entre 0 et 1 this.globalBitmap =Brigthness(this.globalBitmap,value); } } public Bitmap Brigthness(Bitmap bmpInput,float value){ value=Math.min(Math.max(value, 0),1); int colC; int maxW = bmpInput.getWidth(); int maxH = bmpInput.getHeight(); Bitmap bmpOutput = Bitmap.createBitmap(maxW, maxH, Bitmap.Config.ARGB_8888); for (int x = 0; x < maxW; x++) { for (int y = 0; y < maxH; y++) { int colA = bmpInput.getPixel(x, y) ; int aC = (int)(Color.alpha(colA)); int rC = (int)(Color.red(colA)); int gC = (int)(Color.green(colA)); int bC = (int)(Color.blue(colA)); float[] hsv=new float[3]; if(value>0.5){ rC=Math.max(rC,1);gC=Math.max(gC,1);bC=Math.max(bC,1); //ne pas rester sur un noir rC=(int)((Math.pow((float)rC/255,1-Math.pow(value,2)))*255); gC=(int)((Math.pow((float)gC/255,1-Math.pow(value,2)))*255); bC=(int)((Math.pow((float)bC/255,1-Math.pow(value,2)))*255); colC = Color.argb(aC, rC, gC, bC); } else{ Color.RGBToHSV (rC,gC,bC,hsv); hsv[2]=Math.min(Math.max(hsv[2]*(float)((2*value*Math.exp(Math.log(1-value)/Math.log(0.5f)))/Math.exp(1)), 0),1); colC=Color.HSVToColor (aC,hsv); } bmpOutput.setPixel(x, y, colC); } } return bmpOutput; } //********************************** Brigthness FIN********************************************************************************* //**************************************************************************************************************************** ScaledImage ****************************************************** /** * Change scale of image in path * * according to width and height */ @SimpleFunction (description = "Change scale of an image ") public String ScaleImage(@Asset({".png", ".jpeg", ".jpg",".gif"})String filePath, int width, int height) { Bitmap bitmapA=DefineImage(filePath); Bitmap bitmap=Bitmap.createScaledBitmap (bitmapA,width,height,true); String fileSaved= saveBitmap(bitmap,this.imagePath); return fileSaved ;//image.getAbsolutePath(); } /** * Change scale of Seted image in path * * value [0,1}] <0.5 to dark, >0.5 to clair */ @SimpleFunction (description = "Change scale of an image 00.5 to clair */ @SimpleFunction (description = "Change scale of an image 00) return true; else return false; } catch (Exception e) { return false; } }else return false; } /** * Change file path * * dependin on star: / or // or file:// */ //******************************* get Image from mp3 FIN *********************************** /* This is called after every ImageProcess that is done by this processor! To demo events ;) @SimpleEvent public void AfterProcess(String image){ EventDispatcher.dispatchEvent(this, "AfterProcess", image); } */ //************************************************************************************************************************** blur ********************************************************************* /** * blur image in path * */ @SimpleFunction (description = "blur seted Iamge ") public void SetBlur(int radius) { if(this.globalBitmapSet){ int dim=Math.min(this.globalBitmap.getHeight(),this.globalBitmap.getWidth())-1; radius=Math.max(radius,0); radius=Math.min(radius,dim); this.globalBitmap=fullBlurBitmapImage(this.globalBitmap,radius); } } @SimpleFunction (description = "blur seted Iamge only on row") public void SetBlurByRow(int radius) { if(this.globalBitmapSet){ radius=Math.min(Math.max(radius,0),2*this.globalBitmap.getWidth()-1); this.globalBitmap=rowBlurBitmapImage(this.globalBitmap,radius); } } @SimpleFunction (description = "blur seted Iamge only on column") public void SetBlurByColumn(int radius) { if(this.globalBitmapSet){ radius=Math.min(Math.max(radius,0),2*this.globalBitmap.getHeight()-1); this.globalBitmap=columnBlurBitmapImage(this.globalBitmap,radius); } } @SimpleFunction (description = "blur Iamge ") public String BlurImage(@Asset({".png", ".jpeg", ".jpg",".gif"})String filePath, int radius) { try{ Bitmap bitmap=DefineImage(filePath); int dim=Math.min(bitmap.getHeight(),bitmap.getWidth())-1; radius=Math.max(radius,0); radius=Math.min(radius,dim); bitmap=fullBlurBitmapImage(bitmap,radius); String fileSaved= saveBitmap(bitmap,this.imagePath); return fileSaved;//image.getAbsolutePath(); } catch(Exception e){ //StackTraceElements [] elements = e.getStackTrace(); StringWriter errors = new StringWriter(); e.printStackTrace(new PrintWriter(errors)); return errors.toString(); } } @SimpleFunction (description = "blur Iamge only on row") public String BlurImageByRow(@Asset({".png", ".jpeg", ".jpg",".gif"})String filePath, int radius) { Bitmap bitmap=DefineImage(filePath); radius=Math.min(Math.max(radius,0),2*bitmap.getWidth()-1); bitmap=rowBlurBitmapImage(bitmap,radius); String fileSaved= saveBitmap(bitmap,this.imagePath); return fileSaved ;//image.getAbsolutePath(); } @SimpleFunction (description = "only on column") public String BlurImageByColumn(@Asset({".png", ".jpeg", ".jpg",".gif"})String filePath, int radius) { Bitmap bitmap=DefineImage(filePath); radius=Math.min(Math.max(radius,0),2*bitmap.getHeight()-1); bitmap=columnBlurBitmapImage(bitmap,radius); String fileSaved= saveBitmap(bitmap,this.imagePath); return fileSaved ;//image.getAbsolutePath(); } //*************************************************************************** //public static String blurBitmapImage(Bitmap original, int blurRadius){ public static Bitmap fullBlurBitmapImage(Bitmap original, int blurRadius){ int width = original.getWidth(); int height = original.getHeight(); boolean useAlpha = original.hasAlpha(); int blurDiameter = blurRadius*2+1; float[][] colors = Bitmap2Matrix(original, useAlpha, width, height); float[][] avgRow = blurRow(colors, width, blurRadius, blurDiameter); float[][] avg = blurColumn(avgRow, width, blurRadius, blurDiameter); original = modifBitmap(original,avg,width,height,useAlpha); return original; } public static Bitmap rowBlurBitmapImage(Bitmap original, int blurRadius){ int width = original.getWidth(); int height = original.getHeight(); boolean useAlpha = original.hasAlpha(); int blurDiameter = blurRadius*2+1; float[][] colors = Bitmap2Matrix(original, useAlpha, width, height); float[][] avgRow = blurRow(colors, width, blurRadius, blurDiameter); original = modifBitmap(original,avgRow,width,height,useAlpha); return original; } public static Bitmap columnBlurBitmapImage(Bitmap original, int blurRadius){ int width = original.getWidth(); int height = original.getHeight(); boolean useAlpha = original.hasAlpha(); int blurDiameter = blurRadius*2+1; float[][] colors = Bitmap2Matrix(original, useAlpha, width, height); float[][] avgColumn = blurColumn(colors, width, blurRadius, blurDiameter); original = modifBitmap(original,avgColumn,width,height,useAlpha); return original; } public static float[][] Bitmap2Matrix(Bitmap original, boolean useAlpha, int width, int height){ int[] pixels = new int[width *height]; int nb_colors; original.getPixels(pixels,0,width,0,0,width,height); if(useAlpha){ nb_colors = 4;// RGBA } else{ nb_colors = 3;//RGB } float[][] colors = new float[pixels.length][nb_colors]; for(int i=0;i=blurRadius) avgColorsrow[i-blurRadius][col] = ((float) local_sums[col])/blurDiameter; } last_entry = (last_entry+ 1)%blurDiameter; //if we are finishing the line if((i+1)%width==0){ for(int j =0;j