一、前期基础知识储备

UI掌握PS这一逆天的软件,可以实现将图片转化为素描或者水彩的效果,以素描为例:

  1. 在Photoshop中打开一张人物照片,按下快捷键“Ctrl+Shift+U”,把它转换成黑白颜色;
  2. 复制图层,得到一个副本图层。按下快捷键“Ctrl+I”,将副本图层转换成负片效果;
  3. 将副本图层下拉菜单选为“颜色减淡”,这时图片会亮得几乎什么也看不见,不要急,慢慢来;
  4. 在“滤镜”菜单下选择“模糊→高斯模糊”,模糊半径值可根据你需要的素描线条粗细深浅来设置。到此素描画像工作就完成了。

我们将以上四步进行抽象,得到将图片转为素描效果的步骤即为:

  1. 去色,将图片变为灰度图,即黑白图;
  2. 反相,得到每个像素的补色,具体效果就像照片的底片;
  3. 高斯模糊,把反相后的像素值平均一下;
  4. 颜色减淡,将第1步中的像素和第3步得到的像素值进行计算。

在Android图像处理领域,我们可以使用像素点分析的方法实现上述的效果组合。下面,用代码实现上述过程

二、上代码,具体实现素描算法

1)去色,获取黑白图;

 public static int[] discolor(Bitmap bitmap) {int picHeight = bitmap.getHeight();int picWidth = bitmap.getWidth();int[] pixels = new int[picWidth * picHeight];bitmap.getPixels(pixels, 0, picWidth, 0, 0, picWidth, picHeight);for (int i = 0; i < picHeight; ++i) {for (int j = 0; j < picWidth; ++j) {int index = i * picWidth + j;int color = pixels[index];int r = (color & 0x00ff0000) >> 16;int g = (color & 0x0000ff00) >> 8;int b = (color & 0x000000ff);int grey = (int) (r * KR + g * KG + b * KB);pixels[index] = grey << 16 | grey << 8 | grey | 0xff000000;}}return pixels;}

2)反相,得到图片的底图;

public static int[] reverseColor(int[] pixels) {int length = pixels.length;int[] result = new int[length];for (int i = 0; i < length; ++i) {int color = pixels[i];int r = 255 - (color & 0x00ff0000) >> 16;int g = 255 - (color & 0x0000ff00) >> 8;int b = 255 - (color & 0x000000ff);result[i] = r << 16 | g << 8 | b | 0xff000000;}return result;}

3)高斯模糊,得到反高斯图像;

 public static void gaussBlur(int[] data, int width, int height, int radius,float sigma) {float pa = (float) (1 / (Math.sqrt(2 * Math.PI) * sigma));float pb = -1.0f / (2 * sigma * sigma);// generate the Gauss Matrixfloat[] gaussMatrix = new float[radius * 2 + 1];float gaussSum = 0f;for (int i = 0, x = -radius; x <= radius; ++x, ++i) {float g = (float) (pa * Math.exp(pb * x * x));gaussMatrix[i] = g;gaussSum += g;}for (int i = 0, length = gaussMatrix.length; i < length; ++i) {gaussMatrix[i] /= gaussSum;}// x directionfor (int y = 0; y < height; ++y) {for (int x = 0; x < width; ++x) {float r = 0, g = 0, b = 0;gaussSum = 0;for (int j = -radius; j <= radius; ++j) {int k = x + j;if (k >= 0 && k < width) {int index = y * width + k;int color = data[index];int cr = (color & 0x00ff0000) >> 16;int cg = (color & 0x0000ff00) >> 8;int cb = (color & 0x000000ff);r += cr * gaussMatrix[j + radius];g += cg * gaussMatrix[j + radius];b += cb * gaussMatrix[j + radius];gaussSum += gaussMatrix[j + radius];}}int index = y * width + x;int cr = (int) (r / gaussSum);int cg = (int) (g / gaussSum);int cb = (int) (b / gaussSum);data[index] = cr << 16 | cg << 8 | cb | 0xff000000;}}// y directionfor (int x = 0; x < width; ++x) {for (int y = 0; y < height; ++y) {float r = 0, g = 0, b = 0;gaussSum = 0;for (int j = -radius; j <= radius; ++j) {int k = y + j;if (k >= 0 && k < height) {int index = k * width + x;int color = data[index];int cr = (color & 0x00ff0000) >> 16;int cg = (color & 0x0000ff00) >> 8;int cb = (color & 0x000000ff);r += cr * gaussMatrix[j + radius];g += cg * gaussMatrix[j + radius];b += cb * gaussMatrix[j + radius];gaussSum += gaussMatrix[j + radius];}}int index = y * width + x;int cr = (int) (r / gaussSum);int cg = (int) (g / gaussSum);int cb = (int) (b / gaussSum);data[index] = cr << 16 | cg << 8 | cb | 0xff000000;}}}

4)淡化颜色,生成Sketch图

 public static void colorDodge(int[] baseColor, int[] mixColor) {for (int i = 0, length = baseColor.length; i < length; ++i) {int bColor = baseColor[i];int br = (bColor & 0x00ff0000) >> 16;int bg = (bColor & 0x0000ff00) >> 8;int bb = (bColor & 0x000000ff);int mColor = mixColor[i];int mr = (mColor & 0x00ff0000) >> 16;int mg = (mColor & 0x0000ff00) >> 8;int mb = (mColor & 0x000000ff);int nr = colorDodgeFormular(br, mr);int ng = colorDodgeFormular(bg, mg);int nb = colorDodgeFormular(bb, mb);baseColor[i] = nr << 16 | ng << 8 | nb | 0xff000000;}}private static int colorDodgeFormular(int base, int mix) {int result = base + (base * mix) / (255 - mix);result = result > 255 ? 255 : result;return result;}

