Monday, August 8, 2011

package com.softpower.utils;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.PixelGrabber;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.Locale;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.ImageOutputStream;


public class ImageUtils {
public static final int IMAGE_UNKNOWN = -1;
public static final int IMAGE_JPEG = 0;
public static final int IMAGE_PNG = 1;
public static final int IMAGE_GIF = 2;

/**
* Resizes an image
*
* @param imgName
* The image name to resize. Must be the complet path to the file
* @param type
* int
* @param maxWidth
* The image's max width
* @param maxHeight
* The image's max height
* @return A resized BufferedImage
*/
public static BufferedImage resizeImage(String imgName, int type, int maxWidth, int maxHeight) {
try {
return resizeImage(ImageIO.read(new File(imgName)), type, maxWidth, maxHeight);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}

/**
* Resizes an image.
*
* @param image
* The image to resize
* @param maxWidth
* The image's max width
* @param maxHeight
* The image's max height
* @return A resized BufferedImage
* @param type
* int
*/
public static BufferedImage resizeImage(BufferedImage image, int type, int maxWidth, int maxHeight) {
Dimension largestDimension = new Dimension(maxWidth, maxHeight);

// Original size
int imageWidth = image.getWidth(null);
int imageHeight = image.getHeight(null);

float aspectRatio = (float) imageWidth / imageHeight;

if (imageWidth > maxWidth || imageHeight > maxHeight) {
if ((float) largestDimension.width / largestDimension.height > aspectRatio) {
largestDimension.width = (int) Math.ceil(largestDimension.height * aspectRatio);
} else {
largestDimension.height = (int) Math.ceil(largestDimension.width / aspectRatio);
}

imageWidth = largestDimension.width;
imageHeight = largestDimension.height;
}

return createHeadlessSmoothBufferedImage(image, type, imageWidth, imageHeight);
}

/**
* Saves an image to the disk.
*
* @param image
* The image to save
* @param toFileName
* The filename to use
* @param type
* The image type. Use ImageUtils.IMAGE_JPEG to save as
* JPEG images, or ImageUtils.IMAGE_PNG to save as PNG.
* @return false if no appropriate writer is found
*/
public static boolean saveImage(BufferedImage image, String toFileName, int type) {
try {
return ImageIO.write(image, type == IMAGE_JPEG ? "jpg" : "png", new File(toFileName));
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
/**
* Saves an image to the disk.
*
* @param image
* The image to save
* @param toFileName
* The filename to use
* @param type
* The image type. Use ImageUtils.IMAGE_JPEG to save as
* JPEG images, or ImageUtils.IMAGE_PNG to save as PNG.
* @return false if no appropriate writer is found
*/
public static boolean saveImage(BufferedImage image, File toFileName, int type) {
try {
return ImageIO.write(image, type == IMAGE_JPEG ? "jpg" : "png", (toFileName));
} catch (IOException e) {
e.printStackTrace();
return false;
}
}

/**
* Compress and save an image to the disk. Currently this method only supports
* JPEG images.
*
* @param image
* The image to save
* @param toFileName
* The filename to use
* @param type
* The image type. Use ImageUtils.IMAGE_JPEG to save as
* JPEG images, or ImageUtils.IMAGE_PNG to save as PNG.
*/
public static void saveCompressedImage(BufferedImage image, String toFileName, int type) {
try {
if (type == IMAGE_PNG) {
throw new UnsupportedOperationException("PNG compression not implemented");
}

Iterator iter = ImageIO.getImageWritersByFormatName("jpg");
ImageWriter writer;
writer = (ImageWriter) iter.next();

ImageOutputStream ios = ImageIO.createImageOutputStream(new File(toFileName));
writer.setOutput(ios);

ImageWriteParam iwparam = new JPEGImageWriteParam(Locale.getDefault());

iwparam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
iwparam.setCompressionQuality(0.7F);

writer.write(null, new IIOImage(image, null, null), iwparam);

ios.flush();
writer.dispose();
ios.close();
} catch (IOException e) {
e.printStackTrace();
}
}

/**
* Creates a BufferedImage from an Image. This
* method can function on a completely headless system. This especially
* includes Linux and Unix systems that do not have the X11 libraries
* installed, which are required for the AWT subsystem to operate. This method
* uses nearest neighbor approximation, so it's quite fast. Unfortunately, the
* result is nowhere near as nice looking as the
* createHeadlessSmoothBufferedImage method.
*
* @param image
* The image to convert
* @param w
* The desired image width
* @param h
* The desired image height
* @return The converted image
* @param type
* int
*/
public static BufferedImage createHeadlessBufferedImage(BufferedImage image, int type, int width,
int height) {
if (type == ImageUtils.IMAGE_PNG && hasAlpha(image)) {
type = BufferedImage.TYPE_INT_ARGB;
} else {
type = BufferedImage.TYPE_INT_RGB;
}

BufferedImage bi = new BufferedImage(width, height, type);

for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
bi.setRGB(x, y, image.getRGB(x * image.getWidth() / width, y * image.getHeight() / height));
}
}

return bi;
}

/**
* Creates a BufferedImage from an Image. This
* method can function on a completely headless system. This especially
* includes Linux and Unix systems that do not have the X11 libraries
* installed, which are required for the AWT subsystem to operate. The
* resulting image will be smoothly scaled using bilinear filtering.
*
* @param source
* The image to convert
* @param w
* The desired image width
* @param h
* The desired image height
* @return The converted image
* @param type
* int
*/
public static BufferedImage createHeadlessSmoothBufferedImage(BufferedImage source, int type,
int width, int height) {
if (type == ImageUtils.IMAGE_PNG && hasAlpha(source)) {
type = BufferedImage.TYPE_INT_ARGB;
} else {
type = BufferedImage.TYPE_INT_RGB;
}

BufferedImage dest = new BufferedImage(width, height, type);

int sourcex;
int sourcey;

double scalex = (double) width / source.getWidth();
double scaley = (double) height / source.getHeight();

int x1;
int y1;

double xdiff;
double ydiff;

int rgb;
int rgb1;
int rgb2;

for (int y = 0; y < height; y++) {
sourcey = y * source.getHeight() / dest.getHeight();
ydiff = scale(y, scaley) - sourcey;

for (int x = 0; x < width; x++) {
sourcex = x * source.getWidth() / dest.getWidth();
xdiff = scale(x, scalex) - sourcex;

x1 = Math.min(source.getWidth() - 1, sourcex + 1);
y1 = Math.min(source.getHeight() - 1, sourcey + 1);

rgb1 = getRGBInterpolation(source.getRGB(sourcex, sourcey), source.getRGB(x1, sourcey),
xdiff);
rgb2 = getRGBInterpolation(source.getRGB(sourcex, y1), source.getRGB(x1, y1), xdiff);

rgb = getRGBInterpolation(rgb1, rgb2, ydiff);

dest.setRGB(x, y, rgb);
}
}

return dest;
}

private static double scale(int point, double scale) {
return point / scale;
}

private static int getRGBInterpolation(int value1, int value2, double distance) {
int alpha1 = (value1 & 0xFF000000) >>> 24;
int red1 = (value1 & 0x00FF0000) >> 16;
int green1 = (value1 & 0x0000FF00) >> 8;
int blue1 = (value1 & 0x000000FF);

int alpha2 = (value2 & 0xFF000000) >>> 24;
int red2 = (value2 & 0x00FF0000) >> 16;
int green2 = (value2 & 0x0000FF00) >> 8;
int blue2 = (value2 & 0x000000FF);

int rgb = ((int) (alpha1 * (1.0 - distance) + alpha2 * distance) << 24)
| ((int) (red1 * (1.0 - distance) + red2 * distance) << 16)
| ((int) (green1 * (1.0 - distance) + green2 * distance) << 8)
| (int) (blue1 * (1.0 - distance) + blue2 * distance);

return rgb;
}

/**
* Determines if the image has transparent pixels.
*
* @param image
* The image to check for transparent pixel.s
* @return true of false, according to the result
*/
public static boolean hasAlpha(Image image) {
try {
PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false);
pg.grabPixels();

return pg.getColorModel().hasAlpha();
} catch (InterruptedException e) {
return false;
}
}
}

