14ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky/* 24ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * Copyright (C) 2013 The Android Open Source Project 34ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * 44ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * Licensed under the Apache License, Version 2.0 (the "License"); 54ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * you may not use this file except in compliance with the License. 64ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * You may obtain a copy of the License at 74ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * 84ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * http://www.apache.org/licenses/LICENSE-2.0 94ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * 104ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * Unless required by applicable law or agreed to in writing, software 114ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * distributed under the License is distributed on an "AS IS" BASIS, 124ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * See the License for the specific language governing permissions and 144ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * limitations under the License. 154ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky */ 164ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshanskypackage com.example.android.imagepixelization; 174ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 184ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshanskyimport android.animation.ObjectAnimator; 194ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshanskyimport android.app.Activity; 204ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshanskyimport android.graphics.Bitmap; 214ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshanskyimport android.graphics.BitmapFactory; 224ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshanskyimport android.graphics.Color; 234ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshanskyimport android.graphics.drawable.BitmapDrawable; 244ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshanskyimport android.os.AsyncTask; 254ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshanskyimport android.os.Build; 264ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshanskyimport android.os.Bundle; 274ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshanskyimport android.view.Menu; 284ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshanskyimport android.view.MenuItem; 294ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshanskyimport android.view.animation.LinearInterpolator; 304ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshanskyimport android.widget.ImageView; 314ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshanskyimport android.widget.SeekBar; 324ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 334ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshanskyimport java.util.Arrays; 344ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 354ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky/** 364ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * This application shows three different graphics/animation concepts. 374ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * 384ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * A pixelization effect is applied to an image with varying pixelization 394ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * factors to achieve an image that is pixelized to varying degrees. In 404ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * order to optimize the amount of image processing performed on the image 414ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * being pixelized, the pixelization effect only takes place if a predefined 424ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * amount of time has elapsed since the main image was last pixelized. The 434ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * effect is also applied when the user stops moving the seekbar. 444ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * 454ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * This application also shows how to use a ValueAnimator to achieve a 464ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * smooth self-animating seekbar. 474ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * 484ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * Lastly, this application shows a use case of AsyncTask where some 494ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * computation heavy processing can be moved onto a background thread, 504ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * so as to keep the UI completely responsive to user input. 514ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky */ 524ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshanskypublic class ImagePixelization extends Activity { 534ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 544ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky final private static int SEEKBAR_ANIMATION_DURATION = 10000; 554ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky final private static int TIME_BETWEEN_TASKS = 400; 564ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky final private static int SEEKBAR_STOP_CHANGE_DELTA = 5; 574ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky final private static float PROGRESS_TO_PIXELIZATION_FACTOR = 4000.0f; 584ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 594ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky Bitmap mImageBitmap; 604ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky ImageView mImageView; 614ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky SeekBar mSeekBar; 624ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky boolean mIsChecked = false; 634ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky boolean mIsBuiltinPixelizationChecked = false; 644ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky int mLastProgress = 0; 654ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky long mLastTime = 0; 664ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky Bitmap mPixelatedBitmap; 674ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 684ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky @Override 694ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky protected void onCreate(Bundle savedInstanceState) { 704ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky super.onCreate(savedInstanceState); 714ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky setContentView(R.layout.activity_image_pixelization); 724ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 734ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky mImageView = (ImageView) findViewById(R.id.pixelView); 744ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky mSeekBar = (SeekBar)findViewById(R.id.seekbar); 754ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 764ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky mImageBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.image); 774ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky mImageView.setImageBitmap(mImageBitmap); 784ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 794ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky mSeekBar.setOnSeekBarChangeListener(mOnSeekBarChangeListener); 804ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } 814ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 824ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky private SeekBar.OnSeekBarChangeListener mOnSeekBarChangeListener = 834ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky new SeekBar.OnSeekBarChangeListener() { 844ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 854ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky @Override 864ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky public void onStopTrackingTouch(SeekBar seekBar) { 874ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky if (Math.abs(mSeekBar.getProgress() - mLastProgress) > SEEKBAR_STOP_CHANGE_DELTA) { 884ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky invokePixelization(); 894ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } 904ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } 914ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 924ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky @Override 934ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky public void onStartTrackingTouch(SeekBar seekBar) { 944ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } 954ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 964ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky @Override 974ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { 984ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky checkIfShouldPixelize(); 994ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } 1004ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky }; 1014ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 1024ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky /** 1034ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * Checks if enough time has elapsed since the last pixelization call was invoked. 1044ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * This prevents too many pixelization processes from being invoked at the same time 1054ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * while previous ones have not yet completed. 1064ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky */ 1074ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky public void checkIfShouldPixelize() { 1084ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky if ((System.currentTimeMillis() - mLastTime) > TIME_BETWEEN_TASKS) { 1094ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky invokePixelization(); 1104ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } 1114ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } 1124ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 1134ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky @Override 1144ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky public boolean onCreateOptionsMenu(Menu menu) { 1154ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky getMenuInflater().inflate(R.menu.image_pixelization, menu); 1164ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky return true; 1174ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } 1184ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 1194ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky @Override 1204ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky public boolean onOptionsItemSelected (MenuItem item) { 1214ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky switch (item.getItemId()){ 1224ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky case R.id.animate: 1234ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky ObjectAnimator animator = ObjectAnimator.ofInt(mSeekBar, "progress", 0, 1244ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky mSeekBar.getMax()); 1254ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky animator.setInterpolator(new LinearInterpolator()); 1264ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky animator.setDuration(SEEKBAR_ANIMATION_DURATION); 1274ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky animator.start(); 1284ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky break; 1294ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky case R.id.checkbox: 1304ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky if (mIsChecked) { 1314ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky item.setChecked(false); 1324ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky mIsChecked = false; 1334ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } else { 1344ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky item.setChecked(true); 1354ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky mIsChecked = true; 1364ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } 1374ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky break; 1384ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky case R.id.builtin_pixelation_checkbox: 1394ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky mIsBuiltinPixelizationChecked = !mIsBuiltinPixelizationChecked; 1404ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky item.setChecked(mIsBuiltinPixelizationChecked); 1414ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky break; 1424ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky default: 1434ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky break; 1444ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } 1454ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky return true; 1464ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } 1474ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 1484ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky /** 1494ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * A simple pixelization algorithm. This uses a box blur algorithm where all the 1504ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * pixels within some region are averaged, and that average pixel value is then 1514ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * applied to all the pixels within that region. A higher pixelization factor 1524ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * imposes a smaller number of regions of greater size. Similarly, a smaller 1534ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * pixelization factor imposes a larger number of regions of smaller size. 1544ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky */ 1554ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky public BitmapDrawable customImagePixelization(float pixelizationFactor, Bitmap bitmap) { 1564ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 1574ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky int width = bitmap.getWidth(); 1584ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky int height = bitmap.getHeight(); 1594ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 1604ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky if (mPixelatedBitmap == null || !(width == mPixelatedBitmap.getWidth() && height == 1614ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky mPixelatedBitmap.getHeight())) { 1624ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky mPixelatedBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 1634ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } 1644ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 1654ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky int xPixels = (int) (pixelizationFactor * ((float)width)); 1664ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky xPixels = xPixels > 0 ? xPixels : 1; 1674ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky int yPixels = (int) (pixelizationFactor * ((float)height)); 1684ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky yPixels = yPixels > 0 ? yPixels : 1; 1694ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky int pixel = 0, red = 0, green = 0, blue = 0, numPixels = 0; 1704ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 1714ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky int[] bitmapPixels = new int[width * height]; 1724ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky bitmap.getPixels(bitmapPixels, 0, width, 0, 0, width, height); 1734ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 1744ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky int[] pixels = new int[yPixels * xPixels]; 1754ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 1764ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky int maxX, maxY; 1774ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 1784ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky for (int y = 0; y < height; y+=yPixels) { 1794ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky for (int x = 0; x < width; x+=xPixels) { 1804ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 1814ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky numPixels = red = green = blue = 0; 1824ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 1834ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky maxX = Math.min(x + xPixels, width); 1844ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky maxY = Math.min(y + yPixels, height); 1854ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 1864ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky for (int i = x; i < maxX; i++) { 1874ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky for (int j = y; j < maxY; j++) { 1884ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky pixel = bitmapPixels[j * width + i]; 1894ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky red += Color.red(pixel); 1904ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky green += Color.green(pixel); 1914ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky blue += Color.blue(pixel); 1924ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky numPixels ++; 1934ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } 1944ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } 1954ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 1964ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky pixel = Color.rgb(red / numPixels, green / numPixels, blue / numPixels); 1974ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 1984ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky Arrays.fill(pixels, pixel); 1994ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 2004ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky int w = Math.min(xPixels, width - x); 2014ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky int h = Math.min(yPixels, height - y); 2024ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 2034ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky mPixelatedBitmap.setPixels(pixels, 0 , w, x , y, w, h); 2044ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } 2054ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } 2064ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 2074ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky return new BitmapDrawable(getResources(), mPixelatedBitmap); 2084ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } 2094ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 2104ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky /** 2114ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * This method of image pixelization utilizes the bitmap scaling operations built 2124ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * into the framework. By downscaling the bitmap and upscaling it back to its 2134ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * original size (while setting the filter flag to false), the same effect can be 2144ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * achieved with much better performance. 2154ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky */ 2164ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky public BitmapDrawable builtInPixelization(float pixelizationFactor, Bitmap bitmap) { 2174ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 2184ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky int width = bitmap.getWidth(); 2194ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky int height = bitmap.getHeight(); 2204ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 2214ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky int downScaleFactorWidth = (int)(pixelizationFactor * width); 2224ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky downScaleFactorWidth = downScaleFactorWidth > 0 ? downScaleFactorWidth : 1; 2234ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky int downScaleFactorHeight = (int)(pixelizationFactor * height); 2244ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky downScaleFactorHeight = downScaleFactorHeight > 0 ? downScaleFactorHeight : 1; 2254ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 2264ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky int downScaledWidth = width / downScaleFactorWidth; 2274ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky int downScaledHeight = height / downScaleFactorHeight; 2284ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 2294ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky Bitmap pixelatedBitmap = Bitmap.createScaledBitmap(bitmap, downScaledWidth, 2304ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky downScaledHeight, false); 2314ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 2324ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky /* Bitmap's createScaledBitmap method has a filter parameter that can be set to either 2334ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * true or false in order to specify either bilinear filtering or point sampling 2344ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * respectively when the bitmap is scaled up or now. 2354ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * 2364ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * Similarly, a BitmapDrawable also has a flag to specify the same thing. When the 2374ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * BitmapDrawable is applied to an ImageView that has some scaleType, the filtering 2384ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * flag is taken into consideration. However, for optimization purposes, this flag was 2394ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * ignored in BitmapDrawables before Jelly Bean MR1. 2404ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * 2414ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * Here, it is important to note that prior to JBMR1, two bitmap scaling operations 2424ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * are required to achieve the pixelization effect. Otherwise, a BitmapDrawable 2434ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * can be created corresponding to the downscaled bitmap such that when it is 2444ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * upscaled to fit the ImageView, the upscaling operation is a lot faster since 2454ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * it uses internal optimizations to fit the ImageView. 2464ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * */ 2474ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { 2484ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky BitmapDrawable bitmapDrawable = new BitmapDrawable(getResources(), pixelatedBitmap); 2494ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky bitmapDrawable.setFilterBitmap(false); 2504ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky return bitmapDrawable; 2514ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } else { 2524ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky Bitmap upscaled = Bitmap.createScaledBitmap(pixelatedBitmap, width, height, false); 2534ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky return new BitmapDrawable(getResources(), upscaled); 2544ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } 2554ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } 2564ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 2574ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky /** 2584ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * Invokes pixelization either on the main thread or on a background thread 2594ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * depending on whether or not the checkbox was checked. 2604ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky */ 2614ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky public void invokePixelization () { 2624ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky mLastTime = System.currentTimeMillis(); 2634ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky mLastProgress = mSeekBar.getProgress(); 2644ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky if (mIsChecked) { 2654ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky PixelizeImageAsyncTask asyncPixelateTask = new PixelizeImageAsyncTask(); 2664ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky asyncPixelateTask.execute(mSeekBar.getProgress() / PROGRESS_TO_PIXELIZATION_FACTOR, 2674ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky mImageBitmap); 2684ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } else { 2694ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky mImageView.setImageDrawable(pixelizeImage(mSeekBar.getProgress() 2704ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky / PROGRESS_TO_PIXELIZATION_FACTOR, mImageBitmap)); 2714ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } 2724ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } 2734ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 2744ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky /** 2754ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * Selects either the custom pixelization algorithm that sets and gets bitmap 2764ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * pixels manually or the one that uses built-in bitmap operations. 2774ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky */ 2784ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky public BitmapDrawable pixelizeImage(float pixelizationFactor, Bitmap bitmap) { 2794ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky if (mIsBuiltinPixelizationChecked) { 2804ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky return builtInPixelization(pixelizationFactor, bitmap); 2814ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } else { 2824ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky return customImagePixelization(pixelizationFactor, bitmap); 2834ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } 2844ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } 2854ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 2864ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky /** 2874ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * Implementation of the AsyncTask class showing how to run the 2884ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * pixelization algorithm in the background, and retrieving the 2894ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky * pixelated image from the resulting operation. 2904ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky */ 2914ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky private class PixelizeImageAsyncTask extends AsyncTask<Object, Void, BitmapDrawable> { 2924ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 2934ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky @Override 2944ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky protected BitmapDrawable doInBackground(Object... params) { 2954ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky float pixelizationFactor = (Float)params[0]; 2964ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky Bitmap originalBitmap = (Bitmap)params[1]; 2974ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky return pixelizeImage(pixelizationFactor, originalBitmap); 2984ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } 2994ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 3004ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky @Override 3014ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky protected void onPostExecute(BitmapDrawable result) { 3024ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky mImageView.setImageDrawable(result); 3034ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } 3044ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 3054ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky @Override 3064ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky protected void onPreExecute() { 3074ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 3084ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } 3094ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 3104ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky @Override 3114ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky protected void onProgressUpdate(Void... values) { 3124ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky 3134ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } 3144ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky } 3154ea559806d2c4839e1c4019445c43c5fe41c9a0bDaniel Olshansky}