5)将上述代码封如工具类中,最后定义一个获取素描图的方法

 public static Bitmap testGaussBlur(Bitmap src, int r, int fai) {int width = src.getWidth();int height = src.getHeight();int[] pixels = Sketch.discolor(src);int[] copixels = Sketch.simpleReverseColor(pixels);Sketch.simpleGaussBlur(copixels, width, height, r, fai);Sketch.simpleColorDodge(pixels, copixels);Bitmap bitmap = Bitmap.createBitmap(pixels, width, height,Config.RGB_565);return bitmap;}

外界,调用时,传入两个int类型的参数即可,表示高斯模糊的程度和半径。

public class SketchActivity extends AppCompatActivity {private static final String TAG = "SketchActivity";@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_sketch);DisplayMetrics displayMetrics = new DisplayMetrics();getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);int width = displayMetrics.widthPixels;int height = displayMetrics.heightPixels;ImageView imageView = findViewById(R.id.test_img);Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.timg);// 对大图进行压缩 传入的参数为手机屏幕的尺寸 工具类在文末给出bitmap = Utils.compressBySampleSize(bitmap, width, height, false);Bitmap bitmap = SketchUtil.testGaussBlur(bitmap,10,10);imageView.setImageBitmap(bitmap); // 素描图}@Overrideprotected void onDestroy() {super.onDestroy();}
}

效果如下:

三、上代码,具体实现手指在图片上左右滑动调节图片透明度,实现类似调节素描浓度的效果

在上面的算法中,我们为testGaussBlur()传入两个参数,即可实现调节素描的效果。现在提出另一个思路,就是在不改变已传入参数的前提下,调节素描的浓度:

要求:手指左滑浓度变淡,即素描图变透明;手指右滑变浓,即凸显素描图

① 我们在原有ImageView的位置放入一个FrameLayout,然后在这个FrameLayout中放入两个ImageView,一个用于放置原图,在底层;一个用于放置素描效果图,在上层。两个ImageView的大小设为一样大,由于FrameLayout的特性,我们只能看见效果图。

② 然后我们为上层放置效果图的ImageView写入手势控制事件,当用户在图片上左右移动手指的时候,就调节上层图片的透明度,这样就达到了类似调节素描浓度的效果。

实现如下:

/*** 作者    cpf* 时间    2019/4/16* 文件    TestApplication* 描述    手指在图片上滑动 可调节图片的透明度* ①使用Seekbar是否可以做到? 没有办法区分左右滑动 记录上次滑动结果可以做的到 在onStopTrackingTouch方法中记录* ②自定义View + 手势移动 onFling没法表示中间的过程 只有起始和结束时的状态 ,需要一个渐变的距离 onScroll*/
public class SeekbarActivity extends AppCompatActivity implements View.OnTouchListener {private static final String TAG = "SeekbarActivity";private ImageView mImageView, mGestureImageView, originImageView;private SeekBar mSeekBar;private TextView mTxt, mGesTxt;private int mProgress = 100;private float mDistance = 1, maxDistance = 100; // 控制progress参数在0-100,0为完全透明 100为起始值可见private GestureDetector mGestureDetector;private Bitmap finalBitmap,bitmap;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_seekbar);DisplayMetrics displayMetrics = new DisplayMetrics();getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);int width = displayMetrics.widthPixels;int height = displayMetrics.heightPixels;mImageView = findViewById(R.id.alpha_img);mGestureImageView = findViewById(R.id.ges_alpha_img);originImageView = findViewById(R.id.origin_img);mSeekBar = findViewById(R.id.alpha_seek);mTxt = findViewById(R.id.alpha_txt);mGesTxt = findViewById(R.id.ges_alpha_txt);bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.timg);bitmap = Utils.compressBySampleSize(bitmap, width, height, false);finalBitmap = SketchUtil.testGaussBlur(bitmap,10,10);mImageView.setImageBitmap(bitmap);mGestureImageView.setImageBitmap(finalBitmap);originImageView.setImageBitmap(bitmap);mSeekBar.setMax(100); // 100 代表完不全透明 0 代表完全透明mSeekBar.setProgress(100);mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {Log.d(TAG, "onProgressChanged: direction..." + direction);if (direction == 0) {// 左滑 变透明if ((mProgress - progress) > 0 && (mProgress - progress) < 100) {mImageView.setImageBitmap(SketchUtil.testGaussBlur(Utils.setAlpha(finalBitmap, (mProgress - progress)),10,10));mTxt.setText(String.valueOf((mProgress - progress)) + "%");Log.d(TAG, "onProgressChanged: 左滑," + (mProgress - progress));} else if ((mProgress - progress) < 0) {mImageView.setImageBitmap(Utils.setAlpha(SketchUtil.testGaussBlur(finalBitmap,10,10), 1));mTxt.setText(String.valueOf(1) + "%");Log.d(TAG, "onProgressChanged: 左滑过界," + 1);}} else {// 右滑 变清晰if ((mProgress + progress) < 100 && (mProgress + progress) > 0) {mImageView.setImageBitmap(SketchUtil.testGaussBlur(Utils.setAlpha(finalBitmap, (mProgress + progress)),10,10));mTxt.setText(String.valueOf((mProgress + progress)) + "%");Log.d(TAG, "onProgressChanged: 右滑," + (mProgress + progress));} else if ((mProgress + progress) > 100) {mImageView.setImageBitmap(Utils.setAlpha(SketchUtil.testGaussBlur(finalBitmap,10,10), 100));mTxt.setText(String.valueOf(100) + "%");Log.d(TAG, "onProgressChanged: 右滑过界," + 100);}}}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {}@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {mTxt.setVisibility(View.GONE);mProgress = seekBar.getProgress();Log.d(TAG, "onProgressChanged, onStopTrackingTouch:::" + mProgress);}});//初始化图片mImageView.setImageBitmap(Utils.setAlpha(finalBitmap, 100)); // 0 代表完全透明initGesture();}private void initGesture() {mGestureDetector = new GestureDetector(new simpleGestureListener());// 注意以下四个声明不可缺少mGestureImageView.setOnTouchListener(this);mGestureImageView.setFocusable(true);mGestureImageView.setClickable(true);mGestureImageView.setLongClickable(true);}@Overridepublic boolean onTouch(View v, MotionEvent event) {// TODO Auto-generated method stubreturn mGestureDetector.onTouchEvent(event);}private int direction = 0;private class simpleGestureListener extendsGestureDetector.SimpleOnGestureListener {/*****OnGestureListener的函数*****/final int FLING_MIN_DISTANCE = 10;final float MIN_DISTANCE = 0, MAX_DISTANCE = 100;public boolean onDown(MotionEvent e) {// do nothingreturn false;}public boolean onScroll(MotionEvent e1, MotionEvent e2,float distanceX, float distanceY) {if (e1.getX() - e2.getX() > FLING_MIN_DISTANCE) {// Fling left 左滑变透明 distanceX为正值int progress = (int) (maxDistance - distanceX / 15);if (progress >= MIN_DISTANCE) {mGestureImageView.setImageBitmap(Utils.setAlpha(finalBitmap, progress));maxDistance = progress;mProgress = progress;mGesTxt.setVisibility(View.VISIBLE);mGesTxt.setText(String.valueOf(progress) + "%");Log.d("MyGesture22", "onScroll:" + progress + ", 左滑 ," + distanceX);}} else if (e2.getX() - e1.getX() > FLING_MIN_DISTANCE) {// Fling right 右滑显示 distanceX为负值int progress = (int) (maxDistance - distanceX / 5);if (progress <= MAX_DISTANCE) {mGestureImageView.setImageBitmap(Utils.setAlpha(finalBitmap, progress));maxDistance = progress;mProgress = progress;mGesTxt.setVisibility(View.VISIBLE);mGesTxt.setText(String.valueOf(progress) + "%");Log.d("MyGesture22", "onScroll:" + progress + ", 右滑 ," + distanceX);}}return true;}// 用户按下触摸屏、快速移动后松开,由1个MotionEvent ACTION_DOWN, 多个ACTION_MOVE, 1个ACTION_UP触发public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY) {mGesTxt.setVisibility(View.GONE);mImageView.setImageBitmap(Utils.xFerMode(bitmap,Utils.setAlpha(finalBitmap, mProgress)));Log.d(TAG, "onFling: " + mProgress);return true;}}
}

