[转载]网站中的图片缓存

mikel阅读(1127)

[转载]网站中的图片缓存 – MIDI 欢迎你:-) – 博客园.

动态页中存在大量图片而影响速度,是在项目开发中所不可以避免的问题,考虑缓存图片却保持页面的执行是个很不错的选择。
实现一个IhttpHandler对特定的文件格式进行处理,对于图片可以是.jpg也可以是其他的格式,当客户端请求有.jpg后缀的文件时IIS自动将文件交给asp_isapi执行然后实现IhttpHandler 接口中的ProcessRequest方法对页面进行缓存,同时还能对图片进行其他的操作,如添加水印,裁剪图片等操作。
具体操作流程如下:在IIS中配置网站添加一个.jpg映射交给asp_isapi处理然后在Web.Config中进行相关配置:
<httpHandlers>
<!–只处理.jpg文件,可以分目录缓存图片aaa/*.jpg–>
<addpath=*.jpgverb=*type=ImageCache.CachingHandler,ImageCache/>
</httpHandlers>
然后在创建一个类CachingHandler : IhttpHandler继承IhttpHandler接口
实现ProcessRequest方法
public void ProcessRequest(HttpContext context)
{
string imagePath = context.Request.PhysicalPath;//获取服务器路径
Bitmap image = null;
image = new Bitmap(imagePath);
context.Response.Cache.SetCacheability(HttpCacheability.Private);//在客户端缓存
context.Response.Cache.SetMaxAge(new TimeSpan(7, 0, 0, 0));//缓存时间为5秒
image.Save(context.Response.OutputStream, ImageFormat.Jpeg);
}
在页面中添加一个图片并执行这个事件
protected void Page_Load(object sender, EventArgs e)
{
Response.Write(DateTime.Now.ToString());
}
可以看到页面没有被缓存但其中的图片确被缓存了下来。
图片缓存和水印实例 下载地址:http://d.download.csdn.net/down/454222/sunchaohuang

[转载]一个Asp.net mvc下的分页控件MvcPagerX

mikel阅读(839)

[转载]【分享】一个Asp.net mvc下的分页控件MvcPagerX – 哥在博客园 – 博客园.

分页再平常不过的需求,其实也很简单完全可以写百行以内的代码扩展到HtmlHelper上实现,但是为了扩展性,我稍微(这所以是稍微,是因为本 人只稍微了解,还不敢说用得很熟练)用了点面向对象的思想对这个分页控件进行了设计,当然设计之前也参考了一些盆友的作品。吸取了一些思想的精华,下面就 讲讲怎么设计以及为什么要这么设计

接口部分:

using System.Collections.Generic;

namespace MvcPagerx
{
    /// <summary>
    /// 分页接口
    /// </summary>
    public interface IPageAble
    {
        /// <summary>
        /// 一个按钮或者少于一个按钮的时候
        /// </summary>
        /// <returns></returns>
        IList<PageButton> GetBtnLessThanOnePage();
        /// <summary>
        /// 第一页时
        /// </summary>
        /// <returns></returns>
        IList<PageButton> GetBtnWhenFrist();
        /// <summary>
        /// 最后一页时
        /// </summary>
        /// <returns></returns>
        IList<PageButton> GetBtnWhenLast();
        /// <summary>
        /// 默认情况
        /// </summary>
        /// <returns></returns>
        IList<PageButton> GetBtnWhenDefault();
        /// <summary>
        /// 分页设置
        /// </summary>
        PagerSettings PagerSetting { get; set; }
    }
}

此接口主要标明实现类可以被分页,在需要分页的各种情况给出反馈,有

一个按钮或者少于一个按钮的时候

第一页时

最后一页时

默认情况

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Routing;
using System.Web.Mvc;

namespace MvcPagerx
{
    /// <summary>
    /// 能够根据分页按钮生成HTML接口
    /// </summary>
    public interface IGeneratePagerHtmlAble
    {
        /// <summary>
        /// PagerSetting
        /// </summary>
        PagerSettings PagerSetting { get; set; }
        /// <summary>
        /// Generate
        /// </summary>
        /// <param name="pageButtons"></param>
        /// <returns></returns>
        MvcHtmlString Generate(IList<PageButton> pageButtons);

        Func<RequestContext, string, int, string> UrlCallback { set; }
    }
}

【分享】一个ASP.NET mvc下的分页控件MvcPagerX
2011-04-21 22:39 by 鲜宏, 1222 visits, 网摘, 收藏, 编辑

分页再平常不过的需求,其实也很简单完全可以写百行以内的代码扩展到HtmlHelper上实现,但是为了扩展性,我稍微(这所以是稍微,是因为本人只稍微了解,还不敢说用得很熟练)用了点面向对象的思想对这个分页控件进行了设计,当然设计之前也参考了一些盆友的作品。吸取了一些思想的精华,下面就讲讲怎么设计以及为什么要这么设计

接口部分:

using System.Collections.Generic;

namespace MvcPagerx
{
///

/// 分页接口
///

public interface IPageAble
{
///

/// 一个按钮或者少于一个按钮的时候
///

///
IList GetBtnLessThanOnePage();
///

/// 第一页时
///

///
IList GetBtnWhenFrist();
///

/// 最后一页时
///

///
IList GetBtnWhenLast();
///

/// 默认情况
///

///
IList GetBtnWhenDefault();
///

/// 分页设置
///

PagerSettings PagerSetting { get; set; }
}
}

此接口主要标明实现类可以被分页,在需要分页的各种情况给出反馈,有

一个按钮或者少于一个按钮的时候

第一页时

最后一页时

默认情况

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Routing;
using System.Web.Mvc;

namespace MvcPagerx
{
///

/// 能够根据分页按钮生成HTML接口
///

public interface IGeneratePagerHtmlAble
{
///

/// PagerSetting
///

PagerSettings PagerSetting { get; set; }
///

/// Generate
///

/// ///
MvcHtmlString Generate(IList pageButtons);

Func UrlCallback { set; }
}
}

这个接口呢用于标明实现类具有生成HTML代码的功能,在这里我们可以看到,传入的参数是IList,返回的是MvcHtmlString,为什么要传入IList,因为这里给这个接口定位很明确就是只是完成将PageButton这种实体列表转换为相应的HTML代码就可以了。那么谁负责生成IList呢,看看上面的IpageAble接口便知道,那就是实现了IpageAble的类,请看下面

实现类部分:

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System;
namespace MvcPagerx
{
    /// <summary>
    /// 普通的分页类
    /// </summary>
    public class NormalPageProc : IPageAble
    {

        #region fields
        private int _StartPageIndex;
        private int _EndPageIndex;
        public PagerSettings PagerSetting { get; set; }
        #endregion

        #region Private Method

        
        private void Init()
        {
            _StartPageIndex = PagerSetting.CurrentPageIndex - (PagerSetting.NumericPagerCount / 2);
            if (_StartPageIndex + PagerSetting.NumericPagerCount > PagerSetting.PageCount)
                _StartPageIndex = PagerSetting.PageCount + 1 - PagerSetting.NumericPagerCount;
            if (_StartPageIndex < 1)
                _StartPageIndex = 1;

            _EndPageIndex = _StartPageIndex + PagerSetting.NumericPagerCount - 1;
            if (_EndPageIndex > PagerSetting.PageCount)
                _EndPageIndex = PagerSetting.PageCount;
        }

        private void AddFristButton(IList<PageButton> pageBtnList)
        {
            PageButton fristitem = new PageButton(PagerSetting.FirstPageText, 1, PagerSetting.CurrentPageIndex == 1, PageButtonType.FirstPageButton);
            pageBtnList.Add(fristitem);
        }

        private void AddPrevButton(IList<PageButton> pageBtnList)
        {
            var previtem = new PageButton(PagerSetting.PrevPageText, PagerSetting.CurrentPageIndex - 1, PagerSetting.CurrentPageIndex == 1, PageButtonType.PrevPageButton);
            pageBtnList.Add(previtem);
        }

        private void AddMoreButtonBefore(IList<PageButton> pageBtnList)
        {
            if (_StartPageIndex > 1 && PagerSetting.ShowMorePagerItems)
            {
                var index = _StartPageIndex - 1;
                if (index < 1) index = 1;
                PageButton item = new PageButton(PagerSetting.MorePageText, index, false, PageButtonType.MorePageButton);
                pageBtnList.Add(item);
            }
        }

        private void AddNumberButton(IList<PageButton> pageBtnList)
        {
            for (var pageIndex = _StartPageIndex; pageIndex <= _EndPageIndex; pageIndex++)
            {
                var text = pageIndex.ToString();
                if (pageIndex == PagerSetting.CurrentPageIndex && !string.IsNullOrEmpty(PagerSetting.CurrentPageNumberFormatString))
                    text = String.Format(PagerSetting.CurrentPageNumberFormatString, text);
                else if (!string.IsNullOrEmpty(PagerSetting.PageNumberFormatString))
                    text = String.Format(PagerSetting.PageNumberFormatString, text);
                var item = new PageButton(text, pageIndex, false, PageButtonType.NumericPageButton);
                pageBtnList.Add(item);
            }
        }

        private void AddMoreButtonAfter(IList<PageButton> pageBtnList)
        {
            if (_EndPageIndex < PagerSetting.PageCount)
            {
                var index = _StartPageIndex + PagerSetting.NumericPagerCount;
                if (index > PagerSetting.PageCount) index = PagerSetting.PageCount;
                var item = new PageButton(PagerSetting.MorePageText, index, false, PageButtonType.MorePageButton);
                pageBtnList.Add(item);
            }
        }

        private void AddNextButton(IList<PageButton> pageBtnList)
        {
            var nextitem = new PageButton(PagerSetting.NextPageText, PagerSetting.CurrentPageIndex + 1, PagerSetting.CurrentPageIndex >= PagerSetting.PageCount, PageButtonType.NextPageButton);
            pageBtnList.Add(nextitem);
        }

        private void AddLastButton(IList<PageButton> pageBtnList)
        {
            var lastitem = new PageButton(PagerSetting.LastPageText, PagerSetting.PageCount, PagerSetting.CurrentPageIndex >= PagerSetting.PageCount, PageButtonType.LastPageButton);
            pageBtnList.Add(lastitem);
        }


        private IList<PageButton> AddButtons()
        {
            IList<PageButton> pageBtnList = new List<PageButton>();
            AddFristButton(pageBtnList);        //<---添加第一页
            AddPrevButton(pageBtnList);         //<---添加前一页
            AddMoreButtonBefore(pageBtnList);   //<---添加更多按钮(前置)
            AddNumberButton(pageBtnList);       //<---添加数字分页按钮
            AddMoreButtonAfter(pageBtnList);    //<---添加更多按钮(后置)
            AddNextButton(pageBtnList);         //<---添加下一页
            AddLastButton(pageBtnList);         //<---添加最后一页
            IEnumerable<PageButton> currentPages = pageBtnList.Where(p => p.PageIndex == PagerSetting.CurrentPageIndex);
            foreach (PageButton btn in currentPages)
                btn.Disabled = true;
            return pageBtnList;
        }
        #endregion

        /// <summary>
        /// 一个按钮或者少于一个按钮的时候
        /// </summary>
        /// <returns></returns>
        public IList<PageButton> GetBtnLessThanOnePage()
        {
            return new List<PageButton>() { 
                new PageButton(PagerSetting.FirstPageText,1,true,PageButtonType.FirstPageButton)
            };
        }

        /// <summary>
        /// 第一页时
        /// </summary>
        /// <returns></returns>
        public IList<PageButton> GetBtnWhenFrist()
        {
            IList<PageButton> defaultPageButtons = GetBtnWhenDefault();
            defaultPageButtons.SingleOrDefault(m => m.ButtonType == PageButtonType.PrevPageButton).Hide = true;
            defaultPageButtons.SingleOrDefault(m => m.ButtonType == PageButtonType.FirstPageButton).Hide = true;
            return defaultPageButtons;
        }

        /// <summary>
        /// 最后一页时
        /// </summary>
        /// <returns></returns>
        public IList<PageButton> GetBtnWhenLast()
        {
            IList<PageButton> defaultPageButtons = GetBtnWhenDefault();
            defaultPageButtons.SingleOrDefault(m => m.ButtonType == PageButtonType.NextPageButton).Hide = true;
            defaultPageButtons.SingleOrDefault(m => m.ButtonType == PageButtonType.LastPageButton).Hide = true;
            return defaultPageButtons;
        }

        /// <summary>
        /// 默认情况
        /// </summary>
        /// <returns></returns>
        public IList<PageButton> GetBtnWhenDefault()
        {
            Init();
            return AddButtons();
        }

    }
}

此类就是普通的分页生成器,在此类实现了IpageAble中定义的各种情况下需要生成的PageButton列表,然后返回给IGeneratePagerHtmlAble的实现类

如下的NormalPagerHtmlGeenerate

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Routing;
using System.Web.Mvc;

namespace MvcPagerx
{
    /// <summary>
    /// 普通分页HTML代码生成类
    /// </summary>
    internal class NormalPagerHtmlGenerate : IGeneratePagerHtmlAble
    {

        private Func<RequestContext, string, int, string> _GetUrlCallback;

        /// <summary>
        /// 分页设置
        /// </summary>
        public PagerSettings PagerSetting { get; set; }


        private string WrapPageButton(PageButton btn)
        {
            string result = string.Empty;
            if (btn.Disabled)
                return String.Format("<li><a disabled=\"disabled\">{0}</a></li>", btn.Text);
            result = String.Format("<li><a href='{0}'>{1}</a></li>", _GetUrlCallback(PagerSetting.HtmlRequestContext, PagerSetting.PageParameterName, btn.PageIndex), btn.Text);
            return result;
        }

        /// <summary>
        /// 生成HTML代码
        /// </summary>
        /// <param name="pageButtons">按钮列表</param>
        /// <returns></returns>
        public MvcHtmlString Generate(IList<PageButton> pageButtons)
        {
            TagBuilder tagBuilder = new TagBuilder(PagerSetting.TagName);
            tagBuilder.GenerateId(PagerSetting.TagID);
            if (!string.IsNullOrEmpty(PagerSetting.ClassName))
                tagBuilder.AddCssClass(PagerSetting.ClassName);
            StringBuilder sb = new StringBuilder();
            foreach (PageButton btn in pageButtons)
            {
                if (!btn.Hide)
                    sb.Append(WrapPageButton(btn));
            }

            tagBuilder.InnerHtml = sb.ToString();
            return MvcHtmlString.Create(tagBuilder.ToString(TagRenderMode.Normal));
        }
        
        public Func<RequestContext, string, int, string> UrlCallback
        {
            set
            {
                _GetUrlCallback = value;
            }
        }
    }
}

交给此类后便能生成HTML代码到前端展示了,还是相当的简单吧,更多的东西直接看代码吧,这里只是提一下大概思路。

MvcPagerx.rar

[转载]第三十六讲:Android手机摄像头编程入门

mikel阅读(895)

[转载]第三十六讲:Android手机摄像头编程入门 « { Android学习指南 }.

本讲内容:Android手机摄像头编程入门

智能手机中的摄像头和普通手机中的摄像头最大的区别在于,智能机上的摄像头可以由程序员写程序控制,做一些有趣的应用譬如,画中画,做一些有用的应用譬如二维码识别,等等。本讲打算通过一个实例,来介绍一下摄像头编程,相关解释都写在代码中了,请注意看代码注释。

实例:窈窈照相机,功能很简单,就是点击程序弹出照相预览界面,点击相机按钮完成照相功能,所照相片会存储在手机存储卡根目录。

1、创建一个项目 Lesson36_Camera ,主程序文件为 MainActivity.java

2、AndroidManifest.xml 中设置屏幕为横屏,并且声明摄像头和存储卡的使用权限,具体代码如下:

<!--?xml version="1.0" encoding="utf-8"?-->

3、本例中不需要布局文件main.xml,因为本例中的UI组建都是动态添加上去的。

4、最后MainActivity.java的代码如下:

package basic.android.lesson36;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Calendar;
import java.util.Locale;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.os.Bundle;
import android.text.format.DateFormat;
import android.util.Log;
import android.view.KeyEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

private CameraView cv;
//准备一个相机对象
private Camera mCamera = null;
//准备一个Bitmap对象
private Bitmap mBitmap = null;

//准备一个保存图片的PictureCallback对象
public Camera.PictureCallback pictureCallback = new Camera.PictureCallback() {

public void onPictureTaken(byte[] data, Camera camera) {
Log.i("yao","onPictureTaken");
Toast.makeText(getApplicationContext(), "正在保存……", Toast.LENGTH_LONG).show();
//用BitmapFactory.decodeByteArray()方法可以把相机传回的裸数据转换成Bitmap对象
mBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
//接下来的工作就是把Bitmap保存成一个存储卡中的文件
File file = new File("/sdcard/YY"+ new DateFormat().format("yyyyMMdd_hhmmss", Calendar.getInstance(Locale.CHINA)) + ".jpg");
try {
file.createNewFile();
BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(file));
mBitmap.compress(Bitmap.CompressFormat.PNG, 100, os);
os.flush();
os.close();
Toast.makeText(getApplicationContext(), "图片保存完毕,在存储卡的根目录", Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
}
}

};

//Activity的创建方法
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

//窗口去掉标题
requestWindowFeature(Window.FEATURE_NO_TITLE);
//窗口设置为全屏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
//设置窗口为半透明
getWindow().setFormat(PixelFormat.TRANSLUCENT);

//提供一个帧布局
FrameLayout  fl = new FrameLayout(this);

//创建一个照相预览用的SurfaceView子类,并放在帧布局的底层
cv = new CameraView(this);
fl.addView(cv);

//创建一个文本框添加在帧布局中,我们可以看到,文字自动出现在了SurfaceView的前面,由此你可以在预览窗口做出各种特殊效果
TextView tv = new TextView(this);
tv.setText("请按\"相机\"按钮拍摄");
fl.addView(tv);

//设置Activity的根内容视图
setContentView(fl);

}

//相机按键按下的事件处理方法
public boolean onKeyDown(int keyCode, KeyEvent event) {
Log.i("yao","MainActivity.onKeyDown");
if (keyCode == KeyEvent.KEYCODE_CAMERA) {
if (mCamera != null) {
Log.i("yao","mCamera.takePicture");
//当按下相机按钮时,执行相机对象的takePicture()方法,该方法有三个回调对象做入参,不需要的时候可以设null
mCamera.takePicture(null, null, pictureCallback);
}
}
return cv.onKeyDown(keyCode, event);
}

// 照相视图
class CameraView extends SurfaceView {

private SurfaceHolder holder = null;

//构造函数
public CameraView(Context context) {
super(context);
Log.i("yao","CameraView");

// 操作surface的holder
holder = this.getHolder();
// 创建SurfaceHolder.Callback对象
holder.addCallback(new SurfaceHolder.Callback() {

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// 停止预览
mCamera.stopPreview();
// 释放相机资源并置空
mCamera.release();
mCamera = null;
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
//当预览视图创建的时候开启相机
mCamera = Camera.open();
try {
//设置预览
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
// 释放相机资源并置空
mCamera.release();
mCamera = null;
}

}

//当surface视图数据发生变化时,处理预览信息
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

//获得相机参数对象
Camera.Parameters parameters = mCamera.getParameters();
//设置格式
parameters.setPictureFormat(PixelFormat.JPEG);
//设置预览大小,这里我的测试机是Milsstone所以设置的是854x480
parameters.setPreviewSize(854, 480);
//设置自动对焦
parameters.setFocusMode("auto");
//设置图片保存时的分辨率大小
parameters.setPictureSize(2592, 1456);
//给相机对象设置刚才设定的参数
mCamera.setParameters(parameters);
//开始预览
mCamera.startPreview();
}
});
// 设置Push缓冲类型,说明surface数据由其他来源提供,而不是用自己的Canvas来绘图,在这里是由摄像头来提供数据
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}

}

}

5、连接Milestone,编译并运行程序:悲剧的是,截图只能看到黑黑的一片,无法截取到摄像头传输过来SurfaceView信息,而在真机中是能看到预览效果的。

device

还是上一张照好的图片给大家吧,(用了好多年的小黑……)

YY20101208_030141

好了,本讲就到这里,谢谢大家的支持和鼓励,下次再见。

[转载]关于网页静态化及SEO问题的一些补充

mikel阅读(960)

[转载]关于网页*静态化*及SEO问题的一些补充 – 老赵点滴 – 追求编程之美 – 博客园.

前一篇讨论“静态页”的文章反响不错,不少朋友发表了自己的看法,也给老赵更多的想法。虽然也在前一篇文章后面回复了不少内容,但是就以往经验来看,总结为一篇新的文章会让我想表达的内容更为明确,对于“静态化”这一非常容易被人误解的概念来说也是非常重要的。

seo我 们还是先来讨论一下,什么叫做“静态页”。有朋友说,放在硬盘上的htm或html文件便是一种静态页,Web服务器不需要做额外的处理,直接读取文件内 容并输出就可以了,而这样的静态文件对于SEO是有帮助的。至于理由,是搜索引擎会对html结尾的文件给更好的权值(这好像还是结论,不是理由),而这 是“常识”,“了解一点SEO的人都知道这个”,“人们普遍在使用的做法”,因此“它一定是正确的”。不过其实Google并不这么认为,百度倒没有给出专业说法。

当 然,我们已经重复强调,但还是需要不断明确的一点是,即使搜索引擎对于“静态页”有更好的倾向性,那也是因为其“URL样式”,而不是“在硬盘上放置了一 个html文件”。请求方(也就是爬虫)只是向服务器端发送一个URL,并获取服务器端给出的内容。它不会关心,也无法了解服务器端究竟是如何得到页面内 容的,对于客户端来说,世界上没有“静态”或“动态”页面之分。有些朋友可能还是会说“不会啊,html就是静态页面,像aspx之类的就是动态页面,前 者不需要在Web服务器上运算,后者需要”。

真是这样的吗?并非如此,因为html文件也是需要Web服务器来运算的。例如,您请求一个html文件,Web服务器至少做了几件事情:

  • 如果请求包含缓存信息,那么处理缓存状态。
  • 根据URL定位到磁盘上的文件。
  • 进行用户认证和授权(如,是否匿名?)。
  • 判断是否有权限读取。
  • 读取文件。
  • 根据文件类型设置MIME的值。
  • 根据文件最后修改日期设置Last-Modified值。
  • 根据文件内容及其他状态设置其E-Tag值。
  • 如果文件内部有include标记,那么读取另一个文件填充进来。

看 看,处理一个文件需要多少“动态运算”啊,这些可都是在Web服务器(如IIS)加载一个html所做的事情。如果您想要观察这些过程,可以阅读一些 Web服务器的源代码,或者去观察一下ASP.NET中System.Web.StaticFileHandler类所做的事情,它也体现了Web服务器 处理html时的关键之处。事实上,如果您在IIS中将html配置给ASP.NET ISAPI的话,或者使用VS自带的Web服务器,最后便是由StaticFileHandler来输出硬盘上的文件的。

所以,虽然我们 看起来Web服务器只是简单地读取了硬盘上的文件,但其实它还是不如我们想象的那么简单。不过对于客户端来说,这一切都是不可知的。例如 Squid,Nginx这样部署在前端的缓存或反向代理服务器,它们都不会关心后端Web服务器是Windows,Linux还是Unix,也不会关心是 IIS,Apache,Lightted甚至是我们自己写的高效或低劣的Web服务器。对于浏览器,爬虫,或前端负载均衡器来说,它们只知道TCP/IP 协议,它们只知道HTTP协议等东西,其他一概不知。

不过,也有朋友坚持认为“生成静态页”来“进行页面缓存”对SEO有帮助。理由是, “进行页面缓存”能够提高网站性能,爬虫更倾向于访问速度更快的页面。从这个角度看来,这种说法的确有一定道理。只是我还是不喜欢这样的看法,因为这种说 法没有把握事物关键。在这里,SEO的关键在于优化网站性能,而生成静态页只是一种手段之一。这并不是适用性最广的,也并非是最容易实现的。如果您直接把 “生成静态页”与“SEO”联系起来,很有可能会对他人造成误解。

当然,如果您的思路没有问题,“静态页”三个字的指代也足够明确,“静 态页有利于SEO”这个命题毫无疑问是正确的。不过我们现在并没有讨论一个命题的逻辑是否正确,我们也不必纠缠于一个表达形式是否严谨,我们的目的是要说 明道理。也正因为如此,老赵才会一遍一遍地写这么多内容。也就是说,这几篇文章的关键在于“说清道理”,我们把握它既可。

最后,老赵再谈一下对SEO这个工作的看法。

seo从 老赵与各SEO人员的接触感觉来看,他们总是有各种理由来说明“问题所在”,只是如果在改进问题之后还是没有效果的话,他们又可以找出各种理由来告诉你为 什么没有效果——但是要知道SEO是一个实践性工作,它的唯一判断依据便是“效果”,而不是“理论”。SEO的理论很容易掌握,但是如果无法真切提高一个 网站在搜索引擎上的表现,这一切还是白搭。老赵认为,一个好的SEO是需要了解网页制作,或者说网站开发的基本技术的,至少要有常识,否则基本上就是在扯 蛋。老赵曾经接触过一个“专业”的SEO公司,那里的“SEO咨询师”给我留下了深刻的印象——负面印象。其“非专业性”从以下几个事件中便可见一斑:

  1. 还 是“静态页”的问题。由于把URL变为.html结尾之后并没有得到明显的效果,他询问我们的实现方式。在得知我们使用了URL重写,而不是在硬盘上放置 html文件时他“惊呼”这种欺骗搜索引擎的行为是会起到反效果的。他强烈要求我们在硬盘上放置html文件。这个要求自然遭到了我们的拒绝,原因之一是 我们是非常动态的网站,很难实现这个需求,但是更重要的是,懂得一点技术的人就知道,Web服务器的处理方式对于搜索引擎爬虫时完全不可见的,我们是否真 正放置html文件与搜索引擎没有任何关系。
  2. 内容的位置问题。在SEO界有种说法是,搜索引擎会更倾向于把页面靠前的内容看的更 重,而把页面靠后的内容权值放低。因此那位专业SEO咨询师指着我们的某张页面说,这部分内容太靠“下方”,很容易被搜索引擎忽略。请注意,他说的是“内 容在页面显示的时候出现在下方”。您觉得这种说法有道理吗?如今页面布局往往使用XHTML+CSS的方式,而搜索引擎只会关注HTML的内容,而“位 置”很大程度上是由CSS,甚至是由JS来控制的。出现在HTML内容前段的内容,在页面呈现时也可以出现在下方,这也和搜索引擎没有任何关系。可惜这一 点也解释了半天。
  3. 最后一条可以说是最可笑的。因为SEO效果不好,那位SEO咨询师觉得只能“来真的”了,于是向我们索要网站的 IIS日志。分析日志对于SEO有些帮助,因为可以看出爬虫的抓取顺序,频率,甚至结果等等,因此查看日志的做法本没有问题。可惜问题在于,对方从MSN 上给出一个邮箱,让我们把过去几个星期的日志发给他。当看到这个要求的时候,老赵几乎要破口大骂。从这点可以看出,这位SEO咨询师缺少必要的常识,他根 本不知道一个中小型的网站,每天便要生成几百兆到几个G的日志。如此没有常识,为什么会有那么多“成功案例”?

老赵的博客 (也就是您正在看的这个)在搜索引擎上的表现也非常糟糕,即使是老赵经常写作的话题,在Google上也很难找到几篇文章,排名也不太靠前。如果不使用 site:cnblogs.com进行限制的话,几乎没有一篇文章是找到我的blog,都是各种地方的转载。为此我也比较苦恼,咨询了一些专业搞SEO的 朋友,做出一些修改之后还是没有太大改善。不过我相信那只是我没有遇上优秀的SEO人员而已,我的博客的潜力还远没有挖掘到底。

如果您是一个专业的SEO人员,或者是专业的SEO公司,不妨给我一些建议——如果可以的话,我也不介意在这方面进行一点投资。不过,如果是一些“肮脏”的优化方式就不必了,例如去论坛上贴链接,发垃圾邮件。我也知道这些做法很有效果,但是我不想这样做。

[转载]Android OpenGL 学习笔记 --开始篇

mikel阅读(940)

[转载]Android OpenGL 学习笔记 –开始篇 – Terry_龙 – 博客园.

1、什么是 OpenGL?

OpenGL 是个专业的3D程序接口,是一个功能强大,调用方便的底层3D图形库。OpenGL 的前身是 SGI 公司为其图形工作站开的 IRIS GL。IRIS GL 是一个工业标准的3D图形软件接口,功能虽然强大但是移植性不好,于是 SGI 公司便在 IRIS GL 的基础上开发 OpenGL 。具体详细的介绍请 点击这里

2、OpenGL 的发展历程

1992年7月 发布了 OpenGL 1.0 版本,并与微软共同推出 Windows NT 版本的 OpenGL

1995年 OpenGL 1.1 版本面市,加入了新功能,并引入了纹理特性等等。

一直到 2009年8月Khronos小组发布了OpenGL 3.2,这是一年以来OpenGL进行的第三次重要升级。

具体特点及功能、 OpenGL 现状、发展历程、OpenGL 规范、编程入门请 点击这里

3、OpenGL  ES 简介

Android 3D 引擎采用的是OpenGL ESOpenGL ES是一套为手持和嵌入式系统设计的3D引擎API,由Khronos公司维护。在PC领域,一直有两种标准的3D API进行竞争,OpenGL DirectX。一般主流的游戏和显卡都支持这两种渲染方式,DirectXWindows平台上有很大的优势,但是 OpenGL 具有更好的跨平台性。

由于嵌入式系统和PC相比,一般说来,CPU、内存等都比PC差很多,而且对能耗有着特殊的要求,许多嵌入式设备并没有浮点运算协处理器,针对嵌入式系统的以上特点,Khronos对标准的 OpenGL 系统进行了维护和改动,以期望满足嵌入式设备对3D绘图的要求。

4、 Android OpenGL ES 简介

Android系统使用 OpenGL 的标准接口来支持3D图形功能,android 3D 图形系统也分为 java 框架和本地代码两部分。本地代码主要实现的 OpenGL 接口的库,在 Java 框架层,javax.microedition.khronos.opengles java 标准的 OpenGL 包,android.opengl包提供了 OpenGL 系统和 Android GUI 系统之间的联系。

5、Android 支持 OpenGL 列表

  • 1、GL
  • 2、GL 10
  • 3、GL 10 EXT
  • 4、GL 11
  • 5、GL 11 EXT
  • 6、GL 11 ExtensionPack

我们将使用 GL10 这个类开始接触 OpenGL ,探索3D 领域。

6、一步一步实现自己的 Renderer 类

在 Android 中我们使用 GLSurfaceView 来显示 OpenGL 视图,该类位于 android.opengl 包里面。它提供了一个专门用于渲染3D 的接口 Renderer 。接下来我们就来一步步构建自己的 Renderer 类。

1、为 Renderer 类赶回命名空间

import android.opengl.GLSurfaceView.Renderer;

2、新建一个类来实现 Renderer 接口,代码如下:

public class ThreeDGl implements Renderer
{
}

3、如上代码所写,程序实现了 Renderer 类,则必须重写以下方法

public void onDrawFrame(GL10 gl)
{
}
public void onSurfaceChanged(GL10 gl, int width, int height)
{}
public void onSurfaceCreated(GL10 gl, EGLConfig config)
{}

4、当窗口被创建时需要调用 onSurfaceCreate ,我们可以在这里对 OpenGL 做一些初始化工作,例如:

               // 启用阴影平滑
        gl.glShadeModel(GL10.GL_SMOOTH);

        // 黑色背景
        gl.glClearColor(0, 0, 0, 0);

        // 设置深度缓存
        gl.glClearDepthf(1.0f);
        // 启用深度测试
        gl.glEnable(GL10.GL_DEPTH_TEST);
        // 所作深度测试的类型
        gl.glDepthFunc(GL10.GL_LEQUAL);

        // 告诉系统对透视进行修正
        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);

glHint 用于告诉 OpenGL 我们希望进行最好的透视修正,这会轻微地影响性能,但会使得透视图更好看。
glClearColor 设置清除屏幕时所用的颜色,色彩值的范围从 0.0f~1.0f 大小从暗到这的过程。
glShadeModel 用于启用阴影平滑度。阴影平滑通过多边形精细地混合色彩,并对外部光进行平滑。
glDepthFunc 为将深度缓存设想为屏幕后面的层,它不断地对物体进入屏幕内部的深度进行跟踪。
glEnable 启用深度测试。
5、当窗口大小发生改变时系统将调用 onSurfaceChange 方法,可以在该方法中设置 OpenGL 场景大小 ,代码如下:

//设置OpenGL场景的大小
gl.glViewport(0, 0, width, height);

6、场景画出来了,接下来我们就要实现场景里面的内容,比如:设置它的透视图,让它有种越远的东西看起来越小的感觉,代码如下:

//设置投影矩阵
        gl.glMatrixMode(GL10.GL_PROJECTION);
        //重置投影矩阵
        gl.glLoadIdentity();
        // 设置视口的大小
        gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
        // 选择模型观察矩阵
        gl.glMatrixMode(GL10.GL_MODELVIEW);
        // 重置模型观察矩阵
        gl.glLoadIdentity();

gl.glMatrixMode(GL10.GL_PROJECTION); 指明接下来的代码将影响 projection matrix (投影矩阵),投影矩阵负责为场景增加透视度。
gl.glLoadIdentity(); 此方法相当于我们手机的重置功能,它将所选择的矩阵状态恢复成原始状态,调用 glLoadIdentity(); 之后为场景设置透视图。
gl.glMatrixMode(GL10.GL_MODELVIEW); 指明任何新的变换将会影响 modelview matrix (模型观察矩阵)。
gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10); 此方法,前面4个参数用于确定窗口的大小,而后面两个参数分别是在场景中所能绘制深度的起点和终点。
7、了解了上面两个重写方法的作用和功能之后,第三个方法 onDrawFrame 从字面上理解就知道此方法做绘制图操作的。嗯,没错。在绘图之前,需要将屏幕清除成前面所指定的颜色,清除尝试缓存并且重置场景,然后就可以绘图了, 代码如下:

// 清除屏幕和深度缓存
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// 重置当前的模型观察矩阵
gl.glLoadIdentity();

8、Renderer 类在实现了上面的三个重写之后,在程序入口中只需要调用

Renderer render=new ThreeDGl(this);
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        GLSurfaceView gview=new GLSurfaceView(this);
        gview.setRenderer(render);
        setContentView(gview);
    }

到此基本对 OpenGL 有一些了解,当然OpenGL 还有更多的东西需要我们去探索,努力吧。

[转载]Android 播放Gif 动画

mikel阅读(1605)

[转载]Android 播放Gif 动画 – Terry_龙 – 博客园.

Android 中是不支持直接使用Gif 图片关联播放帧动画,如下动画在Android 中是无法播放的:

Android 提供了另外一种解决的办法,就是使用AnimationDrawable 这一函数使其支持逐帧播放,但是如何把gif 图片打散开来,成为每一帧的图片呢?下面介绍两种比较不错的软件,可以帮我们打散图片。

gifsplitter2.0

下载地址:gif分割

使用方法如下:

这一软件分割图片都是bmp图片,图片比较大,这里不推荐使用,尽量节省不必要的字节,所以这里推荐使用如下 软件

easygifanimator

软件下载:动画分割器

使用方法如下:

点击文件将帧文件导出即可

得到了帧文件后我们可以就编写代码,在res目录下新建anim动画文件夹,写下如下代码

<?xml version=”1.0″ encoding=”UTF-8″?>
<animation-list android:oneshot=”false”
xmlns:android
=”http://schemas.android.com/apk/res/android”>
<item android:duration=”150″ android:drawable=”@drawable/xiu0″ />
<item android:duration=”150″ android:drawable=”@drawable/xiu1″ />
<item android:duration=”150″ android:drawable=”@drawable/xiu2″ />
<item android:duration=”150″ android:drawable=”@drawable/xiu3″ />
</animation-list>

对应的item 为顺序的图片从开始到结束,duration为每张逐帧播放间隔,oneshot 为false 代表循环播放,设置为true 即播放一次即停止。

对应Activity 代码如下编写:


import android.app.Activity;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;

public class animActivity extends Activity implements OnClickListener {
ImageView iv
= null;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

iv = (ImageView) findViewById(R.id.ImageView01);
iv.setOnClickListener(
this);
}

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
AnimationDrawable anim = null;
Object ob
= iv.getBackground();
anim
= (AnimationDrawable) ob;
anim.stop();
anim.start();
}
}

使用AnimationDrawable 对象获得图片的图片,然后指定这个AnimationDrawable 开始播放动画

Tip:使用此方法不会默认播放,必须要有事件触发才可播放动画,如上面的通过点击监听触发动画的播放

那么如何使用图片自动播放呢?我们可以联想一下,ProgressBar 是不是默认的时候就会转,那就是那个圆形的进度条,是的。我们可以对它进行改造合它也可以自动播放,在Values 文件下新建一个styles 文件,编写如下代码 :

<?xml version=”1.0″ encoding=”UTF-8″?>
<resources>
<style name=”animStyle” parent=”@android:style/Widget.ProgressBar.Large”>
<item name=”android:indeterminateDrawable”>@anim/test</item>
</style>
</resources>

上面样式文件自Widget.ProgressBar.Large 为其设置动画文件,我们在XML中就可以通过设置它的样式使其为我们工作

<ProgressBar android:id=”@+id/ProgressBar01″ style=”@style/animStyle”
android:layout_width
=”128px” android:layout_height=”128px”></ProgressBar>

OK,就是这么简单,下面看看运行效果:

源码下载:Demo

转载Android NDK(Eclipse+Cygwin+NDK)的开发

mikel阅读(932)

转载Android NDK(Eclipse+Cygwin+NDK)的开发 – 正正博客 – 博客园.

本篇博客在cnblogs首发:http://www.cnblogs.com/zzc1986

开发问题:

我非常喜欢Eclipse这个IDE,因此,这是我的首选了。而目前Android的NDK开发离不开Linux环境,大家却对Windows比较熟悉,在Windows平台最好的模拟Linux环境的就是Cygwin了,好马上开始了。

Eclipse CDT安装和Cygwin的安装就不多说了,注意Cygwin一定要安装好所有的gnu工具,比如gcc,gdb等,建议出去特别专业外的全部安装,这样 就有了一个比较完整的Linux开发环境。但是,Cygwin在最近版本中却不能与Eclipse进行很好的集成,参考:http://www.2009fly.com/index/a/bianchengyuyan/C_C__/2011/0119/232.html。为了使用,请跟着我做简单的如下配置,参考中虽然也提供了方法,但是我并没有配置成功,估计是不是新版本又有所改变。好了,来做如下配置:

1、  首先,你要建立一个标准的C/C++工程,然后在工程的属性作如下配置:选中C/C++ Build->Tool Chain Editor,在右边的Current toolchain中选择Cygwin GCC。

2、  在C/C++ Build->Settings 中,你需要做一下几个方面的配置。在Cygwin C Compiler->Includes中,设置你的Cygwin的include路径,比如,我的是:

E:\cygwin\usr\include

E:\cygwin\usr\include\w32api

完成上面的配置后,你如果写代码,就可以看到提示了,而且原来可恶的警告提示符也不见了。

3、  目前你能编译了,但是link呢?很好办,在你的Cygwin C Linker->Libraries中的Library search path(-L)中配置你的library路径,我的是:

E:\cygwin\lib

在Cygwin C Linker->Libraries的Libraries(-l)中填写你需要连接的库,注意,比如libxml2.so,你只需要写xml2就够了,Linux下开发的都应该清楚的啊。

现在开发没有问题了,但是我们要进行的是Android上的开发啊,呵呵,刚才我配置的是PC上的开发,其实也没有关系啊,只要把上面的 include设置成你针对的android平台的include就可以了。比如我的是针对的Android-8,也就是Android2.2,那么我把 include设置成:

E:\Android\android-ndk-r4\build\platforms\android-8\arch-arm\usr\include

这样就可以了,至于link的library么,那就不用设置了,因为我们只想用Eclipse来完成编码,而编译就交给ndk-build了,当 然,你要会写Android.mk文件的奥。还有一点,要提醒的是,如果你的程序需要Android ndk还没有公开的API,那么,你可以直接去Android的git库里面将其代码下载下来。放心,你不需要重新编译的,知识利用里面的头文件就好,然 后配置到Eclipse CDT的include目录用来完成代码编写,配置到Android.mk文件用来compile、link。那么link的时候so去哪里找呢,呵呵, 就在你的Android模拟器中啊,或者说就在你的真机上呢,将他们下载到你的platfoms的目录中就可以了:

E:\Android\android-ndk-r4\build\platforms\android-8\arch-arm\usr\lib

不过要注意版本奥。有些so没问题,但是有些却是有问题的奥,比如icu4c库,也就是libicucore.so。那么,怎样用ndk-build呢,呵呵,你现在有Cygwin了,ndk-build就可以直接使用了,请参考Android ndk的官方文档。

奥,我的Eclipse是Helios Service Release 1,CDT版本是7.0.1.201009141542。下次也会在这个版本上讲解“Android NDK(Eclipse+Cygwin+NDK)的调试”。欢迎大家加入Andorid高级开发群:72565180来进行讨论奥,里面有很多的高手和资料等着你呢。

====================================================================

版权所有,欢迎转载,请在转载前注明原文出处:正正博客

CNBlogs URL:http://www.cnblogs.com/zzc1986

尊重别人的劳动成果也就是尊重自己!

推荐:Android交流群: 72565180

====================================================================

正正博客:http://www.2009fly.com/

[转载]android源码解析 ---- camera 照相机 摄像机

mikel阅读(814)

Android源码解析 —- camera 照相机 摄像机 

文章出处:http://blog.csdn.net/dany1202/archive/2011/01/26/6164450.aspx

一.camera启动
1.一个activity启动调用流程:
onCreate()–>onStart()–>onResume()
onCreate():
1.可添加所需布局文件,画界面。
2.开启线程,启动硬件摄像头,调用CameraHolder.instance().open()得到一个Android.hardwareCamera实例mCameraDevice
ensureCameraDevice()–>CameraHolder.instance().open()–>mCameraDevice.getParameters();确保摄像头存在,并将摄像头打开。
startPreview();开始取景预览
3.创建 VideoPreview 的SurfaceHolder,同时注册callback函数,当VideoPreview的长宽变化时,调用SurfaceChanged()函数
mSurfaceView = (SurfaceView) findViewById(R.id.camera_preview);
SurfaceHolder holder = mSurfaceView.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
4.mIsImageCaptureIntent是否为从短信息或联系人编辑界面发送的intent到camera
mIsImageCaptureIntent = isImageCaptureIntent();当该函数返回true时,表示从短信息或联系人界面跳转到拍照界面;
为false时,表示从桌面程序正常启动camera;要注意两种不同情况所需的右侧界面功能按钮区有变动。
onStart():
1.mSwitcher.setSwitch(SWITCH_CAMERA)设置拍照录像切换按钮切换到照相模式。
onResume()
startPreview()重新开始预览
1.当按home键退出程序时,会掉用stopPreview(),故再次进入时,会执行onResume()函数,在此函数中,应重新开启预览功能。
2.keepScreenOnAwhile()点亮屏幕,防止屏幕变黑。

2.拍照录像切换功能
1.Switcher继承自ImageView,在布局文件中直接布局即可
2.mSwitch为true时,滑块在下方,显示拍照界面;当mSwitch为false时,滑块在上方,显示录像界面。
3.当点击或触碰拍照录像切换按钮时:
MotionEvent.ACTION_UP–>tryToSetSwitch()–>mListener.onSwitchChanged(this, onOff)
在camera.java中实现该接口,调用switchToVideoMode()–>MenuHelper.gotoVideoMode(this)–>startCameraActivity(),并结束当前程序。

3.updateThumbnailButton()更新功能按钮去的到相簿按钮
1.调用事件:
initializeFirstTime初始化时调用
initializeSecondTime()时调用
Intent.ACTION_MEDIA_SCANNER_FINISHED,扫描SD卡结束时调用
2.mThumbController.isUriValid(),当图库里有图片时,值为TRUE;当图库里无图片时,值为FALSE。
3.updateLastImage()更新到相簿按钮上的显示图片。
4.mThumbController.updateDisplayIfNeeded()–>if (mUri == null) mButton.setImageDrawable(null);当图库无照片时,此处不显示任何照片。

4.shutterButton拍照按钮
1.对焦调用流程
按下屏幕上的ShutterButton 按钮。
ShutterButton.java中的监听线程 调用callShutterButtonFocus(),这个函数会调用接口 ShutterButton.OnShutterButtonListener 的函数onShutterButtonFocus()。
Camera.java实现了接口ShutterButton.OnShutterButtonListener。故Camera.java中的函数onShutterButtonFocus()被调用。
接着的执行流程为—–> doFocus()——>autoFocus()—>mCameraDevice.autoFocus()
2.拍照调用流程
之后ShutterButton.java调用performClick(),这个函数中调用了Camera.java中的onShutterButtonClick()
接着的执行流程为 —–>dosnap()—–>ImagePicture.onSnap()—–>ImageCapture.initiate()—->ImageCapture.capture() 此函数执行完后,takepicture 过程完成
takePicture 完成后,surfaceChanged()将被调用将刚照下的照片显示在屏幕上。
Camera.java中的回调接口JpegPictureCallback中的函数onPictureTaken()接着执行。这个函数先调用ImageCapture.storeImage()将jpeg图像数据存储在内存。
3.picture 的thumbnail显示过程:
ImageCapture.storeImage()—>ImageCapture.setLastPictureThumb()—> mThumbController.setData(uri, lastPictureThumb);

5.布局文件

1.attach_camera_control.xml,当从短信息或联系人界面,进入camera时,右侧功能按钮区的“确定” “重拍”及“取消”

2.camera_control.xml,camera和videocamera主界面右侧的功能按钮区的布局

3.camera.xml,camera主界面左侧预览取景区的布局

4.video_camera.xml,videocamera主界面左侧预览取景区的布局

5.on_screen_hint.xml,SD卡相关信息的输出,如在屏幕下方提示“使用相机前请先插入 SD 卡。”

6.照相机SD卡

1.BroadcastReceiver mReceiver,接受SD卡发出的状态变化消息。

2.Intent.ACTION_MEDIA_MOUNTED 挂在

Intent.ACTION_MEDIA_UNMOUNTED 未挂在

Intent.ACTION_MEDIA_CHECKING SD卡从未插入到插入的过程中会调用此状态

Intent.ACTION_MEDIA_SCANNER_FINISHED 扫描SD卡结束,即SD卡进入可使用状态

3.checkStorage()->calculatePicturesRemaining()->MenuHelper.calculatePicturesRemaining()计算SD卡剩余空间

4.updateStorageHint()更新界面提示显示文字

其中MenuHelper.NO_STORAGE_ERROR包含SD卡状态:MEDIA_CHECKING,MEDIA_SHARED,等SD卡被移除状态

state = Environment.getExternalStorageState()获取SD卡状态

如state.equals(Environment.MEDIA_CHECKING)表示SD卡正在准备中

mStorageHint = OnScreenHint.makeText(this, noStorageText);设置当前界面需显示的内容

mStorageHint.show();显示SD卡状态文字

7. 摄像机SD卡,比照相机稍微麻烦一些

1.onResume()函数中注册receive事件

IntentFilter intentFilter =
new IntentFilter(Intent.ACTION_MEDIA_MOUNTED);
intentFilter.addAction(Intent.ACTION_MEDIA_EJECT);
intentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);
intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
intentFilter.addDataScheme(“file”);
mReceiver = new MyBroadcastReceiver();
registerReceiver(mReceiver, intentFilter);
mStorageStatus = getStorageStatus(true);

2.class MyBroadcastReceiver处理接收到的如上注册事件

比如其中

if (action.equals(Intent.ACTION_MEDIA_EJECT)) {
updateAndShowStorageHint(false);
stopVideoRecording();
}在当拔出SD卡是触发

3.updateAndShowStorageHint()->getStorageStatus()

此处 当remaining == NO_STORAGE_ERROR,可添加如SHARE,CHECKING等状态的处理

根据不同的状态,返回不同的值

例如:

if (state.equals(Environment.MEDIA_CHECKING)) {
return STORAGE_STATUS_PREPARE;
}else if(state.equals(Environment.MEDIA_SHARED)){
return STORAGE_STATUS_SHARE;
}else {
return STORAGE_STATUS_NONE;
}

当然,所填家的事件需要在1.2步骤中进行注册并调用此函数

4.showStorageHint()

在switch (mStorageStatus)处理所需显示信息

例如,添加如下case语句,处理如上添加的SHARE状态

case STORAGE_STATUS_SHARE:
errorMessage = getString(R.string.sdcard_busy_message);
break;

5.mStorageHint = OnScreenHint.makeText(this, errorMessage);设置所需显示文字内容

6.mStorageHint.show();显示在当前摄像机界面中

8.取景预览去右侧设置条

1.在oncreat()或者xml文件中,我们找不到设置项对应的布局,那么设置项是在什么地方添加的呢?

changeHeadUpDisplayState()该函数即位添加此布局的入口。

2.res/xml/camera_preferences.xml

其相应的图片及文字值位于该xml文件下

(未完待续)

[转载]android 之摄像头

mikel阅读(806)

[转载]android 之摄像头 – rangq1的专栏 – CSDN博客.

用google查了一下camera方面的资料,前几页的检索内容居然一模一样的,真是浪费时间,严重鄙视一下。

既然要用到硬件肯定要牵涉到权限,

在Mainifest.xml中加入camera的权限:

<uses-permission Android:name=”Android.permission.CAMERA”></uses-permission>

<uses-feature android:name=”android.hardware.camera” />
<uses-feature android:name=”android.hardware.camera.autofocus” />

调用camera最简单的办法是调用系统的功能,然后通过onActivityResult方法获得图像数据。

不是太习惯用android的xml配置文件,但是为了代码简单,先加一个layout.xml

<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”
android:orientation=”vertical” android:layout_width=”fill_parent”
android:layout_height=”fill_parent”>
<TextView android:text=”Camera Demo” android:id=”@+id/TextView01″
android:layout_width=”fill_parent” android:layout_height=”wrap_content”></TextView>
<RelativeLayout android:id=”@+id/FrameLayout01″ android:layout_weight=”1″
android:layout_width=”fill_parent” android:layout_height=”fill_parent”></RelativeLayout>
<Button android:text=”test” android:id=”@+id/Button01″
android:layout_width=”wrap_content” android:layout_height=”wrap_content” android:layout_gravity=”center”></Button>
</LinearLayout>

系统camera的uri为:

android.media.action.IMAGE_CAPTURE

final int TAKE_PICTURE = 1;
ImageView iv;


private void test1(){

iv = new ImageView(this);

((FrameLayout)findViewById(R.id.FrameLayout01)).addView(iv);

Button buttonClick = (Button)findViewById(R.id.Button01);

buttonClick.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View arg0) {
startActivityForResult(new Intent(“android.media.action.IMAGE_CAPTURE”), TAKE_PICTURE);
}

});

}

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == TAKE_PICTURE) {
if (resultCode == RESULT_OK) {
Bitmap b = (Bitmap) data.getExtras().get(“data”);
iv.setImageBitmap(b);
}
}
}

系统功能很简单,呵呵,不过不能满足俺小小的控制欲,看看camera类能干些什么。

首先扫描了一下camera,感觉camera主要是用到几个接口:

1.需要SurfaceHolder类来显示图像,并获取SurfaceHolder类传递给Camera,Camera以后通过该Holder对图像进行处理。

所以程序中需要SurfaceView子类,并实现SurfaceHolder.Callback 接口:

public void surfaceChanged(SurfaceHolder holder, int format, int width,int height)

public void surfaceCreated(SurfaceHolder holder)

public void surfaceDestroyed(SurfaceHolder holder)

如:public class Preview extends SurfaceView implements SurfaceHolder.Callback

2.拍摄相片主要用到如下方法:

public final void takePicture(ShutterCallback shutter, PictureCallback raw, PictureCallback jpeg)

方法中的参数是几个回调接口:

ShutterCallback

void onShutter();

拍照时调用该接口,用于按下拍摄按钮后播放声音等操作

PictureCallback

void onPictureTaken(byte[] data, Camera camera);

拍照时调用该接口,data为拍摄照片数据,camera为Camera类自身

takePicture方法中有两个PictureCallback,看参数名好像一个是原始数据,一个是jpeg数据。

3.还有一个预览方式

PreviewCallback

void onPreviewFrame(byte[] data, Camera camera);

该接口可以获取摄像头每一帧的图像数据

此外此外还有几个辅助方法:

startPreview()
stopPreview()
previewEnabled()

4.其它方法:

①自动对焦 AutoFocusCallback

void onAutoFocus(boolean success, Camera camera);

摄像头自动对焦,success表示自动对焦是否成功

ErrorCallback

void onError(int error, Camera camera)

摄像头发生错误是调用该接口,

CAMERA_ERROR_UNKNOWN

CAMERA_ERROR_SERVER_DIED 表示媒体服务已经当掉,需要释放Camera重新启动

③setParameters(Parameters params)

设置摄像头参数

先来做一个最简单的测试:

用来表现图像的SurfaceView子类,Android的例子里面有一个,直接拿过来用用:

class camerView extends SurfaceView implements SurfaceHolder.Callback{
SurfaceHolder mHolder;
Camera mCamera;

public camerView(Context context) {
super(context);

mHolder = this.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}

public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(width, height);
mCamera.setParameters(parameters);
mCamera.startPreview();
}

public void surfaceCreated(SurfaceHolder holder) {
mCamera = Camera.open();
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException exception) {
mCamera.release();
mCamera = null;
}
}

public void surfaceDestroyed(SurfaceHolder holder) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}

public void draw(Canvas canvas){
super.draw(canvas);
Log.d(“===>”, “draw”);
}
}

内容比较简单,Camera的管理都跟camerView 的几个接口绑在一块。

下来把View加到Active中去,同时用用 takePicture方法:

private void test2(){
cv = new camerView(this);
RelativeLayout relay = (RelativeLayout)findViewById(R.id.FrameLayout01);
relay.addView(cv);

buttonClick = (Button)findViewById(R.id.Button01);
buttonClick.setOnClickListener(new OnClickListener(){
public void onClick(View arg0) {
cv.mCamera.takePicture(
new ShutterCallback(){
public void onShutter() {
Log.d(“===>”, “onShutter”);
}},
new PictureCallback(){
public void onPictureTaken(byte[] data, Camera camera) {
Log.d(“===>”, “raw:” + (data == null ? “null” : data.length));
}},//raw
new PictureCallback(){
public void onPictureTaken(byte[] data, Camera camera) {
Log.d(“===>”, “postview:” + (data == null ? “null” : data.length));
}}, //postview
new PictureCallback(){
public void onPictureTaken(byte[] data, Camera camera) {
Log.d(“===>”, “jpeg:” + (data == null ? “null” : data.length));
}} // jpeg
);
}
});
}

这样所有的代码就完成了,在模拟器上点击test按钮,在log中可以看到:

===>onShutter

===>raw:null

===>jpeg:18474

很奇怪的是 camerView中的 ===>draw没有输出,说明View不进行绘制,那么摄像图像是怎么出来的呢?

源代码中是调用本地方法,懒得去看C代码,不想钻得太深,娱乐而已。

上网查了一半天也没有搞明白,感觉是通过SurfaceHolder获得View的Canvas对象,直接进行绘制,Holder中没有View的引用,当然不会再去调用View的draw方法了。

最后在网上搜到文章一篇,对这个原因有一点说明,Copy之,以防后面忘记:

在通常情况 下,OPhone程序中的View都是在同一个GUI线程中绘制的,该线程也是接收用户交互事件的线程(例如:按钮点击事件)。从另外的 线程修改GUI元素是不可以的,如果要迅速的更新UI显示该如何办?显然在主线程中还需要处理其他事件,不适合做这件事情,所以OPhone提供了 SurfaceView 来满足这种需求。一个SurfaceView 包装一个Surface对象(通过SurfaceHolder操作该对象)而不是Canvas对象,这就是关键所在,Surface可以在其他线程中绘 制,这对于周期性更新和要求高帧率的场景来说是很有用的,特别是在游戏开发中。Surface中包含了当前UI的原生数据(raw data),在不同的软件和硬件条件下对这些数据的处理是不一样的,这就可以通过一些设置来加速图形的绘制,可以通过SurfaceHolder的 setType函数来设置,目前接收如下的参数:

SURFACE_TYPE_NORMAL :用RAM缓存原生数据的普通Surface
SURFACE_TYPE_HARDWARE :适用于DMA(Direct memory access )引擎和硬件加速的Surface
SURFACE_TYPE_GPU :适用于GPU加速的Surface
SURFACE_TYPE_PUSH_BUFFERS :表明该Surface不包含原生数 据,Surface用到的数据由其他对象提供,在Camera图像预览中就使用该类型的Surface,有Camera负责提供给预览Surface数 据,这样图像预览会比较流畅。如果在这里设置了上面三种类型则可以发现不会出现预览图像,在和Camera底层的预览机制实现有关,如果对预览有特殊要求 的可以现实PreviewCallback 接口来自己处理

如果想在图像上叠加一些文字等透明信息的时候,总不能也像j2me一样地处理吧。

后面看到一篇文章介绍,直接将一个View叠加到Camera上就可以了,开始还不相信,后面实在找不到其它办法,试一试看看:

在test2()中加入

TextView tv = new TextView(this);
tv.setText(“test”);

RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
lp.addRule(RelativeLayout.CENTER_IN_PARENT);
relay.addView(tv, lp);

果然可以。呵呵,分了一下神,再回来看看Camera。

既然jpeg数据有输出,看看jpeg是什么内容,

new PictureCallback(){

public void onPictureTaken(byte[] data, Camera camera) {
Log.d(“===>”, “jpeg:” + (data == null ? “null” : data.length));
}} // jpeg

在jpeg的回调接口中添加内容

Log.d(“===>”, “jpeg:” + (data == null ? “null” : data.length));
cv.setVisibility(View.INVISIBLE);
ImageView iv = new ImageView(test.this);
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
iv.setImageBitmap(bitmap);
relay.addView(iv);

其中的test是类名,另外需要把relay改成final变量:

final RelativeLayout relay = (RelativeLayout)findViewById(R.id.FrameLayout01);

呵呵,又看到那幅熟悉的图片了,帅。

raw数据没有输出,网上也有人提问,外网被屏蔽了看不到详细的信息,那就此处不表下次再说了。

看看能不能设置一下参数就可以有输出了,在好奇的驱使下,又试了一下设置参数。

从log中可以看到Parameters预设的参数:

picture-format=jpeg
picture-preview=yuv422sp
很可惜,设置为其它的参数系统都报错,玩不转,郁闷,看来要在摄像头这一块抱太多的遗憾了。

算了,看看Camera最后一点功能吧,获取帧数据:

mCamera.setPreviewCallback(new PreviewCallback(){
public void onPreviewFrame(byte[] data, Camera camera) {
Log.d(“===>”, “onPreviewFrame”);
}
});

其中的data是yuv格式的,需要对其解码:

static public void decodeYUV420SP(byte[] rgbBuf, byte[] yuv420sp, int width, int height) {
final int frameSize = width * height;
if (rgbBuf == null)
throw new NullPointerException(“buffer ‘rgbBuf’ is null”);
if (rgbBuf.length < frameSize * 3)
throw new IllegalArgumentException(“buffer ‘rgbBuf’ size ”
+ rgbBuf.length + ” < minimum ” + frameSize * 3);

if (yuv420sp == null)
throw new NullPointerException(“buffer ‘yuv420sp’ is null”);

if (yuv420sp.length < frameSize * 3 / 2)
throw new IllegalArgumentException(“buffer ‘yuv420sp’ size ” + yuv420sp.length
+ ” < minimum ” + frameSize * 3 / 2);

int i = 0, y = 0;
int uvp = 0, u = 0, v = 0;
int y1192 = 0, r = 0, g = 0, b = 0;

for (int j = 0, yp = 0; j < height; j++) {
uvp = frameSize + (j >> 1) * width;
u = 0;
v = 0;
for (i = 0; i < width; i++, yp++) {
y = (0xff & ((int) yuv420sp[yp])) – 16;
if (y < 0) y = 0;
if ((i & 1) == 0) {
v = (0xff & yuv420sp[uvp++]) – 128;
u = (0xff & yuv420sp[uvp++]) – 128;
}

y1192 = 1192 * y;
r = (y1192 + 1634 * v);
g = (y1192 – 833 * v – 400 * u);
b = (y1192 + 2066 * u);

if (r < 0) r = 0; else if (r > 262143) r = 262143;
if (g < 0) g = 0; else if (g > 262143) g = 262143;
if (b < 0) b = 0; else if (b > 262143) b = 262143;

rgbBuf[yp * 3] = (byte)(r >> 10);
rgbBuf[yp * 3 + 1] = (byte)(g >> 10);
rgbBuf[yp * 3 + 2] = (byte)(b >> 10);
}
}
}
摄像头这一块android虽然给了一个接口,但是实现还是各个厂家自己实现的,所以不同的机型处理方式还不一致,

很难做到统一

[转载]Jquery调用Web Service

mikel阅读(833)

[转载]Jquery调用Web Service – 琴韵之弦 – 博客园.

最近在学习JQuery与Web Serivce,于是想想可不可以两者一起使用呢?于是开始摸索,在摸索过程中还是会发现一些问题,大家都知道无论是Web Service还是WCF返回的数据格式是XML,由于XML文件格式文件庞大、格式复杂、传输占用宽带并且服务器端与客户端解析XML花费资源和时间; 而Json的数据格式比较简单、占用宽带小并且相当稳定;所以接下来我们就利用JSON格式。

1. 新建一个Web应用程序的项目,并新建 Web 服务,命名为WebService.asmx

2. 为WebService.asmx写点方法吧,下面做一个简单的方法;

注意:a) 在该Web Service中不能重载,需要确保Web Service能运行

b) 必须有   [System.Web.Script.Services.ScriptService],如果没有它,在前台页面不会调用到该服务。

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Linq;
using System.Text;
using System.Collections.Generic;

namespace jqueryandWCF
{
///
/// WebService 的摘要说明
///
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
// 若要允许使用 ASP.NET AJAX 从脚本中调用此 Web 服务,请取消对下行的注释。
[System.Web.Script.Services.ScriptService]
public class WebService : System.Web.Services.WebService
{
[WebMethod]
public string HelloWorld(string userName)
{
return "Hello " + userName +" !";
}
}
}

3. HTML页面,我们可以点击某一按钮时来调用该服务.

注意:1) ajax中的data:”{}”是用于传递方法中的参数,格式为:data:”{paraName:paraValue}”,如果该方法无参数,则格式为:data:”{}”

2) 如果成功,我是以HTML的形式显示它的值,大家可以用其它方法,取它的值时用(result.d)

&lt;%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="jqueryandWCF._Default" %&gt;


无标题页

<script src="Scripts/jquery-1.4.1.js" type="text/javascript"></script> <script type="text/javascript">// <!&#91;CDATA&#91;
 $(document).ready(function() {
 #region ===这段不用===
 //当启动ajax时显示该图片,相反就隐藏该图片
 /*
 $("#loading").ajaxStart(function() {
 $(this).show();
 })
 $("#loading").ajaxStop(function() {
 $(this).hide();
 })
 */
 #endregion

 $("#Button1").click(function() {
 try {
 $.ajax({
 type: "POST", //访问WebService使用post方式请求
 contentType: "application/json;utf-8", //WebService会返回json类型
 url: "WebService.asmx/HelloWorld", //调用WebService的地址和方法名称组合
 data: "{userName:'Jodie'}", //这里是要传递的参数,格式为data:"{paraName:paraValue}"
 dataType: "json",
 success: function(result) {
 $("#result").html(result.d);
 }
 })
 }
 catch (ex) {
 alert(ex);
 }
 })
 })
// &#93;&#93;></script>

<form id="form1"> <input id="Button1" type="button" value="Invoke1" />
<div id="result"><img id="loading" style="display: none;" src="Images/图1.bmp" alt="loading" /></div>
</form>

4. 做了这么多,当然要验收一下我们结果是怎样的?