超大图片显示,可任意缩放,移动,不用DiskLruCache
1.演示,代码
下载示例apk 下载项目 : https://gitee.com/xi/LImage.git
2.遇到的问题
- 想省内存,不太可能
- 只支持拖拽手势,不支持缩放相对简单,解码view对应的区域就可以。
- 不支持缩放好像说不过去,同时支持缩放+拖拽后变复杂,如转屏后的位置,指定锚点缩放,缩放后又移动,移动后又缩放。
- 用系统图库打开图片?直接打开超大图片不能正常显示.用图库打开图片所在目录?没有找到相关代码.
3.缩放,移动的思路
3.1 缩放思路
- 用一张解码区域是整张图片,但是inSampleSize大小适中的缩略图缩放.虽然图片是不清晰的,但是省内存,省解码时间.
- 缩小过程不需要高清的.
- 放大到100%的时候就重新解码当前view对应区域的位图,inSampleSize = 1 .
3.2 移动思路
- 当缩放比例小于100%时,就移动缩略图,
- 当缩放比例等于100%时,按当前view区域大小平移,重新解码对应的位图.
4.核心代码
4.1 解码
- BitmapRegionDecoder 可以指定一个区域(大图范围内,超出会抛异常)对一张大位图解码,解出一张小位图.然后在view上显示这个小位图.
- BitmapFactory.Options 解码选项,下面是常用的几个重要选项:
inSampleSize | 缩略大小,值为2的n次幂(n为自然数).其它值无意义 |
inPreferredConfig |
色彩模式,决定一个像素占用的字节数 |
inBitmap |
指定复用的位图..不用在申请内存. |
- 代码
private BitmapRegionDecoder mDecoder; private BitmapFactory.Options mOptions; private Rect mDecodeRegion; void initRegionDecoder(){ try { InputStream fs = getResources().getAssets().open("world_map.jpg"); mDecoder = BitmapRegionDecoder.newInstance(fs,false); mBitmapWidth = mDecoder.getWidth(); mBitmapHeight = mDecoder.getHeight(); mOptions = new BitmapFactory.Options(); mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888; mOptions.inSampleSize = ; } catch (IOException e) { e.printStackTrace(); } } protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //... mDecodeRegion = new Rect(left,top,left + viewWidth ,top + viewHeight ); // mDecodeRegion = new Rect(0,0,mBitmapWidth ,mBitmapHeight); mOptions.inSampleSize = calculateInSampleSize(mDecodeRegion.width(),mDecodeRegion.height(),viewWidth,viewHeight); // mOptions.inSampleSize = 2; long begin,end; begin = SystemClock.elapsedRealtime(); mBitmap = mDecoder.decodeRegion(mDecodeRegion,mOptions); end = SystemClock.elapsedRealtime(); //.. }
4.2 手势
- ScaleGestureDetector 缩放手势识别器
- GestureDetectorCompat 移动手势识别器
这两个比较简单,先构造,然后在 public boolean onTouchEvent(MotionEvent event) 里接收触摸事件,最后在相应的手势回调方法处理手势就可以.
4.3 变形
缩放: 用变形矩阵.小于100%时移动也用变形矩阵,等于100%时自己计算.
@Override protected void onDraw(Canvas canvas) { if (mPercentage < 100.0f && mThumbnailBitmap != null){ canvas.drawBitmap(mThumbnailBitmap,mMatrix,mPaint); }else if(mPercentage == 100.0f && mBitmap != null){ canvas.drawBitmap(mBitmap,mBitmapLeft,mBitmapTop,mPaint); } //... }
4.4 LargeImageView.java
package com.example.ff.limage; import android.annotation.SuppressLint; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.BitmapRegionDecoder; import android.graphics.BlurMaskFilter; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Point; import android.graphics.Rect; import android.os.AsyncTask; import android.os.Environment; import android.os.Parcelable; import android.os.SystemClock; import android.support.annotation.Nullable; import android.support.v4.view.GestureDetectorCompat; import android.util.AttributeSet; import android.util.Log; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.ScaleGestureDetector; import android.view.View; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.math.BigDecimal; import static android.os.Environment.isExternalStorageRemovable; public class LargeImageView extends View { private String TAG = "LargeImageView"; private Paint mPaint; private BitmapRegionDecoder mDecoder; private BitmapFactory.Options mOptions; private Rect mDecodeRegion; private static Bitmap mThumbnailBitmap; private Bitmap mBitmap; private Matrix mMatrix; private float thumbnailWidth,thumbnailHeight; private float mPercentage; private float mThumbnailLeft,mThumbnailTop,mBitmapLeft,mBitmapTop; private int mBitmapWidth,mBitmapHeight; private Point mFocus; private boolean mScaling = false; private DiskLruCache mDiskLruCache; public void destroyBitmaps(){ Log.e(TAG, "destroyBitmaps: release bitmaps" ); if (!mDecoder.isRecycled()) { mDecoder.recycle(); } if (!mBitmap.isRecycled()){ mBitmap.recycle(); mBitmap = null; } } public void destroyThumbnailBitmap(){ if (!mThumbnailBitmap.isRecycled()){ mThumbnailBitmap.recycle(); mThumbnailBitmap = null; } } public void createThumbnailBitmap(){ if (null == mThumbnailBitmap){ DecodeTask task = new DecodeTask(); task.execute(mDecodeRegion); } } public void createBitmaps(){ } private class DecodeTask extends AsyncTask<Rect,Void,Void>{ @Override protected Void doInBackground(Rect... rects) { Log.e(TAG, "doInBackground: " ); long begin,end; mDecodeRegion = ,,mBitmapWidth,mBitmapHeight); mOptions.inSampleSize = ; begin = SystemClock.elapsedRealtime(); mThumbnailBitmap = mDecoder.decodeRegion(mDecodeRegion,mOptions); end = SystemClock.elapsedRealtime(); Log.e(TAG, "doInBackground: decode mThumbnailBitmap need " + (end - begin) + " ms. " ); return null; } } @Override protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) { super.onFocusChanged(gainFocus, direction, previouslyFocusedRect); } // 打印Matrix内数据 void showMatrix(Matrix matrix,String tag){ // 下面的代码是为了查看matrix中的元素 ]; matrix.getValues(matrixValues); String temp ; ; i < ; ++i) { temp = ""; ; j < ; ++j) { temp += matrixValues[ * i + j] + "\t"; } Log.e(tag, temp); } } private void printThumbnailRect(){ float left = mThumbnailLeft; float top = mThumbnailTop; float right = mThumbnailLeft + thumbnailWidth; float bottom = mThumbnailTop + thumbnailHeight; Log.e(TAG, "printThumbnailRect: left = " + left + " top = " + top + " right = " + right + " bottom = " + bottom + " width = " + thumbnailWidth + " height = " + thumbnailHeight); } private ScaleGestureDetector scaleDetector; private ScaleGestureDetector.SimpleOnScaleGestureListener scaleGestureListener = new ScaleGestureDetector.SimpleOnScaleGestureListener() { @Override public boolean onScale(ScaleGestureDetector detector) { float factor = detector.getScaleFactor(); ) return true; && factor > ){ return true; } if (thumbnailWidth * factor < mBitmapWidth){ if (thumbnailWidth * factor >= mBitmapWidth * 0.01f){ thumbnailWidth *= factor; thumbnailHeight *= factor; mMatrix.postScale(factor,factor,detector.getFocusX(),detector.getFocusY()); } }else{ factor = mBitmapWidth / thumbnailWidth; mMatrix.postScale(factor,factor,detector.getFocusX(),detector.getFocusY()); thumbnailWidth = mBitmapWidth; thumbnailHeight = mBitmapHeight; mPercentage = 100.0f; ]; mMatrix.getValues(matrix); mThumbnailLeft = matrix[]; mThumbnailTop = matrix[]; float left = mThumbnailLeft; float top = mThumbnailTop; float right = mThumbnailLeft + thumbnailWidth; float bottom = mThumbnailTop + thumbnailHeight; int viewWith = getWidth(); int viewHeight = getHeight(); mBitmapLeft = ; mBitmapTop = ; ){ mBitmapLeft = left; mDecodeRegion.left = ; mDecodeRegion.right = (int) (viewWith - left); ){ mBitmapTop = top; mDecodeRegion.top = ; mDecodeRegion.bottom = (int) (viewHeight - top); }else if(bottom < viewHeight){ mDecodeRegion.bottom = mBitmapHeight; mDecodeRegion.top = (int) (mBitmapHeight - bottom); }else { mDecodeRegion.top = (int) -top; mDecodeRegion.bottom = mDecodeRegion.top + viewHeight; } }){ mBitmapTop = top; mDecodeRegion.top = ; mDecodeRegion.bottom = (int) (viewHeight - top); if (right < viewWith){ mDecodeRegion.right = mBitmapWidth; mDecodeRegion.left = (int) (mBitmapWidth - right); }else{ mDecodeRegion.left = (int) -left; mDecodeRegion.right = mDecodeRegion.left + viewWith; } }else if(right < viewWith ){ mDecodeRegion.right = mBitmapWidth; mDecodeRegion.left = (int) (mBitmapWidth - right); if(bottom < viewHeight){ mDecodeRegion.bottom = mBitmapHeight; mDecodeRegion.top = (int) (mBitmapHeight - bottom); }else{ mDecodeRegion.top = (int) -top; mDecodeRegion.bottom = mDecodeRegion.top + viewHeight; } }else if(bottom < viewHeight){ mDecodeRegion.left = (int) -left; mDecodeRegion.right = mDecodeRegion.left + viewWith; mDecodeRegion.bottom = mBitmapHeight; mDecodeRegion.top = (int) (mBitmapHeight - bottom); }else{ mDecodeRegion.left = (int) -left; mDecodeRegion.right = mDecodeRegion.left + viewWith; mDecodeRegion.top = (int) -top; mDecodeRegion.bottom = mDecodeRegion.top + viewHeight; } mOptions.inSampleSize = ; && mDecodeRegion.height() > ){ mBitmap = mDecoder.decodeRegion(mDecodeRegion,mOptions); }else{ if (mBitmap != null && !mBitmap.isRecycled()){ mBitmap.recycle(); mBitmap = null; } } } BigDecimal bd = ).setScale(,BigDecimal.ROUND_HALF_UP); mPercentage = bd.floatValue(); Log.i(TAG, "onScale: bitmap.w = " + mThumbnailBitmap.getWidth() + " bitmap.h = " + mThumbnailBitmap.getHeight() + " thumbnailWidth = " + thumbnailWidth + " thumbnailHeight = " + thumbnailHeight); invalidate(); return true; } @Override public boolean onScaleBegin(ScaleGestureDetector detector) { mScaling = true; float focusX = detector.getFocusX(); float focusY = detector.getFocusY(); mFocus = new Point((int)focusX,(int)focusY); return true; } @Override public void onScaleEnd(ScaleGestureDetector detector) { mScaling = false; mFocus = null; super.onScaleEnd(detector); } }; private GestureDetectorCompat scrollDetector; private GestureDetector.SimpleOnGestureListener simpleOnGestureListener = new GestureDetector.SimpleOnGestureListener() { @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { && Math.abs(distanceY) < ) return true; ]; mMatrix.getValues(matrix); mThumbnailLeft = matrix[]; mThumbnailTop = matrix[]; int viewWith = getWidth(); int viewHeight = getHeight(); if (mThumbnailLeft <= viewWith && mThumbnailLeft >= -thumbnailWidth && mThumbnailTop <= viewHeight && mThumbnailTop >= -thumbnailHeight){ && viewWith - mThumbnailLeft < -distanceX){ distanceX = -(viewWith - mThumbnailLeft); } && mThumbnailLeft + thumbnailWidth < distanceX){ distanceX = mThumbnailLeft + thumbnailWidth; } && viewHeight - mThumbnailTop < -distanceY){ distanceY = -(viewHeight - mThumbnailTop); } && mThumbnailTop + thumbnailHeight < distanceY){ distanceY = mThumbnailTop + thumbnailHeight; } mMatrix.postTranslate(-distanceX,-distanceY); if (mPercentage == 100.0f){ mMatrix.getValues(matrix); mThumbnailLeft = matrix[]; mThumbnailTop = matrix[]; float left = mThumbnailLeft; float top = mThumbnailTop; float right = mThumbnailLeft + thumbnailWidth; float bottom = mThumbnailTop + thumbnailHeight; mBitmapLeft = ; mBitmapTop = ; ){ mBitmapLeft = left; mDecodeRegion.left = ; mDecodeRegion.right = (int) (viewWith - left); ){ mBitmapTop = top; mDecodeRegion.top = ; mDecodeRegion.bottom = (int) (viewHeight - top); }else if(bottom < viewHeight){ mDecodeRegion.bottom = mBitmapHeight; mDecodeRegion.top = (int) (mBitmapHeight - bottom); }else { mDecodeRegion.top = (int) -top; mDecodeRegion.bottom = mDecodeRegion.top + viewHeight; } }){ mBitmapTop = top; mDecodeRegion.top = ; mDecodeRegion.bottom = (int) (viewHeight - top); if (right < viewWith){ mDecodeRegion.right = mBitmapWidth; mDecodeRegion.left = (int) (mBitmapWidth - right); }else{ mDecodeRegion.left = (int) -left; mDecodeRegion.right = mDecodeRegion.left + viewWith; } }else if(right < viewWith ){ mDecodeRegion.right = mBitmapWidth; mDecodeRegion.left = (int) (mBitmapWidth - right); if(bottom < viewHeight){ mDecodeRegion.bottom = mBitmapHeight; mDecodeRegion.top = (int) (mBitmapHeight - bottom); }else{ mDecodeRegion.top = (int) -top; mDecodeRegion.bottom = mDecodeRegion.top + viewHeight; } }else if(bottom < viewHeight){ mDecodeRegion.left = (int) -left; mDecodeRegion.right = mDecodeRegion.left + viewWith; mDecodeRegion.bottom = mBitmapHeight; mDecodeRegion.top = (int) (mBitmapHeight - bottom); }else{ mDecodeRegion.left = (int) -left; mDecodeRegion.right = mDecodeRegion.left + viewWith; mDecodeRegion.top = (int) -top; mDecodeRegion.bottom = mDecodeRegion.top + viewHeight; } mOptions.inSampleSize = ; Log.e(TAG, "onScroll: mDecodeRegion = " + mDecodeRegion ); && mDecodeRegion.height() > ){ mBitmap = mDecoder.decodeRegion(mDecodeRegion,mOptions); }else{ mBitmap = null; } } invalidate(); } return true; } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { return true; } }; private void initGestureDetector() { scrollDetector = new GestureDetectorCompat(getContext(), simpleOnGestureListener); scaleDetector = new ScaleGestureDetector(getContext(), scaleGestureListener); } @Override public boolean onTouchEvent(MotionEvent event) { boolean ret = scaleDetector.onTouchEvent(event); ret |= scrollDetector.onTouchEvent(event); return ret || true; } * * ; // 256MB private static final String DISK_CACHE_SUBDIR = "thumbnails"; void initCache(){ try { Context context = getContext(); File cacheDir = context.getCacheDir(); cacheDir = context.getExternalCacheDir(); final String cachePath = Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) ||!isExternalStorageRemovable() ? context.getExternalCacheDir().getPath() : context.getCacheDir().getPath(); cacheDir = new File(cachePath + File.separator + DISK_CACHE_SUBDIR); PackageManager pm = context.getPackageManager(); PackageInfo pi = pm.getPackageInfo(context.getPackageName(), ); int appVersion = pi.versionCode; ; mDiskLruCache = DiskLruCache.open(cacheDir, appVersion,valueCount,DISK_CACHE_SIZE); } catch (IOException e) { e.printStackTrace(); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } } void init(){ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setStyle(Paint.Style.FILL); mPaint.setTextSize(); setLayerType(View.LAYER_TYPE_SOFTWARE,mPaint); // LinearGradient backGradient = new LinearGradient(0, 0, 0, mPaint.getTextSize(), new int[]{Color.BLACK, Color.GRAY ,Color.YELLOW}, null, Shader.TileMode.CLAMP); // mPaint.setShader(backGradient); mMatrix = new Matrix(); // initCache(); initGestureDetector(); initRegionDecoder(); } void initRegionDecoder(){ try { InputStream fs = getResources().getAssets().open("world_map.jpg"); mDecoder = BitmapRegionDecoder.newInstance(fs,false); mBitmapWidth = mDecoder.getWidth(); mBitmapHeight = mDecoder.getHeight(); mOptions = new BitmapFactory.Options(); mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888; mOptions.inSampleSize = ; } catch (IOException e) { e.printStackTrace(); } } private void getAttrs(Context context, AttributeSet attrs) { TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.LargeImageViewAttrs); String file = ta.getString(R.styleable.LargeImageViewAttrs_src); ta.recycle(); } public LargeImageView(Context context) { super(context); init(); } public LargeImageView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); getAttrs(context,attrs); init(); } public LargeImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); getAttrs(context,attrs); init(); } @SuppressLint("NewApi") public LargeImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); getAttrs(context,attrs); init(); } @Override protected void onRestoreInstanceState(Parcelable state) { super.onRestoreInstanceState(state); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); } public static int calculateInSampleSize(int width, int height, int reqWidth, int reqHeight) { // Raw height and width of image ; if (height > reqHeight || width > reqWidth) { final ; final ; || halfWidth <= ) return inSampleSize; if (width > height) { // Calculate the largest inSampleSize value that is a power of 2 and keeps both // height and width larger than the requested height and width. while ((halfWidth / inSampleSize) >= reqWidth) { inSampleSize *= ; } } else { while ((halfHeight / inSampleSize) >= reqHeight) { inSampleSize *= ; } } } return inSampleSize; } @Override protected void onDraw(Canvas canvas) { if (mPercentage < 100.0f && mThumbnailBitmap != null){ canvas.drawBitmap(mThumbnailBitmap,mMatrix,mPaint); }else if(mPercentage == 100.0f && mBitmap != null){ canvas.drawBitmap(mBitmap,mBitmapLeft,mBitmapTop,mPaint); } if (mFocus != null){ mPaint.setColor(Color.RED); mPaint.setMaskFilter(, BlurMaskFilter.Blur.SOLID)); mPaint.setColor(Color.parseColor("#ff0000")); canvas.drawCircle(mFocus.x,mFocus.y,,mPaint); } //draw percentage String percentage = mPercentage + "%"; float textSize = mPaint.getTextSize(); float percentWidth = mPaint.measureText("100.0%"); float circleX = getWidth() - percentWidth ; float circleY = percentWidth ; mPaint.setColor(Color.parseColor("#7f7A378B")); mPaint.setMaskFilter(, BlurMaskFilter.Blur.NORMAL)); canvas.drawCircle(circleX ,circleY,percentWidth * 0.66f,mPaint); mPaint.setColor(Color.WHITE); mPaint.setMaskFilter(null); percentWidth = mPaint.measureText(percentage); circleY += textSize / ; circleX -= percentWidth / ; canvas.drawText(percentage,circleX ,circleY,mPaint); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { Log.e(TAG, "onMeasure: " ); int viewWidth = getPaddingLeft() + getPaddingRight() + getSuggestedMinimumWidth(); ) viewWidth = ; viewWidth = resolveSizeAndState(viewWidth, widthMeasureSpec, ); int viewHeight = getSuggestedMinimumHeight() + getPaddingBottom() + getPaddingTop(); ) viewHeight = ; //计算最佳值,在其中解析了 heightMeasureSpec viewHeight = resolveSizeAndState(viewHeight, heightMeasureSpec, ); //将量算的结果保存到View的成员变量mMeasuredWidth 和mMeasuredHeight中。 setMeasuredDimension(viewWidth, viewHeight); // 量算完成之后,View的父控件就可以通过调用 // getMeasuredWidth、getMeasuredState、getMeasuredWidthAndState // 这三个方法获取View的量算结果。 mBitmapLeft = ; mBitmapTop = ; - viewWidth / ; - viewHeight / ; mDecodeRegion = new Rect(left,top,left + viewWidth ,top + viewHeight ); // mDecodeRegion = new Rect(0,0,mBitmapWidth ,mBitmapHeight); mOptions.inSampleSize = calculateInSampleSize(mDecodeRegion.width(),mDecodeRegion.height(),viewWidth,viewHeight); // mOptions.inSampleSize = 2; long begin,end; begin = SystemClock.elapsedRealtime(); mBitmap = mDecoder.decodeRegion(mDecodeRegion,mOptions); end = SystemClock.elapsedRealtime(); thumbnailWidth = mBitmapWidth; thumbnailHeight = mBitmapHeight; BigDecimal bd = ).setScale(,BigDecimal.ROUND_HALF_UP); mPercentage = bd.floatValue(); Log.e(TAG, "init region = " + mDecodeRegion + " ratio = " + (float) mDecodeRegion.width() / mDecodeRegion.height() + " bitmap.w = " + mBitmap.getWidth() + " bitmap.h = " + mBitmap.getHeight() + " ratio = " + (float) mBitmap.getWidth() / mBitmap.getHeight() + " need " + (end - begin) + " ms"); if (mThumbnailBitmap != null){ Log.e(TAG, "onMeasure : mThumbnailBitmap is ok."); float width = mThumbnailBitmap.getWidth(); float height = mThumbnailBitmap.getHeight(); - width / ; - height / ; mMatrix.setTranslate(dx,dy); float factor = mBitmapWidth / width; mMatrix.postScale(factor,factor,viewWidth/ ,viewHeight /); } } @Override protected void onFinishInflate() { super.onFinishInflate(); Log.e(TAG, "onFinishInflate: " ); createThumbnailBitmap(); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); Log.e(TAG, "onAttachedToWindow: " ); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); Log.e(TAG, "onDetachedFromWindow: " ); } @Override protected void onWindowVisibilityChanged(int visibility) { super.onWindowVisibilityChanged(visibility); Log.e(TAG, "onWindowVisibilityChanged : " + visibility); } @Override public void onWindowFocusChanged(boolean hasWindowFocus) { super.onWindowFocusChanged(hasWindowFocus); Log.e(TAG, "onWindowFocusChanged: hasWindowFocus = " + hasWindowFocus ); } Bitmap loadBitmapFromCache(String key){ Bitmap bitmap = null; try { DiskLruCache.Snapshot snapshot = mDiskLruCache.get(key); if (snapshot != null) { InputStream ); bitmap = BitmapFactory.decodeStream(is); } } catch (IOException e) { e.printStackTrace(); } return bitmap; } void pushToCache(String key, Bitmap value){ try { DiskLruCache.Editor editor = mDiskLruCache.edit(key); if (editor != null){ OutputStream ); value.compress(Bitmap.CompressFormat.JPEG, , out); out.flush(); editor.commit(); mDiskLruCache.flush(); } } catch (IOException e) { e.printStackTrace(); } } }
超大图片显示,可任意缩放,移动,不用DiskLruCache的更多相关文章
- JS控制图片显示的大小(图片等比例缩放)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- Java图片工具类,完成图片的截取和任意缩放
package com.common.util; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Renderin ...
- 【JS控制图片显示的大小(图片等比例缩放)】
效果: 代码: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www ...
- C++对于大型图片的加载缩放尝试
Qt对于图片的操作主要集中在这几个类 QImage ,QImageReader ,QPixmap 其中QImage这个类对图片的缩放有几个很不错的技巧,不过对于大图片却并不好使,当我们去看QImage ...
- C#图片处理示例(裁剪,缩放,清晰度,水印)
C#图片处理示例(裁剪,缩放,清晰度,水印) 吴剑 2011-02-20 原创文章,转载必需注明出处:http://www.cnblogs.com/wu-jian/ 前言 需求源自项目中的一些应用,比 ...
- wpf图片浏览器,实现缩放平移操作图片切换等功能
wpf经常要用到控件来查看图片,尤其是高清图片,于是做了一个例子: 1.定义图片的队列,用list来存. private readonly List<string> files; 2.切换 ...
- 实现图片的2次缩放后再进行candy边缘检测
//实现图片的2次缩放后再进行candy边缘检测//Author:SD//Date:2015-9-27#include "cv.h"#include "highgui.h ...
- VS2010 MFC GDI+ 实现PNG透明图片显示
网上找了一些资料学习了一下PNG图的显示,这里总结一下. 参考:http://blog.csdn.net/czyt1988/article/details/7965066 一.VS2010配置GDI+ ...
- 蚂蚁代理免费代理ip爬取(端口图片显示+token检查)
分析 蚂蚁代理的列表页大致是这样的: 端口字段使用了图片显示,并且在图片上还有各种干扰线,保存一个图片到本地用画图打开观察一下: 仔细观察蓝色的线其实是在黑色的数字下面的,其它的干扰线也是,所以这幅图 ...
随机推荐
- 福大软工 · BETA 版冲刺前准备(团队) [已完成]
写在前面 本次作业地址 林燊大哥 过去存在的问题 算法组 没有考虑到数据集不充足的情况.一开始我们将所有数据集按照8:1:1进行分割,分别分配给训练集.开发集和测试集.然鹅后来发现采集到的数据不够充足 ...
- MySQL 存储过程和存储函数 的定义条件和处理程序
#三.定义条件和处理程序 #mysql 存储函数和过程可以将错误 变成我们想要的处理结果分2步骤 #1.定义错误条件 语法:DECLARE 条件名字 CONDITION for 错误编码 #2. 定义 ...
- JAVA中简单的MD5加密类(MD5Utils)
MD5加密分析: JDK API: 获取对象的API: 加密的API: package cn.utils; import java.security.MessageDigest; im ...
- 编写高质量代码改善C#程序的157个建议——建议129:泛型类型参数要以T作为前缀
建议129:泛型类型参数要以T作为前缀 作为一种约定,泛型类型的参数要以T作为前缀.如委托声明: Action<T1,T2> 其中,泛型类型参数名不应该处理成: Action<Arg ...
- 编写高质量代码改善C#程序的157个建议——建议114:MD5不再安全
建议114:MD5不再安全 MD5不再安全不是就算法本身而言的.如果从可逆性的角度出发,MD5值不存在被破解的可能性. MD5被广泛应用于密码验证和消息完整性验证.假设新注册一个用户,当注册用户的密码 ...
- FPGA的时钟质量对设计的影响
小梅哥编写,未经许可严禁用于任何商业用途 近期,一直在调试使用Verilog编写的以太网发送摄像头数据到电脑的工程(以下简称以太网图传).该工程基于今年设计的一款FPGA教学板AC620.AC620上 ...
- 电脑连接真机,但是androidstudio不显示手机,ADB Interface黄色感叹号
1.打开设备管理器 右键计算机 -->管理-->选择设备管理器 2. 步骤如下: 1. 在设备管理器中,找到ADB Interface,右击,选择“更新驱动程序软件” 2. 在弹出的窗口中 ...
- C# xsd 验证 XML数据有效性 问题
使用XSD进行批量数据导入时生成的XML数据有效性这样的功能已经不是第一次做了,之前做的时候都没有碰到什么问题,这些天在开发中遇到了一个很头痛的问题就是无论XSD文件规则怎么写,验证都是通过的. 下面 ...
- ArcGIS应用——使用Python为图斑连续编号及扩展应用
为图斑连续编号 在GIS应用中,为图斑连续编号(编号递增)是一项常见的需求,利用ArcGIS,可以方便的实现. Python脚本如下: rec=0 def autoIncrement(): globa ...
- .net core i上 K8S(一)集群搭建
1.前言 以前搭建集群都是使用nginx反向代理,但现在我们有了更好的选择——K8S.我不打算一上来就讲K8S的知识点,因为知识点还是比较多,我打算先从搭建K8S集群讲起,我也是在搭建集群的过程中熟悉 ...