可以看到,笔者先是尝试使用SeekBar的方式来实现类似的效果,即将该SeekBar置于图片的上层,然后重写其两个属性,将其设为完全透明,即对于用户不可见,同时将SeekBar设为大小同ImageView一样大,也就实现了对于图片的覆盖,然后在对SeekBar的滑动监听事件onProgressChanged()中调节效果图的透明度,同时在另一监听方法onStopTrackingTouch()记录手指上次离开屏幕时的数值,这样在下次手指down下的时候,传入该值即可。用SeekBar实现这一需求只能做到一半,如上面代码中的注视一般,可以做到记录上次滑动的数值,但是没有办法区分开手指滑动的方向,即无法验证手指左滑还是右滑。

而后,笔者采用GestureDetector的方式实现,拦截下屏幕上的触摸事件,并把事件设置给展示效果图的ImageView。这样手指滑动的事件就传递给了ImageView。然后在重写onScroll()方法,区分开手指左右滑动,并在对应的实现中对图片透明度做不同的调整;最后重写onFling()方法,识别手指抬起,将展示图片透明度数值的TextView设为不可见。

效果如下:

以下是文中使用到的工具类:用以加载大图、调节图片透明度。还有其他一些关于Bitmap的处理方法。

public class Utils {public static final String TAG = "Utils:";private static final String SAVE_FOLDER = "PencilCamera";private static final String SAVE_FILENAME_PREFIX = "IMG";private static int lastSaveFileIndex = 0;/*** 图片透明度处理** @param sourceImg 原始图片* @param number    透明度* @return*/public static Bitmap setAlpha(Bitmap sourceImg, int number) {try {int[] argb = new int[sourceImg.getWidth() * sourceImg.getHeight()];sourceImg.getPixels(argb, 0, sourceImg.getWidth(), 0, 0,sourceImg.getWidth(), sourceImg.getHeight());// 获得图片的ARGB值number = number * 255 / 100;for (int i = 0; i < argb.length; i++) {if ((argb[i] & 0xff000000) != 0x00000000) {// 透明色不做处理argb[i] = (number << 24) | (argb[i] & 0xFFFFFF);// 修改最高2位的值}}sourceImg = Bitmap.createBitmap(argb, sourceImg.getWidth(),sourceImg.getHeight(), Bitmap.Config.ARGB_8888);} catch (OutOfMemoryError e) {e.printStackTrace();System.gc();}return sourceImg;}/*** 混合两张Bitmap 返回融合后的Bitmap** @param src 主图* @param dst 修饰图*/public static Bitmap xFerMode(Bitmap src, Bitmap dst) {Bitmap lightenModeBitmap = Bitmap.createBitmap(dst.getWidth(), dst.getHeight(), Bitmap.Config.ARGB_8888);Canvas canvas = new Canvas(lightenModeBitmap);Paint paint1 = new Paint();paint1.setAntiAlias(true);Rect srcRect = new Rect(0, 0, src.getWidth(), src.getHeight());canvas.drawARGB(0, 0, 0, 0);canvas.drawBitmap(src, srcRect, srcRect, paint1); //画人物 srcpaint1.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN));// 再把原来的bitmap画到现在的bitmapcanvas.drawBitmap(dst, srcRect, srcRect, paint1); //画特效 dstreturn lightenModeBitmap;}/*** Return the compressed bitmap using sample size.** @param src       The source of bitmap.* @param maxWidth  The maximum width.* @param maxHeight The maximum height.* @param recycle   True to recycle the source of bitmap, false otherwise.* @return the compressed bitmap*/public static Bitmap compressBySampleSize(final Bitmap src,final int maxWidth,final int maxHeight,final boolean recycle) {if (isEmptyBitmap(src)) return null;BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;ByteArrayOutputStream baos = new ByteArrayOutputStream();src.compress(Bitmap.CompressFormat.JPEG, 100, baos);byte[] bytes = baos.toByteArray();BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);options.inSampleSize = calculateInSampleSize(options, maxWidth, maxHeight);options.inJustDecodeBounds = false;if (recycle && !src.isRecycled()) src.recycle();return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options);}/*** Return the sample size.* 1500*1500的大图采样率为8 尺寸为562*562* 300*400的采样率为2* @param options   The options.* @param maxWidth  The maximum width.* @param maxHeight The maximum height.* @return the sample size*/private static int calculateInSampleSize(final BitmapFactory.Options options,final int maxWidth,final int maxHeight) {int height = options.outHeight;int width = options.outWidth;int inSampleSize = 1;while (height > maxHeight || width > maxWidth) {height >>= 1;width >>= 1;inSampleSize <<= 1;}return inSampleSize;}private static boolean isEmptyBitmap(final Bitmap src) {return src == null || src.getWidth() == 0 || src.getHeight() == 0;}/*** Reize bitmap with dimensions equal to or less than given params, without changing the aspect ratio* @param bitmap    Input bitmap* @param maxWidth  Max allowed width of resized Bitmap* @param maxHeight Max allowed height of resized Bitmap* @return Resized bitmap*/public static Bitmap resizeBitmap(Bitmap bitmap, int maxWidth, int maxHeight) {if (maxHeight > 0 && maxWidth > 0) {int width = bitmap.getWidth();int height = bitmap.getHeight();float ratioBitmap = (float) width / (float) height;float ratioMax = (float) maxWidth / (float) maxHeight;int finalWidth = maxWidth;int finalHeight = maxHeight;if (ratioMax > ratioBitmap) {finalWidth = (int) ((float)maxHeight * ratioBitmap);} else {finalHeight = (int) ((float)maxWidth / ratioBitmap);}Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmap, finalWidth, finalHeight, true);return scaledBitmap;} else {return bitmap;}}/*** Save bitmap as JPEG with a incremental filename, in the SAVE_FOLDER directory* @param activity* @param bitmap* @return* @throws IOException*/public static String saveBitmap(Activity activity, Bitmap bitmap) throws IOException {File file;try {// Create a new save filefile = createSaveFile();OutputStream fOut = new FileOutputStream(file);// saving the Bitmap to a file compressed as a JPEG with 85% compression ratebitmap.compress(Bitmap.CompressFormat.JPEG, 85, fOut);fOut.close();// Add saved file to galleryIntent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);Uri contentUri = Uri.fromFile(file);mediaScanIntent.setData(contentUri);activity.sendBroadcast(mediaScanIntent);} catch(IOException e) {String errorMsg = "Unable to save image";Log.e(TAG, errorMsg + ":" + e.getMessage());throw new IOException(errorMsg);}return file.getPath();}/*** Rotate bitmap by given angle in degrees* @param bitmap* @param angle* @return*/public static Bitmap rotateBitmap(Bitmap bitmap, int angle) {Matrix matrix = new Matrix();matrix.postRotate(angle);return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);}/*** Create a new save file in the SAVE_FOLDER directory with name as '<SAVE_FILENAME_PREFIX>_<3 digit serial number>'* ( example: IMG_001)* @return* @throws IOException*/private static File createSaveFile() throws IOException {File file;String path = Environment.getExternalStorageDirectory().toString();OutputStream fOut = null;String saveFolderPath = path + '/' + SAVE_FOLDER;int saveFileIndex = lastSaveFileIndex;do {String saveFileName = SAVE_FILENAME_PREFIX + String.format("%03d", ++saveFileIndex) + ".jpg";String saveFilePath = saveFolderPath + '/' + saveFileName;Log.d(TAG,"Saving image to path - "+saveFilePath);file = new File(saveFilePath); // the File to save tofile.getParentFile().mkdirs();} while(file.exists());file.createNewFile();return file;}
}

Android素描算法及实现手指在图片上左右滑动调节图片透明度,最终实现类似调节素描浓度的效果相关推荐

