Det första intrycket var när Melanie och Devin Duncan klev upp på sen och började prata om Pinterest utifrån ett SEO-perspektiv. Spännande tankar som gav en hel del idéer. Har du ett företag som säljer saker och har bra bilder kan det vara idé att lägga upp ett konto och börja lägga upp och länka bilder. Jag har redan börjat experimentera med det. 🙂
Vi fick också vara med on en lansering. En ny e-handelsplattform lanserades i direktsändning. Det var tictail.com som har gjort plattform som skall vara extrem enkel att komma igång med. Jag har registrerat ett konto men inte hunnit med att testa ännu. Återkommer eventuellt om detta.
Sedan pratade David Rowan som jobbar för Wired Magazin i England. Han pratade om hur långt vi kommit på internet och hur framtiden kommer att se ut. Bland annat pratade han om SoLoMo. Dvs. alla affärer kommer på sikt vara SOcial, LOcal och MObile. Han och några andra talare varnade också för företag som är grossister och bara är en mellanhand kommer få problem inom kort. Det kommer skapas tjänster som helt enkelt kör över dem. Även e-handlare och vanliga butiker som säljer andra leverantörers produkter kommer få problem när vi köper dem direkt via webben hos tillverkaren. Det är ett av skälen till att ICA och de andra livsmedelskedjorna gör fler egna produkter.
En av höjdpunkterna var att se Klarnas nya kassa eller Klarna Checkout som de kallar den. Se filmen läs mer om den här.
Som avslutning kom Gary Vaynerchuk som hade massor av åsikter. Men en av de viktigaste var att ibland är det viktigare att behålla och underhålla sina befintliga kunder än att skaffa nya. Det är också billigare.
Årets Google Analyctis Conference gick av stapeln i Stockholm idag. En heldag som ingår in en eventvecka som går under titeln Digital Days. Google Analytics konferensen har växt enormt sedan förra årets allra första och den hade i år 325 besökare och 100 stod på reservlistan. Vi fick en fullspäckad agenda med två parallella spår, en för marknadsföring och en lite mer ”hard core” teknisk variant.
Efter en kort trendanalys och en snabbsummering av alla föreläsningar så har de en gemensam nämnare; Custom Variabler. Flera talare pratade om vikten att sätta korrekta Custom Variabler för att sedan bygga unika segment på dessa. Detta är förvisso inte på något sätt en nyhet för oss i branschen men det är bra att man visar konkreta case kring dem.
Också de nya fräscha funktionerna som lanserades i slutet på förra året i Google Analytics version 5 som vi sett varit mycket användbara i våra egna kundanalyser fick lite extra fokus under dragningen av Chris Anderson, Google USA, i Measurement Sociala Media. Jag tänker främst på Multi Channel Funnels, dvs flera kanalers samverkan till avslut, men också den helt nya Social rapporten som är bara några veckor gammal.
Vi fick bekräftat åter igen att mobila besökare blir allt viktigare. Sven Törnkvist, Google Sverige, berättade om att genom tekniken som mobil användning tillåter har konsumenternas beteende förändrats. Vilken säljkanal du ska använda bestämmer konsumenten och därför är det viktigt att tänka ”non line”. Med mobilen byggs bryggor mellan on-site och off-site och det gäller för oss att finnas där konsumenterna är.
För övrigt, segmentera dina data samt se till att använda marknadsföringsbudget fördelad på att både att nå nya besökare men också för att ta hand om dem som redan är bekanta med varumärket.
Webbdagarna. Smaka på ordet. Webbdagarna. Två dagar om webb tänker ni som inte var där. Slutsummeringen är att det faktiskt handlade mycket om att göra bra saker. Dvs. alla företag och personer skall göra bra saker. Joakim Jardenberg sammanfattade det med ”Do good shit”. Men det genomgående temat var att göra bra saker samt att göra det transparent. Att våga göra bra saker via sociala medier. Det fanns mängder med exempel på hur olika företag och organisationer använder sociala medier till att göra bra saker och att vara transparenta. Bland annat Ving och Viasat visade på detta.
Men om vi betänker det faktum att LinkedIn har ca 980 000 användare i Sverige, Facebook har 4 638 500 och Twitter ca 250 000 så är det idag i Sverige fler som inte har ett konto för sociala medier än de som inte har det. Det finns 260 260 personer som har Facebook som är över 64 år. 932 680 är mellan 13-19 år. Facebook har alltså en bra spridning på användarna. Men börjar vi fundera på hur många som faktiskt använder Facebook, dvs. loggar in och delar med sig, kommenterar mm, blir bilden lite annorlunda. Jag har en ganska strikt syn på vilka som blir mina vänner på Facebook, vilket gör att jag har 343 vänner. Av dessa uppskattar jag att ca 150 är någorlunda aktiva, ca 100 stycken är där ibland och 100 använder inte sitt konto. Om det är ca 30% som inte använder sitt Facebookkonto innerbär det att av de 4 438 500 konton som finns i Sverige är det bara 3,1 miljoner konton som är aktiva. Tar vi bort ytterligare 5% som troligen är test och fejkkonton är vi nera i ca 2,9 miljoner konton. Det är alltså ca 6 miljoner svenskar som inte går att nå via Facebook. Alltså måste alla företag vara bra och göra ”Good shit” på sin webbplats och intranät också om vi skall hålla oss inom den digitala världen. Självklart skall alla organisationer och företag vara bra i grunden. Men om vi skärmar oss till webben, det heter faktiskt webbdagarna.
När det nu är influenser från Jocke Jardenberg och Johan Ronnestam som ringer kvar i öronen (Se hans föreläsning här). Det är nu upp till alla oss som besökte Webbdagarna att samla alla bra tankar och intryck och överföra dem till de digitala kanaler vi jobbar med på det egna företaget och åt kunder i de fallen vi jobbar som konsulter. Vi har också ett kollektivt ansvar att sprida kunskapen uppåt och visa ledningsgruppen att det finns ett värde i att göra bra saker. Det kommer troligen inte att vara en ny värld nästa vecka men om vi tillsammans blir en smart svärm som Adam Hassan pratade om i sitt framträdande och kollektivt föra fram vårt budskap.
Till sist vill jag bara passa på att säga en lite sak om vem som var snällast på Webbdagarna. Jo, det var Therese Reuterswärd!
Det är viktigt att hantera sitt varumärke strategiskt. Det är alla som har ett varumärke eniga om. Men alla tänker inte hela vägen. Jag läste innan jul boken om Steve Jobs. Hans nästan sjukliga drivkraft att lägga sig i de minsta saker i Apples butiker bara för att det speglar varumärket. Allt ifrån känslan av hur det är att köpa en produkt från Apple, till hur det är att packa upp produkten och sedan använda produkten. Allt ska andas premium.
Apple Store 5th Ave, NYC
Men det börjar ännu tidigare, innan den fysiska affären. Funderar du på att köpa en ny MacBook Pro? Då gör du säkerligen en del research på apple.se även om du gör det slutgiltiga köpet i den fysiska butiken. Då är det självklart viktigt att känslan av varumärket börjar förmedlas redan här. Som kund ska jag få samma känsla på webben som jag får i den fysiska butiken och det som produkten representerar. Apple är en föregångare, verkligheten får många företagare ser annorlunda ut. Vi har mycket att lära av Apple! Hur hänger upplevelsen för en kund ihop från webb, till att en säljare kommer på besök, eller att kunden kommer till en butik eller ett kontor till hur tjänsten och produkten blir vid ett köp? Det finns fortfarande de som tror att webbplatsen inte är viktigt. ”Nä, vi gör inte affärer via webben, vi gör affärer via människor”. Men – hänger inte allt ihop? Är inte alla delar olika beståndsdelar som tillsammans skapar ditt varumärke?
Vad säger din webb om ditt varumärke?
Ibland misstänker jag att vissa företag inte ens reflekterar över att deras webb besöks av en potentiell kund innan deras säljare dyker upp. I det läget bestäms mycket av vad som sedan händer. Om webbplatsen inte svarat upp mot den förväntade kvalitén mot en förväntad produkt kommer säljaren ha svårt att vända affären till en framgång. Det är därför all kommunikation hänger ihop. Allt från webben via broschyrer, kataloger, mässmontrar, besök av säljare till hur en butik eller ett kontor ser ut. Allt måste hänga ihop med den position som du vill ha på ditt varumärke. Det är därför en Apple Store ser väldigt annorlunda ut mot Överskottsbolaget. Våra förväntningar är på olika nivåer och skulle ÖB se ut so Apple Store på 5th Avenue i New York skulle inte det vara rätt heller. Allt måste hänga ihop, fast på rätt nivå, och det gäller även webbplatsen.
I var och vart annat projekt man sitter i (i alla fall när det gäller e-handel eller integration) så skall det skalas bilder. De skall ha bestämda storlekar, bestämda bredder, de ska beskäras och ramas in.
GDI+ ligger under System.Drawing vilket har en liten drawback, ända upp till senaste versionen av .NET (4.5) så skriver Micosoft så här på MSDN: Classes within the System.Drawing namespace are not supported for use within a Windows or ASP.NET service. Attempting to use these classes from within one of these application types may produce unexpected problems, such as diminished service performance and run-time exceptions. For a supported alternative, see Windows Imaging Components.
GDI+ ligger säkerligen på många av våra webbar och i många av våra Windows-tjänster och fungerar riktigt bra, men varför chansa i fortsättningen? Dessutom kan jag tycka att resultatet av det som GDUI+ genererar inte alltid är tillfredsställande ur en kvalité. Men det finns en lösning!
Windows Imaging Components
Det finns två sätt att arbeta med Windows Imaging Components (vidare kallat WIC). Det ena är via Windows Presentation Foundation (vidare kallat WPF) och det andra är via COM. Det senare alternativet kan vara användbart där vi har problem med trust eller vi inte vill programmera i något av de språk som tillhandahålls inom ramen för .NET. Men för den här gången kommer vi fokusera på C#.
Tanken jag har med detta lilla blogginlägg är att ge er alla lite hjälp på vägen, lite kod ni kan kopiera och utgå i från i era egna projekt. Så slipper ni skriva allt från början, vilket gör en övergång ganska mycket smidigare.
Jag har fokuserat på tre olika typer av bildomskalingar.
En omskalning där vi håller en av sidorna konstant och låter den andra skala efter behov. Det här är det klassiska sättet att skala om bilder.
Där vi använder en fixerad storlek (både höjd och bredd) på resultatet och lägger in vår omskalde bild i denna, så att den får plats.
Samt en tredje variant där vi, likt vår förra variant, använder en fixerad storlek på bilden men den här gången så skalar vi ner bilden så att en av sidorna exakt matchar en av resultatet sidor och sedan beskär vi bort överflödet av bilden.
Klassisk omskalning
Den klassisk omskalningen är bara ”vänligt” implemneterad, med det menar jag att den alltid kommer att skala om en bild proportionellt. Den väljer alltid den skalning som blir minst om man anger båda parametrarna, annars kan man skicka in 0 (noll) på en av dem för att vara övertygad om att skalning sker med den aktuella parametern i avseende.
private BitmapFrame ResizeImage(BitmapSource input, int width, int height) {
double newHeightRatio = (height / (double)input.PixelHeight);
double newWidthRatio = (width / (double)input.PixelWidth);
if (newHeightRatio <= 0 && newWidthRatio > 0)
newHeightRatio = newWidthRatio;
else if (newWidthRatio <= 0 && newHeightRatio > 0)
newWidthRatio = newHeightRatio;
var scale = Math.Min(newWidthRatio, newHeightRatio);
if (scale > 1)
scale = 1;
var target = new TransformedBitmap(input, new ScaleTransform(scale, scale));
return BitmapFrame.Create(target);
}
WPF innehåller en så kallad BitmapSource som transformerar vår bild, denna tar emot en transformationstyp och .NET tillhandahåller några standardiserade. Dessa är
MatrixTransform
RotateTransform
ScaleTransform
SkewTransform
TranslateTransform
Just nu kommer jag enbart att fokusera på ScaleTransform eftersom det är den som är mest intressant för mig, men här kan vi lätt modifiera koden ovan för att exempelvis rotera eller skeva en bild istället.
Det här sättet att skala bilder med WPF är det snabbaste och ger en helt godkänd bildkvalité. Vi har inte heller någon möjlighet att direkt påverka bilddjupet, resultatbilden kommer i detta fall att ha samma upplösning (DPI) som orginalet.
Det här är ressultatet av en sådan här omskalning. Jag har talat om att bilden skall vara 200 px hög.
Det inte den här metoden ger möjlighet till är att välja vilken algoritm som skall användas för omskalningen. För att kunna ange detta måste vi använda ett annat sätt när vi skalar om bilderna, och förlorar då effektivitet. Det här är en avvägning man får göra i fall till fall, dock tycker jag att den algoritm som används av exemplet ovan ger en bra bildkvalité till en bra hastighet.
public BitmapFrame Resize(BitmapFrame input, int width, int height, BitmapScalingMode salingMode, int dpi) {
var group = new DrawingGroup();
RenderOptions.SetBitmapScalingMode(group, scalingMode);
group.Children.Add(new ImageDrawing(photo, new Rect(0, 0, width, height)));
var targetVisual = new DrawingVisual();
var targetContext = targetVisual.RenderOpen();
targetContext.DrawDrawing(group);
var target = new RenderTargetBitmap(width, height, dpi, dpi, PixelFormats.Default);
targetContext.Close();
target.Render(targetVisual);
var targetFrame = BitmapFrame.Create(target);
return targetFrame;
}
I exemplet ovan kan man se hur vi kan välja både skalningsmetod och djup i bilden som vi producerar. Vi använder en helt annan metodik för att skala bilderna vilken tar mer kraft från systemet.
Skala en bild och placera den i en ram
Om man alltid vill ha en fast storlek på bilderna, tillexempel till en produklista där det skulle se otroligt dumt ut om bilderna var i olika bredder eller höjder, kan man välja att lägga dem i en ”omgivande ram”. Lösningen är vanlig och gör det mycket enklare att designa webbplatser.
public BitmapFrame ResizeAndFit(BitmapSource input, int width, int height) {
if (input.PixelWidth == width && input.PixelHeight == height)
return BitmapFrame.Create(input);
if (input.Format != PixelFormats.Bgra32 || input.Format != PixelFormats.Pbgra32)
input = new FormatConvertedBitmap(input, PixelFormats.Bgra32, null, 0);
var scale = Math.Min((double)width / input.PixelWidth, height / (double)input.PixelHeight);
if (scale > 1)
scale = 1;
var x = (int)Math.Round((width - (input.PixelWidth * scale)) / 2);
var y = (int)Math.Round((height - (input.PixelHeight * scale)) / 2);
var scaled = new TransformedBitmap(input, new ScaleTransform(scale, scale));
var stride = scaled.PixelWidth * (scaled.Format.BitsPerPixel / 8);
var result = new WriteableBitmap(width, height, scaled.DpiX, scaled.DpiY, scaled.Format, null);
var colorFrame = GetColorBitmap(width, height, Brushes.White);
var colorFrameStride = colorFrame.PixelWidth * (colorFrame.Format.BitsPerPixel / 8);
var colorFrameData = new byte[colorFrame.PixelHeight * colorFrameStride];
var data = new byte[scaled.PixelHeight * stride];
colorFrame.CopyPixels(colorFrameData, colorFrameStride, 0);
scaled.CopyPixels(data, stride, 0);
result.WritePixels(new Int32Rect(0, 0, width, height), colorFrameData, colorFrameStride, 0, 0);
result.WritePixels(new Int32Rect(0, 0, scaled.PixelWidth, scaled.PixelHeight), data, stride, x, y);
return BitmapFrame.Create(result);
}
private BitmapSource GetColorBitmap(int width, int height, Brush color) {
var renderBitmap = new RenderTargetBitmap(size.Width, size.Height, 96, 96, PixelFormats.Pbgra32);
var drawingVisual = new DrawingVisual();
using (var context = drawingVisual.RenderOpen()) {
context.DrawRectangle(color, null, new Rect(0, 0, size.Width, size.Height));
}
renderBitmap.Render(drawingVisual);
return renderBitmap;
}
Den här typen av omskalning blir lite mer avancerad. Här måste vi nämligen rita ut vår omskalde bild i en ytterligare bild. Först så ser vi till att båda våra bildformat är på samma format, om vår inkommande bild inte är 32bitars RGB (Bgra32) så omvandlar vi källan till detta, exempel på andra format kan vara 16bitars RGB eller CMYK.
Efter detta skalar vi ner bilden så att den får plats i vår ram. Det vi gör är att vi räknar ut proportionell skalning i både X- och Y-led för att sedan välja den som är minst. Det kommer vara den skalfaktor vi använder för att se till att bilden får plats i vår destinationsstorlek.
Som standard är vår nya skrivbara bitmap transparent, detta fungerar mycket bra för PNG och kanske till och med är önskvärt. Det vi i så fall gör är att vi raderar våran colorFrame från koden ovan och låter inte denna skrivas till bilden. När vi skalar foton är det i de flesta fall önskvärt att spara bilderna som JPEG eftersom det tar minst plats. JPEG stödjer inte transparens och därför måste vi måla vår bakgrund i en önskad färg.
Vi kopierar sedan över vår bakgrund och därefter vår bild till vår destination och returnerar denna. Omskalningen är klar!
Det här är resultatet. Jag har talat om att jag vill ha en bild som är 500 px bred och 200 px hög, och med blå bakgrund.
Skala en bild och beskär det som inte får plats
Om du vill ha en fast bildstorlek men inte vill ha en ”ful” färgad ram kring din bild så kan det vara nog så bra att beskära bort en del av bilden. Om dina orginalbilder ligger väldigt nära dina omskalade bilder i proportioner så är detta ett utmärkt alternativ, på bilderna som jag använder blir resultatet dessvärre mycket sämre. s
public BitmapFrame ResizeAndCrop(BitmapSource input, int width, int height) {
if (input.PixelWidth == width && input.PixelHeight == height)
return BitmapFrame.Create(input);
var useScaleH = (width / (double)input.PixelWidth) * input.PixelHeight;
var newSizeH = 0;
var newSizeW = width;
if (useScaleH < height) {
var newSizeH = height;
var newSizeW = 0;
}
var scaled = ResizeImage(input, newSizeW, newSizeH);
var x = ((scaled.PixelWidth - width) / 2);
var y = ((scaled.PixelHeight -height) / 2);
var stride = scaled.PixelWidth * (scaled.Format.BitsPerPixel / 8);
var result = new WriteableBitmap(width, height, scaled.DpiX, scaled.DpiY, scaled.Format, null);
var data = new byte[scaled.PixelHeight * stride];
var copyWidth = scaled.PixelWidth - (scaled.PixelWidth - width);
var copyHeight = scaled.PixelHeight - (scaled.PixelHeight - height);
if (x < 0) {
x = 0;
copyWidth = scaled.PixelWidth;
}
if (y < 0) {
y = 0;
copyHeight=scaled.PixelHeight
}
scaled.CopyPixels(data, stride, 0);
result.WritePixels(new Int32Rect(x, y, copyWidth, copyHeight), data, stride, 0, 0);
return BitmapFrame.Create(result);
}
Det här ser mer avancerat ut än vad det är. Vi måste först räkna ut vilken sida som, när vi skalat ner bilden, kommer att vara lika stor som den nya bilden medan den andra sidan är större. När vi gjort det kan vi skala ner bilden proportionellt.
Vi skapar därefter en destinationsbild som är exakt så stor som vi vill ha den. Eftersom vår nedskalade bild är större än denna måste vi räkna ut en ram som skall användas för att beskära bilden. Det gör vi genom att räkna ut hur mycket som ”hänger över” i bredd- och höjdled. Vi centrerar bilden genom att dela dessa värden i hälften och koperar nu över de pixlar som ligger inom ramen till vår destinationsbild.
Viktigt att notera här är att om orginalbilden är mindre än destinationsbilden så kommer vi bara kopiera över bilden till det övre vänstra hörnet. Det är för att vi inte vill sträcka ut bilden och förstöra den. Det bästa är inte använda denna metod vid sådana bilder, utan i stället lösa det problemet på annat sätt, exempelvis genom att lägga en ram kring den.
Det här är resultatet. Jag har talat om att bilden skall vara 500 px bred och 200 px hög. Min orginalbild är stående och denna liggande, därför förlorar vi mycket av bilden. Två bildformat som ligger nära varandra i proportioner resulterar
Avkoda och koda bilder från disk/ström.
För att allt det här ska fungera behöver du också några småsaker, exempelvis en bild-decoder och en bild encoder. Självklart finn detta inbyggt och är inte direkt rocket-sience. Här kommer lite exempel:
Stream orginalImage = null; //Load stream from image-file or like.
var orginalImageDecoder = BitmapDecoder.Create(
orginalImage,
BitmapCreateOptions.PreservePixelFormat,
BitmapCacheOption.None);
När du skall spara dina omskalade bilder kan du göra det i sex format som Microsoft tillhandahåller. Dessa är
BmpBitmapEncoder
GifBitmapEncoder
JpegBitmapEncoder
PngBitmapEncoder
TiffBitmapEncoder
WmpBitmapEncoder
alla dessa format används på samma sätt som nedan. JpegBitmapEncoder har dessutom möjlighet att sätta kvalité för kompressionen.
Stream resizedImage = null; //Init a writable stream for the destination
BitmapFrame resizedImageFrame = null; //Frame from one of the resize algorithms above.
var targetEncoder = new JpegBitmapEncoder(){
QualityLevel = 85;
};
targetEncoder.Frames.Add(resizedImageFrame);
targetEncoder.Save(resizedImage);
Jag hoppas att det här har väckt dina tankar lite kring att kanske använda WPF för att göra din bildmanipulering i framtiden.
Hey. Very cool blog!! Man .. Excellent .. Amazing .. I’ll bookmark your website and take the feeds additionally…I’m happy to locate a lot of useful information right here within the post. Thanks for sharing..
Året var 2003. Birger Lundgrens svenska IT-företag StreamServe hade växt från ingenting till ett företag som omsatte 400 miljoner kronor. Genom att sälja sin andel i företaget kunde han nu bosätta sig i landet han förälskat sig i under en semesterresa. ”Sydafrika, det bästa stället i världen”.
När han inte jobbar med EPiServer spenderar Birger mycket tid med sin två-åriga son. Eller så tar han strandpromenader, reser och provar sydafrikanska viner åt sin svenska agent. På bilden (Birger Lundgren till vä) ovan är det management-möte för EPiServer som står på agendan. Cape Town style.
I dag bor Birger halva året i Kapstaden och halva året i Stockholm och jobbar bland annat med att ansvara för EPiServers verksamhet i Sydafrika. Den lilla verksamheten består förutom Birger själv, av två engelsmän som arbetar som konsulter och EPiServer-utvecklare. Själv fokuserar han mest på försäljning och marknadsföring.
Jag träffar Birger på ett café i Kapstadens innerstad. Vi pratar om omognaden inom webb- och internetbranschen i Sydafrika jämfört med Sverige. ”För fyra år sedan när vi bestämde oss för att etablera en liten verksamhet här nere så satsade vi en del på marknadsföring. Vi hade frukostseminarier och runda bords-samtal och vi annonserade. Intresset var jättestort men beställningarna dröjde”. På en outvecklad marknad är det svårare att sälja en produkt som ligger i framkant men nu har kunderna börjat komma. I Sydafrika såväl som runt om i Afrika. ”Botswanas regering till exempel, de kör EPiServer”, berättar Birger.
Den sydafrikanska marknaden är stor och har en oerhörd potential men på grund av dåligt utbyggt bredband, ofta med små nedladdningskvoter, har det stora genomslaget väntat på sig. ”Internetutvecklingen i Sydafrika rör sig at the speed of a glacier”, skrattar Birger. Och marknaden följer. Birger beskriver ett exempel från Telkoms webbplats, Sydafrikas största internetleverantör. ”Om man surfar in på deras sida för internetsupport står där tydligt ett telefonnummer man ska ringa. Men om man ringer det numret får man meddelandet this number is no longer in use, please dial… Och då var det ändå ett halvår sedan de ändrade numret”.
Men boomen kommer att komma, det är Birger säker på. Man väntar nu på lansering av två nya linor som kommer göra stor skillnad för tillgänglighet och snabbhet för sydafrikanska bredband så framtiden ser ljus ut. Så sent som förra året öppnade Google ett kontor i Kapstaden, en indikation på framtidstro från jätten. ”Dessutom ligger man till och mer före Europa vad gäller mobila lösningar”, berättar Birger. I ett land som saknar prisvärt internet har den mobila marknaden tagit stora kliv framåt. Ett väl utbyggt 3G-nät har medfört en satsning på mobila lösningar eftersom mobiltelefonen är mer tillgänglig än datorer för majoriteten av befolkningen. Och vad säger att framtiden har kommit mer än mobilt.
Får man skriva ”puss”? Jag gör det.