Friday, May 20, 2011

HTML5 Mobile Web 系列:小圖示請使用 Data URI

引用網址 :http://blog.ericsk.org/archives/1436/trackback


使用 Data URI 可以節省 request 的數量。


首先以一個直接的例子來說明什麼是 Data URI,假設我有一張 PNG 圖片,像是這樣:


在網頁上嵌入的語法很簡單,就是 <img src="圖片路徑" width="寬" height="高">,但是這樣一來瀏覽器便需要多送出一個 reuqest 取得這張圖片,如果一個頁面上的圖片很多,對於網頁存取的速度就會有很深的影響(尤其是手機上的瀏覽器),除了可以使用 CSS Sprites 的技巧減少圖片存取數量,也可以使用 Data URI 將圖片編碼成字串後,直接嵌入在 HTML 或 CSS 檔案內容裡,作法如下:



  1. 首先將圖片以 base64 編碼成字串,以上圖為例,編碼後的字串為:

    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
    AAAASUVORK5CYII=

  2. 嵌入圖片時,語法修改為<img src="data:image/png;base64,你的base64字串" width="" height="">,要注意 bas64 字串不能有斷行,必須要接起來,效果如下圖所示:(IE 使用者若看不到,請升級至 IE9 以上,並確定沒有按到相容模式


  3. 如果是用在 CSS 檔案裡,原本若寫成 background-image: url(/path/to/image.png),則可以修改成 background-image: url(data:image/png;base64,圖片的base64字串)

  4. 當然這個方法也可以用在 gif, jpg 等 web 上可以使用的檔案,記得將 image/png 這個 MIME-type 改成對應的


不過 Data URI 不一定在每個圖片的顯示都適用,而且太過度地使用也可能會造成 HTML 檔案或是 CSS 檔案的肥大(如果 html, css 檔案也有作快取那就還好),總之就看網站設計者如何巧妙地運用 Data URI 的方式來呈現資料,以減輕 browser 發送網路存取的負擔囉。


註: Base64 編碼器可以在網路上搜尋 base64 encoder 就有很多資源了


番外篇


如果使用了 Data URI,那還可以將圖片 cache 在用戶端的 localStorage 裡面,像是這樣:


<img src="" id="the-img">
<script src="jquery.min.js"></script>
<!-- See: http://www.webtoolkit.info/javascript-base64.html -->
<script src="base64.js"></script>
<script>
if (!localStorage.theImg) {
  $.get('/path/to/img.png', function(data) {
    var img = Base64.encode(data);
    localStorage.theImg = 'data:image/png;base64,' + img;
    $('#the-img').attr('src', localStorage.theImg);
  });
} else {
  $('#the-img').attr('src', localStorage.theImg);
}
</script>


 

歷史上的今天

Wednesday, March 16, 2011

Date Only and Time Only data types in SQL Server 2005 (without the CLR)

來源:http://weblogs.sqlteam.com/jeffs/archive/2007/10/31/sql-server-2005-date-time-only-data-types.aspx

In this post, I showed a simple way to create simple but useful Date and Time user-defined data types in SQL Server 2000. Here's how to do it in SQL Server 2005, without the need for CLR types or anything fancy.

First, we must create two user defined data types:

create type Date from dateTime
create type Time from dateTime

So, internally (and externally to our clients), these types are really just DateTime. But, we will apply some rules to these types so that the Date data type will always be constrained to a time exactly at midnight, and the the Time data type will always be at the "base date", or 1900-01-01:

create rule DateOnlyRule as
dateAdd(dd,datediff(dd,0,@DateTime),0) = @DateTime

go

create rule TimeOnlyRule as
datediff(dd,0,@DateTime) = 0

go

Finally, we call sp_bindrule to bind the rules to the data types:

EXEC sp_bindrule 'DateOnlyRule', 'Date'
EXEC sp_bindrule 'TimeOnlyRule', 'Time'

That's it! Now, we can create a table that uses our brand-new data types:

create table Trans
(
TranID int identity primary key,
TranAmount money not null,
TranDate Date not null,
TranTime Time not null
)

Notice that TranDate and TranTime are two separate columns here. If we try to insert data, our rules will ensure that our TranDate and TranTime columns only contain the appropriate data, and by doing so we can simply calculate TranDate + TranTime to get the transactions DateTime.

The following inserts will succeed:

insert into Trans (TranAmount, TranDate, TranTime)
values (200, '2005-01-01', '09:00:00 AM')

insert into Trans (TranAmount, TranDate, TranTime)
values (400, '2005-01-03', '7:50:30 PM')

But this will fail, since our rules are violated (getdate() returns the current date and the time):

insert into Trans (TranAmount, TranDate, TranTime)
values (200, getdate(), getdate())

Msg 513, Level 16, State 0, Line 1
A column insert or update conflicts with a rule imposed by a previous CREATE RULE statement. The statement was terminated. The conflict occurred in database 'PlayGround', table 'dbo.Trans', column 'TranDate'.
The statement has been terminated.

Finally, we can select from our table and simply add the two columns together to get each transaction's DateTime:

select *, TranDate + TranTime as TranDateTime
from Trans

TranID TranAmount TranDate TranTime TranDateTime
------- ----------- ------------------- ------------------- -------------------
1 200.00 2005-01-01 00:00:00 1900-01-01 09:00:00 2005-01-01 09:00:00
2 400.00 2005-01-03 00:00:00 1900-01-01 19:50:30 2005-01-03 19:50:30

(2 row(s) affected)

The nice advantage of doing this is that you can quickly and efficiently select all transactions for a single day like this:

select * from Trans
where TranDate = '2005-01-01'

If we stored the Date and Time in the same column, we'd need to use a less efficient range:

select * from Trans
where TranDate >= '2005-01-01' and TranDate < '2005-01-02'

SQL 2008 does finally implement true Date and Time data types, but until then, I hope this gives you some ideas to play with.

Notes:

* If you do wish to break apart DateTime data into two columns, another option is to simply use a single, standard DateTime column but then define two extra computed columns in your table, one that returns just the Date, another that returns just the Time. Then, you can index those computed columns and reference them easily and efficiently. If you truly wish to store just a date or just a time, however, these user defined data types are a great way to do it. At the end of this SQLTeam article there's a good example demonstrating this.

* You could also just use the expressions for the rules in CHECK constrains on individual table columns, instead of creating the user defined data types and rules. As Books On Line states, CREATE RULE will at some point be removed from future versions of SQL Server, so you may wish to avoid using it.

see also:

* Working with Time Spans and Durations in SQL Server
* Group by Month (and other time periods)
* Working with Date and/or Time values in SQL Server: Don't Format, Don't Convert -- just use DATETIME
* Data Types -- The Easiest Part of Database Design
* How to format a Date or DateTime in SQL Server
* Breaking apart the DateTime datatype -- Separating Dates from Times in your Tables
* Date Only and Time Only data types in SQL Server 2005 (without the CLR)

Thursday, February 17, 2011

轉貼:Milestone 刷非官方真正的 Android 2.2 及問題討論 (補上超頻教學)

文章來源 :http://lbear.pixnet.net/blog/post/19726924




  話說,原本讓使用者相信,會是在 Google N1 升級 2.2 後,就開放升級的 Milestone,竟然讓所有人跌破眼鏡,到了現在都還沒釋出官方的 2.2 ( HTC Desire 都正式升級 2.2 了,三星那隻悲哀的哀 9000,也即將釋出 2.2 官方版了 ) 真是讓 Milestone 的使用者淦到沒力加無言以對,

Wednesday, January 12, 2011

javascript數字Format處理

var num = 10;
var result = num.toFixed(2); // result will equal 10.00

num = 930.9805;
result = num.toFixed(3); // result will equal 930.981

num = 500.2349;
result = num.toPrecision(4); // result will equal 500.2

num = 5000.2349;
result = num.toPrecision(4); // result will equal 5000

num = 555.55;
result = num.toPrecision(2); // result will equal 5.6e+2



function addCommas(nStr)
{
nStr += '';
x = nStr.split('.');
x1 = x[0];
x2 = x.length > 1 ? '.' + x[1] : '';
var rgx = /(\d+)(\d{3})/;
while (rgx.test(x1)) {
x1 = x1.replace(rgx, '$1' + ',' + '$2');
}
return x1 + x2;
}