  1. php上传图片限制类型,php,_使用php的图片上传类进行图片上传,总是提示:上传文件时出错 : 未允许类型 。都是默认的配置,php - phpStudy...

    使用php的图片上传类进行图片上传,总是提示:上传文件时出错 : 未允许类型 .都是默认的配置 使用php的图片上传类进行图片上传,总是提示:上传文件时出错 : 未允许类型 .都是默认的配置 $upl ...

  2. html5 图片上传,支持图片预览、压缩、及进度显示,兼容IE6+及标准浏览器

    原文:html5 图片上传,支持图片预览.压缩.及进度显示,兼容IE6+及标准浏览器 以前写过上传组件,见 打造 html5 文件上传组件,实现进度显示及拖拽上传,兼容IE6+及其它标准浏览器,对付一 ...

  3. Python爬虫:运用多线程、IP代理模块爬取百度图片上小姐姐的图片

    Python爬虫:运用多线程.IP代理模块爬取百度图片上小姐姐的图片 1.爬取输入类型的图片数量(用于给用户提示) 使用过百度图片的读者会发现,在搜索栏上输入关键词之后,会显示出搜索的结果,小编想大多 ...

  4. ps批量修改名片文字_怎么修改图片上的文字 修改图片文字比如名片图片上面的地址需要修改下...

