超大图片显示,可任意缩放,移动,不用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检查)
分析 蚂蚁代理的列表页大致是这样的: 端口字段使用了图片显示,并且在图片上还有各种干扰线,保存一个图片到本地用画图打开观察一下: 仔细观察蓝色的线其实是在黑色的数字下面的,其它的干扰线也是,所以这幅图 ...
随机推荐
- .NET基础 (04)基础类型和语法
基础类型和语法1 .NET中所有内建类型的基类是什么2 System.Object中包含哪些方法,哪些是虚方法3 值类型和引用类型的区别4 简述装箱和拆箱原理5 C#中是否有全局变量6 struct和 ...
- 编写高质量代码改善C#程序的157个建议——建议101:使用扩展方法,向现有类型“添加”方法
建议101:使用扩展方法,向现有类型“添加”方法 考虑如何让一个sealed类型具备新的行为.以往我们会创建一个包装器类,然后为其添加方法,而这看上去一点儿也不优雅.我们也许会考虑修改设计,直接修改s ...
- 洛谷P4178 Tree (点分治)
题目描述 给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K 输入输出格式 输入格式: N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下 ...
- 微软编程一小时 题目2: Longest Repeated Sequence
题目2 : Longest Repeated Sequence 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 You are given a sequence of i ...
- Java 中使用MD5方法加密密码
prequisites 导入包 import java.security.MessageDigest;
- scvmm2008 错误 2912 0x80041001
执行scvmm系列作业时抛出错误 2912 0x80041001. 这个原因是由于主机和vmm通信媒介bits服务挂起所引起的,bits全称Background Intelligent Transfe ...
- [数学趣味001]RSA算法原理及示例
可以先看看这个视频: RSA_Encryption_Algorithm 公开密钥 Perwork: 私钥:Sender和Receiver预先约定加密和解密方案,向其他人保密. 这个实现比较难:向其他人 ...
- Replication--发布属性immediate_sync
在创建发布时,如果选择立即初始化,会将immediate_sync属性设置为true.如果immediate_sync属性为true时,snapshot文件和发布事务及发布命令将一直保留到指定的事务保 ...
- C#操作windows服务,安装、卸载、停止、启动
public class ServiceUtil { private string _ServiceName = string.Empty; private string _AppName = str ...
- docker swarm 命令
初始化swarm manager并制定网卡地址 docker swarm init --advertise-addr 192.168.10.117 强制删除集群,如果是manager,需要加–forc ...