    现在在网络上下载的图片是不是都对有文字水印的咧是不,那么怎么修改图片上的文字呢,修改图片文字比如名片图片上面的地址需要修改下这些怎么完成?OK ,今天就让小编来给大伙科普一下,其实要做到真正的无痕迹修 ...

  5. java 图片上写字_java 在图片上写字,两个图片合并的实现方法

    实例如下: package writeimg; import javax.imageio.ImageIO; import java.awt.Color; import java.awt.Font; i ...

  6. java 两张图片合并_java 在图片上写字,两个图片合并的实现方法

    实例如下: package writeimg; import javax.imageio.ImageIO; import java.awt.Color; import java.awt.Font; i ...

  7. PHP实现将任意尺寸的图片裁剪后等比缩放到任意尺寸的透明图片上,并实现图片翻转...

    类库地址 github.com/jinqiubj/Pi- 此类库满足以下需求 将任意尺寸的图片等比缩放到任意尺寸的透明图片上,如图1是一张200*200的正方形图片. 在等比缩放的同时,此类库可根据图 ...

  8. 妈蛋:kinMaxShow轮播图异常,WebUploader图片上传坑爹,图片被压缩了

    2019独角兽企业重金招聘Python工程师标准>>> 今天晚上在改造轮播图. 原来的代码是这样的: <div> <img src="${static}/ ...

  9. 图片上传成功但是图片显示不出来_小程序上传图片到腾讯云

    这是小程序开发第二篇,主要介绍如何上传图片到腾讯云,之所以选择腾讯云,是因为腾讯云免费空间大 准备工作 上传图片主要是将图片上传到腾讯云对象存储(COS). 要使用对象存储 API,需要先执行以下步骤 ...

最新文章

  1. hive安装报错如何解决?
  2. CSS之Background-size:cover
  3. BERT源码分析(PART I)
  4. C++若不想使用编译器自动生成的函数,就该明确拒绝
  5. Shadow Brokers扬言兜售新漏洞攻击工具
  6. 为Docker容器设置静态IP
  7. 如何使得客户端和服务器端完美配合做IOS应用内付费
  8. 如何在 40 秒内创建一个.Net Core Web API?
  9. python数值类型教程_Python数值类型 int、float、complex 详解
  10. linux内核 address_space 结构
  11. html swf格式转换器,蒲公英SWF格式转换器
  12. IDEA Spring环境搭建+简单入门(图文教程)
  13. RK3568平台开发系列讲解(安卓篇)JNI调用流程分析
  14. java 汇率换算_汇率转换示例代码
  15. ## 关于时下新兴的日常图片视频摄像防抖技术的简单介绍与讨论
  16. 什么叫51单片机最小系统
  17. Arcgis去除矢量文件Z值和/或M值方法
  18. swiper滑动时每页都有动画
  19. 大小口圆锥台计算机,2011年对口单招计算机试卷A04(18页)-原创力文档
  20. Centos删除乱码文件或文件夹

热门文章

  1. python蒙特卡洛方法圆周率_蒙特卡罗方法 python 实现
  2. excel poi导入,数字和日期格式校验
  3. 【推荐与广告】积累与发现
  4. 详解智能优化算法:遗传算法和蚁群算法
  5. 【itext学习之路】-------(第四篇)给pdf增加文本水印和图片水印
  6. [2018年底]电信短信自注册,rild重启等项目问题总结
  7. 注意!你得提前1.5h进考场,防疫要求千万别出错
  8. html背景图片全屏效果的方式
  9. windows环境下electron开发遇到的各种坑汇总
  10. 文本生成词云图wordcloud